Chris Pollett > Old Classes > PIC197 ( Print View ) Enrollment info Course Info:
Homework Assignments: Practice Exams: PIC: |
HW2 Solutions Page//Only modified files from demo03 from book displayed. //defines.h: essential defines for Invader game //Copyright Ian Parberry, 1999 //Last updated April 3, 2000 //modified for invader porblem by Chris Pollett 2001 #ifndef __DEFINES_H__ #define __DEFINES_H__ #define SCREEN_WIDTH 640 //pixels wide #define SCREEN_HEIGHT 480 //pixels high #define COLORS 256 //number of colors #define COLOR_DEPTH 8 //number of bits to store colors #define TRANSPARENT_COLOR 255 //transparent palette position // //mod's for invaders // #define BUNKER_NUM 3 // number of bunkers #define BUNKER_OFFSET SCREEN_WIDTH/(BUNKER_NUM+1) // space b/w bunkers #define MIN_LEFTPOS SCREEN_WIDTH/(2*BUNKER_NUM) // farthest invaders/player can // move left #define MAX_RIGHTPOS SCREEN_WIDTH-MIN_LEFTPOS // farthest invaders/player can // move right #endif // File Name: InvaderGroup.h // // Class Name: CInvaderGroup // // Purpose: acts as a container for a space invader CObjects // Has methods to push and remove invaders. Also // has methods to draw the whole invader group and // update whole groups position. // #ifndef __CIGRP__ #define __CIGRP__ #include <vector> using namespace std; #include "objects.h" #include "defines.h" #define MAX_INVGRPROWS 3 #define MAX_INVGRPCOLS 4 class CInvaderGroup { private: vector<CObject> v; // holds invaders stored in this group // CObject are relatively small // if were larger should use pointer to a CObject int xVel; //left right speed of invaders int yOffset; // how far invaders move down when reach a side public: CInvaderGroup() {yOffset=0; xVel=-1;} //constructor void draw(LPDIRECTDRAWSURFACE surface); //draw invaders to surface void create(int x,int y,CBaseSprite* inv[MAX_INVGRPROWS]); //create //instance //note: probably would be better to have inv //be a vector. void move(); //make a move depending on time and speed void remove(int i){ v.erase(&(v[i]));} //remove object from invader // group void push(CObject o) {v.push_back(o);} //add invader ot group void clear(){ v.clear();} //delete all invaders from group int getSize() { return v.size();} //return the number of invaders in //group int getTop(); // y-position of top most invaders int getBottom(); // y-position of bottom most invaders int getRight(); // x-position of rightmost invader int getLeft(); // x-position of leftmost invader }; #endif // // Filename: InvaderGroup.cpp // // Purpose: contains member function defintions for CInvaderGroup // #include "invadergroup.h" // // Member Function: draw // // Purpose: draws each invader in the group to the designated surface // void CInvaderGroup::draw(LPDIRECTDRAWSURFACE surface) { vector<CObject>::iterator i; for(i=v.begin(); i !=v.end(); i++) i->draw(surface); } // // Member Function: create // // Purpose: creates a ``default'' space invader group. (As opposed // to doing push external to the class to make a designer // one.) The default group is horizontally centered at x and its last // row is at height y. inv is the array of sprite images for // the different rows of the group void CInvaderGroup::create(int x,int y, CBaseSprite* inv[MAX_INVGRPROWS]) { CObject obj; int xOld; int xOffset = SCREEN_WIDTH/(1.5*MAX_INVGRPCOLS); //initial x spacing //of invaders xVel = -1; //initial invader velocity yOffset = y/(MAX_INVGRPROWS); // vertical spacing b/w invaders x -= (xOffset * MAX_INVGRPCOLS/2); //passed x in assumed to be //center of invader group //so now get left side xOld=x; for(int i=0; i<MAX_INVGRPROWS; i++) { for(int j=0; j<MAX_INVGRPCOLS; j++) { obj.create(x, y, xVel,0,inv[i]); push(obj); x+=xOffset; } x = xOld; y-= yOffset; } yOffset /=4; // yOffset now used to control how far invaders // move down when reach a side of screen. } // // Member Function: move // // Purpose: updates the position of the invader group. Causes group to // switch direction and move down if reach side of screen. // void CInvaderGroup::move() { vector<CObject>::iterator i; for(i=v.begin(); i != v.end(); i++) { i->move(); } if(getLeft() <MIN_LEFTPOS || getRight() > MAX_RIGHTPOS) { xVel=-xVel; for(i=v.begin(); i != v.end(); i++) { i->setXVel(xVel); i->setY(i->getY()+yOffset); } } } // // Coordinate member functions: // // The next four member functions are used to get the coordinates of // bounding rectangle of the invader group. Could here could easily // be improved. // int CInvaderGroup::getTop() { vector<CObject>::iterator i; int top = SCREEN_HEIGHT; int tmp; for(i=v.begin(); i != v.end(); i++) { tmp = i->getY(); if(top > tmp) top=tmp; } return top; } int CInvaderGroup::getBottom() { vector<CObject>::iterator i; int bot = 0; int tmp; for(i=v.begin(); i != v.end(); i++) { tmp = i->getY(); if(bot < tmp) bot=tmp; } return bot; } int CInvaderGroup::getLeft() { vector<CObject>::iterator i; int left = SCREEN_WIDTH; int tmp; for(i=v.begin(); i != v.end(); i++) { tmp = i->getX(); if(left > tmp) left=tmp; } return left; } int CInvaderGroup::getRight() { vector<CObject>::iterator i; int right = 0; int tmp; for(i=v.begin(); i != v.end(); i++) { tmp = i->getX(); if(right < tmp) right=tmp; } return right; } //objects.h: header file for CObject class // // modified with set and get methods for speed and velocity --cpollett 2001 // also added stuff to cycle through sprite frames (similar to later demos). // //Copyright Ian Parberry, 1999 //Last updated September 28, 1999 #ifndef __OBJECTS__ #define __OBJECTS__ #include "bsprite.h" class CObject{ //class for a moving object private: int m_nX,m_nY; //current location int m_nXspeed,m_nYspeed; //current speed int m_nLastXMoveTime; //last time the object moved int m_nCurrentFrame; //-CP what frame we're on int m_nLastFrameTime; //-CP added a variable holding last time // animation changed CBaseSprite *m_pSprite; //pointer to sprite public: CObject(); //constructor void draw(LPDIRECTDRAWSURFACE surface); //draw void create(int x,int y,int xspeed,int yspeed, CBaseSprite *sprite); //create instance void accelerate(int xdelta,int ydelta=0); //change speed void move(); //make a move depending on time and speed //modified code -CP //various set and get methods int getX() {return m_nX;} int getY() {return m_nY;} void setX(int x) {m_nX = x;} void setY(int y) {m_nY = y;} int getXVel() {return m_nXspeed;} int getYVel() {return m_nYspeed;} void setXVel(int x) {m_nXspeed = x;} void setYVel(int y) {m_nYspeed = y;} }; #endif //objects.cpp //Copyright Ian Parberry, 1999 //Last updated September 28, 1999 #include "objects.h" #include "timer.h" //game timer extern CTimer Timer; CObject::CObject(){ //constructor m_nX=m_nY=m_nXspeed=m_nYspeed=0; m_pSprite=NULL; m_nLastXMoveTime=0; m_nCurrentFrame=0; m_nLastFrameTime=0; } void CObject::draw(LPDIRECTDRAWSURFACE surface){ //draw m_pSprite->draw(m_nCurrentFrame,m_nX,m_nY,surface); } void CObject::create(int x,int y,int xspeed,int yspeed, CBaseSprite *sprite){ m_nLastXMoveTime=0; //time m_nLastFrameTime=0; m_nCurrentFrame=0; m_nX=x; m_nY=y; //location m_nXspeed=xspeed; m_nYspeed=yspeed; //speed m_pSprite=sprite; //image } void CObject::accelerate(int xdelta,int ydelta){ //change speed m_nXspeed+=xdelta; m_nYspeed+=ydelta; } void CObject::move(){ //move object const int XSCALE=8; //to scale back horizontal motion const int MARGIN=100; //margin on outside of page const int FRAME_RATE=500; int xdelta; //change in position int time=Timer.time(); //current time if(time-m_nLastFrameTime > FRAME_RATE) //-CP advance a frame of animation { // if enough time has passed m_nCurrentFrame++; if(m_nCurrentFrame>= m_pSprite->frame_count()) m_nCurrentFrame = 0; m_nLastFrameTime = time; } //horizontal motion int tfactor=time-m_nLastXMoveTime; //time since last move xdelta=(m_nXspeed*tfactor)/XSCALE; //x distance moved m_nX+=xdelta; //x motion if(m_nX<-MARGIN)m_nX=SCREEN_WIDTH+MARGIN; //wrap left if(xdelta||m_nXspeed==0) //record time of move m_nLastXMoveTime=time; if(m_nX>SCREEN_WIDTH+MARGIN)m_nX=-MARGIN; //wrap right } // //Filename: main.cpp // //Purpose: Main window loop. Loads in Graphics controls player and // inavder group // //system includes #include <windows.h> #include <windowsx.h> #include <ddraw.h> #include <stdio.h> #include <stdlib.h> //system defines #define WIN32_LEAN_AND_MEAN //custom includes #include "defines.h" //global definitions #include "bmp.h" //bmp file reader #include "timer.h" //game timer #include "bsprite.h" //for base sprite class #include "objects.h" //for object class #include "invadergroup.h" //for space invader group class //globals BOOL ActiveApp; //is this application active? LPDIRECTDRAW lpDirectDrawObject=NULL; //direct draw object LPDIRECTDRAWSURFACE lpPrimary=NULL; //primary surface LPDIRECTDRAWPALETTE lpPrimaryPalette; //its palette LPDIRECTDRAWSURFACE lpSecondary=NULL; //back buffer LPDIRECTDRAWPALETTE lpSecondaryPalette; //its palette LPDIRECTDRAWSURFACE lpBackground=NULL; //background image CTimer Timer; //game timer CBmpFileReader background; //background image CBmpSpriteFileReader g_cSpriteImages; //sprite images CObject spaceship; //spaceship object CBaseSprite *spaceshipsprite=NULL; //spaceship sprite CObject bunkers[BUNKER_NUM]; CBaseSprite *bunkersprite=NULL; //bunker sprite CInvaderGroup invaders; CBaseSprite *invgrpsprite[MAX_INVGRPROWS]; // invader sprites int minInvHeight; // as low as invaders allowed to go //helper functions LPDIRECTDRAWPALETTE CreatePalette(LPDIRECTDRAWSURFACE surface); BOOL InitDirectDraw(HWND hwnd); HWND CreateDefaultWindow(char* name,HINSTANCE hInstance); BOOL LoadSpaceShipSprite(){ //load player's spaceship image return spaceshipsprite->load(&g_cSpriteImages,0,1,1); } //LoadSpaceShipSprite BOOL LoadBunkerSprite(){ //load bunker image return bunkersprite->load(&g_cSpriteImages,0,121,1); } //LoadBunkerSprite BOOL LoadInvGrpSprite(){ //load invader group images int i; for(i=0; i < MAX_INVGRPROWS; i++) { switch( i%3) { case 0: if(!invgrpsprite[i]->load(&g_cSpriteImages,0,1,73)) return FALSE; if(!invgrpsprite[i]->load(&g_cSpriteImages,1,121,73)) return FALSE; break; case 1: if(!invgrpsprite[i]->load(&g_cSpriteImages,0,244,73)) return FALSE; if(!invgrpsprite[i]->load(&g_cSpriteImages,1,365,73)) return FALSE; break; case 2: if(!invgrpsprite[i]->load(&g_cSpriteImages,0,244,1)) return FALSE; if(!invgrpsprite[i]->load(&g_cSpriteImages,1,365,1)) return FALSE; break; } } return TRUE; } //LoadInvGrpSprite BOOL LoadImages(){ //load graphics from files to surfaces int i; //get the background image if(!background.load("bckgnd.bmp"))return FALSE; //read from file background.draw(lpBackground); //draw to background surface //set palettes in all surfaces if(!background.setpalette(lpPrimaryPalette))return FALSE; if(!background.setpalette(lpSecondaryPalette))return FALSE; //load the plane sprite if(!g_cSpriteImages.load("sprites.bmp"))return FALSE; spaceshipsprite=new CBaseSprite(1,121,72); if(!LoadSpaceShipSprite())return FALSE; //load spaceship images bunkersprite=new CBaseSprite(1,121,72); if(!LoadBunkerSprite())return FALSE; //load bunker images for(i=0; i<MAX_INVGRPROWS; i++) invgrpsprite[i] = new CBaseSprite(2,115,72); if(!LoadInvGrpSprite())return FALSE; //load invader group images return TRUE; } //LoadImages void CreateObjects(){ int i; //don't mess with MST vs. rest of the world counter vars int sHeight= spaceshipsprite->height(); spaceship.create(SCREEN_WIDTH/2,SCREEN_HEIGHT, 0,0,spaceshipsprite); //create plane for(i=0; i < BUNKER_NUM; i++) bunkers[i].create((i+1)*BUNKER_OFFSET,SCREEN_HEIGHT-sHeight, 0,0,bunkersprite); minInvHeight = SCREEN_HEIGHT - sHeight - bunkersprite->height(); invaders.create(SCREEN_WIDTH*2/3,SCREEN_HEIGHT*1/2, invgrpsprite); } //CreateObjects BOOL RestoreSurfaces(){ //restore all surfaces BOOL result=TRUE, flag=FALSE; int i; if(SUCCEEDED(lpPrimary->Restore())) //if primary restored result=result&&background.draw(lpPrimary)&& //redraw image background.setpalette(lpPrimaryPalette); //set palette else return FALSE; if(SUCCEEDED(lpSecondary->Restore())) //if secondary restored result=result&&background.draw(lpSecondary)&& //redraw image background.setpalette(lpSecondaryPalette); //set palette else return FALSE; if(SUCCEEDED(lpBackground->Restore())) //if background restored result=result&&background.draw(lpBackground); //redraw image else return FALSE; if(spaceshipsprite->Restore()) //if spaceship sprite restored result=result&&LoadSpaceShipSprite(); //redraw image else return FALSE; if(bunkersprite->Restore()) //if bunker sprite restored result=result&&LoadBunkerSprite(); //redraw image for(i=0; i < MAX_INVGRPROWS; i++) { if(invgrpsprite[i]->Restore()) //if invader sprites restored flag = TRUE; else return FALSE; } if(flag) result=result&&LoadBunkerSprite(); //redraw image else return FALSE; return result; } //RestoreSurfaces BOOL PageFlip(){ //return TRUE if page flip succeeds if(lpPrimary->Flip(NULL,DDFLIP_WAIT)==DDERR_SURFACELOST) return RestoreSurfaces(); return TRUE; } //PageFlip BOOL ComposeFrame(){ //compose a frame of animation int i; //draw background lpSecondary->BltFast(0,0,lpBackground,NULL, DDBLTFAST_NOCOLORKEY|DDBLTFAST_WAIT); //move spaceship spaceship.move(); // // make sure space ship stays in bounds // if(spaceship.getX() < MIN_LEFTPOS) { spaceship.setX(MIN_LEFTPOS); spaceship.setXVel(0); } if(spaceship.getX() > MAX_RIGHTPOS) { spaceship.setX(MAX_RIGHTPOS); spaceship.setXVel(0); } // move invaders invaders.move(); // // make sure invaders stays in bounds // if(invaders.getBottom() > minInvHeight) { invaders.clear(); invaders.create(SCREEN_WIDTH*2/3,SCREEN_HEIGHT*1/2, invgrpsprite); Timer.start(); } //draw objects spaceship.draw(lpSecondary); for(i=0; i < BUNKER_NUM; i++) bunkers[i].draw(lpSecondary); invaders.draw(lpSecondary); return TRUE; } //ComposeFrame BOOL ProcessFrame(){ //process a frame of animation ComposeFrame(); //compose a frame in secondary surface return PageFlip(); //flip video memory surfaces } //ProcessFrame BOOL keyboard_handler(WPARAM keystroke){ //keyboard handler BOOL result=FALSE; //return TRUE if game is to end switch(keystroke){ case VK_ESCAPE: result=TRUE; break; //exit game case VK_SPACE: //delete a random invader invaders.remove(rand()%invaders.getSize()); break; // //space ship controls // case VK_LEFT: spaceship.accelerate(-1); break; case VK_RIGHT: spaceship.accelerate(1); break; case VK_DOWN: spaceship.setXVel(0); break; default: break; } return result; } //keyboard_handler //message handler (window procedure) long CALLBACK WindowProc(HWND hwnd,UINT message, WPARAM wParam,LPARAM lParam){ switch(message){ case WM_ACTIVATEAPP: ActiveApp=wParam; break; case WM_CREATE: break; case WM_KEYDOWN: //keyboard hit if(keyboard_handler(wParam))DestroyWindow(hwnd); break; case WM_DESTROY: //end of game if(lpDirectDrawObject!=NULL){ //if DD object exists if(lpSecondary!=NULL) //if secondary surface exists lpSecondary->Release(); //release secondary surface if(lpPrimary!=NULL) //if primary surface exists lpPrimary->Release(); //release primary surface if(lpBackground!=NULL) //if background exists lpBackground->Release(); //release background if(spaceshipsprite!=NULL) //if spaceship sprite exists spaceshipsprite->Release(); //release spaceship sprite delete spaceshipsprite; //delete spaceship sprite if(bunkersprite!=NULL) //if bunker sprite exists bunkersprite->Release(); //release bunker sprite delete bunkersprite; //delete bunker sprite int i; for(i=0; i < MAX_INVGRPROWS; i++) { if(invgrpsprite[i]!=NULL) //if invgrpsprite exists invgrpsprite[i]->Release(); //release invgrpsprite delete invgrpsprite[i]; } lpDirectDrawObject->Release(); //release DD object } ShowCursor(TRUE); //show the mouse cursor PostQuitMessage(0); //and exit break; default: //default window procedure return DefWindowProc(hwnd,message,wParam,lParam); } //switch(message) return 0L; } //WindowProc int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nCmdShow){ MSG msg; //current message HWND hwnd; //handle to fullscreen window hwnd=CreateDefaultWindow("directX demo 3",hInstance); if(!hwnd)return FALSE; //set up window ShowWindow(hwnd,nCmdShow); UpdateWindow(hwnd); SetFocus(hwnd); //allow input from keyboard ShowCursor(FALSE); //hide the cursor //init graphics BOOL OK=InitDirectDraw(hwnd);//initialize DirectDraw if(OK)OK=LoadImages(); //load images from disk if(!OK){ //bail out if initialization failed DestroyWindow(hwnd); return FALSE; } //start game timer Timer.start(); //create objects CreateObjects(); //message loop while(TRUE) if(PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)){ if(!GetMessage(&msg,NULL,0,0))return msg.wParam; TranslateMessage(&msg); DispatchMessage(&msg); } else if(ActiveApp)ProcessFrame(); else WaitMessage(); } //WinMain |