// Vazteroids a game by PhilVaz // Full Screen GDI game // May 20, 2003 // Feb 20, 2004 -- Joystick support added // INCLUDES /////////////////////////////////////////////// #define WIN32_LEAN_AND_MEAN #include // include all the windows headers #include // include useful macros #include // for DirectSound #include // for rand functions #include #include #include // include DirectSound #include "dsutil.h" // for LoadSoundBuffer() #include "Vazteroids.h" // sounds and icon resources // DEFINES //////////////////////////////////////////////// // defines for windows #define WINDOW_CLASS_NAME "WINCLASS1" #define WINDOW_WIDTH 800 // size of game window #define WINDOW_HEIGHT 600 #define GAME_SPEED 30 // speed of game (increase to go slower) #define GAME_STATE_DEMO_INIT 0 // demo initialization state #define GAME_STATE_DEMO_RUN 1 // demo running state #define GAME_STATE_GAME_INIT 2 // game initialization state #define GAME_STATE_GAME_RUN 3 // game running state #define GAME_STATE_GAME_RESET 4 // game reset state (new level) #define GAME_STATE_GAME_PAUSE 5 // game pause state (no movement) #define THRUST_SPEED .75f #define THRUST_FRICTION .1f #define MAX_SHIP_SPEED 20 #define BULLET_SPEED 12.0f #define MAX_ASTEROIDS 60 #define MAX_PARTICLES 2000 #define MAX_BULLETS 5 #define TIME_BETWEEN_BULLETS 5 #define TIME_FOR_SHIP_REGENERATION 300 // about 5 seconds #define TIME_BETWEEN_LEVELS 80 // about 2 seconds #define DIFFICULTY_EASY 0 #define DIFFICULTY_HARD 1 #define NUMBER_OF_SHIPS 5 #define SCORE_FOR_EXTRA_SHIP 5000 #define SCORE_FOR_SMALL_ROCK 50 #define SCORE_FOR_MEDIUM_ROCK 25 #define SCORE_FOR_LARGE_ROCK 10 #define SCORE_FOR_LARGE_UFO 100 #define SCORE_FOR_SMALL_UFO 500 #define CHANCE_FOR_LARGE_UFO 3 // out of 1000 #define CHANCE_FOR_SMALL_UFO 2 // out of 1000 #define DURATION_FOR_SHIP_BULLET 40 #define DURATION_FOR_UFO_BULLET 50 // MACROS ///////////////////////////////////////////////// #define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0) #define KEYUP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1) // GLOBALS //////////////////////////////////////////////// HWND game_window = NULL; // global game window handle HINSTANCE game_instance = NULL; // global game instance handle HDC game_dc = NULL; // global device context (for GDI) handle // for back (double) buffering HDC back_dc = NULL; HBITMAP back_bmp = NULL; HBITMAP old_bmp = NULL; RECT back_rect = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; LPDIRECTSOUND game_sound_main = NULL; // global direct sound object LPDIRECTSOUNDBUFFER game_sound_fire1 = NULL; // sound ship fire LPDIRECTSOUNDBUFFER game_sound_fire2 = NULL; // sound ufo fire LPDIRECTSOUNDBUFFER game_sound_explode1 = NULL; // sound explode small LPDIRECTSOUNDBUFFER game_sound_explode2 = NULL; // sound explode medium LPDIRECTSOUNDBUFFER game_sound_explode3 = NULL; // sound explode large LPDIRECTSOUNDBUFFER game_sound_explode4 = NULL; // sound explode ufo LPDIRECTSOUNDBUFFER game_sound_explode5 = NULL; // sound explode ship LPDIRECTSOUNDBUFFER game_sound_regen1 = NULL; // sound regeneration start LPDIRECTSOUNDBUFFER game_sound_regen2 = NULL; // sound regeneration finish LPDIRECTSOUNDBUFFER game_sound_thrust = NULL; // sound ship thrust LPDIRECTSOUNDBUFFER game_sound_ufo1 = NULL; // sound small ufo LPDIRECTSOUNDBUFFER game_sound_ufo2 = NULL; // sound large ufo LPDIRECTSOUNDBUFFER game_sound_extra = NULL; // sound extra ship DEVMODE game_screen; // global for full screen mode // global pens and brush HPEN red_pen = CreatePen(PS_SOLID, 2, RGB(255,0,0)); HPEN green_pen = CreatePen(PS_SOLID, 2, RGB(0,255,0)); HPEN blue_pen = CreatePen(PS_SOLID, 2, RGB(0,0,255)); HPEN white_pen = CreatePen(PS_SOLID, 2, RGB(255,255,255)); HPEN regen_pen = CreatePen(PS_SOLID, 2, RGB(255,255,255)); HPEN black_pen = CreatePen(PS_SOLID, 2, RGB(0,0,0)); HBRUSH black_brush = CreateSolidBrush(RGB(0,0,0)); HBRUSH white_brush = CreateSolidBrush(RGB(255,255,255)); // global joystick variables bool joy_ok; // whether joystick found ok UINT joy_num; // number of joys JOYINFO joy_info; // joy init info UINT joy_ID; // joy ID JOYCAPS joy_caps; // joy capture info RECT joy_trip; // joy trip info DWORD joy_xcenter; // joy x axis center DWORD joy_ycenter; // joy y axis center // joy directions (1=true, 0=false) int joy_left, joy_right, joy_up, joy_down, joy_but1, joy_but2, joy_but3, joy_but4; // global game variables int game_state = GAME_STATE_DEMO_INIT; // start in demo state char text[80]; // for display text output int game_score = 0; // set score to zero int game_level = 1; // set level to one int game_difficulty = DIFFICULTY_EASY; int rocks_hit = 0; int ships_left = 0; int bullet_countdown = 0; // countdown between bullets int level_countdown = 0; // countdown between levels bool sound_ok; // for whether DirectSound set okay int extra_score; // target score for extra ship POINT points[9]; // for temp display of polygon points (rock and ship) // // asteroid polygon shape (9 points each, 5 shapes) relative to center point // (24 x 24 square total) // int xrock[5][9] = { { -10, -11, -10, -8, 0, 9, 12, 8, 1 }, { -7, -10, -11, -4, 5, 12, 8, 2, -3 }, { -9, -10, -8, 2, 12, 11, 9, 2, -4 }, { 7, -1, -7, -12, -5, 7, 11, 12, 10 }, { 10, 12, 9, 3, -8, -9, -11, -3, 4 } }; int yrock[5][9] = { { -11, -3, 2, 7, 11, 7, -1, -9, -10 }, { -12, -5, 3, 12, 9, 0, -7, -9, -10 }, { -7, -1, 8, 9, 12, 2, -7, -12, -9 }, { -12, -10, -5, 3, 12, 10, 5, -2, -8 }, { -12, -1, 8, 12, 9, 0, -5, -9, -11 } }; // // ship polygon shape (32 rotation positions, 4 points each) // int xship[4][32] = { {0, 2, 4, 6, 8, 9, 10, 11, 11, 11, 10, 9, 8, 6, 4, 2, 0, -2, -4, -6, -8, -9, -10, -11, -11, -11, -10, -9, -8, -6, -4, -2}, {-7, -9, -11, -12, -13, -14, -14, -13, -12, -10, -8, -6, -4, -1, 2, 5, 7, 9, 11, 12, 13, 14, 14, 13, 12, 10, 8, 6, 4, 1, -2, -5}, {0, -2, -3, -5, -6, -7, -8, -9, -9, -9, -8, -7, -6, -5, -3, -2, 0, 2, 3, 5, 6, 7, 8, 9, 9, 9, 8, 7, 6, 5, 3, 2}, {8, 6, 3, 0, -3, -6, -8, -10, -12, -13, -14, -14, -14, -13, -12, -10, -8, -6, -3, 0, 3, 6, 8, 10, 12, 13, 14, 14, 14, 13, 12, 10} }; int yship[4][32] = { {-11, -11, -10, -9, -8, -6, -4, -2, 0, 2, 4, 6, 8, 9, 10, 11, 11, 11, 10, 9, 8, 6, 4, 2, 0, -2, -4, -6, -8, -9, -10, -11}, {12, 10, 8, 6, 4, 1, -2, -5, -7, -9, -11, -12, -13, -14, -14, -13, -12, -10, -8, -6, -4, -1, 2, 5, 7, 9, 11, 12, 13, 14, 14, 13}, {9, 9, 8, 7, 6, 5, 3, 2, 0, -2, -3, -5, -6, -7, -8, -9, -9, -9, -8, -7, -6, -5, -3, -2, 0, 2, 3, 5, 6, 7, 8, 9}, {12, 13, 14, 14, 14, 13, 12, 10, 8, 6, 3, 0, -3, -6, -8, -10, -12, -13, -14, -14, -14, -13, -12, -10, -8, -6, -3, 0, 3, 6, 8, 10} }; // // THRUST (move) and BULLET (shoot) direction X (sin) and Y (-cos) // float xdir[32] = {0.0f, 0.1951f, 0.3827f, 0.5556f, 0.7071f, 0.8315f, 0.9239f, 0.9808f, 1.0f, 0.9808f, 0.9239f, 0.8315f, 0.7071f, 0.5556f, 0.3827f, 0.1951f, 0.0f, -0.1951f, -0.3827f, -0.5556f, -0.7071f, -0.8315f, -0.9239f, -0.9808f, -1.0f, -0.9808f, -0.9239f, -0.8315f, -0.7071f, -0.5556f, -0.3827f, -0.1951f}; float ydir[32] = {-1.0f, -0.9808f, -0.9239f, -0.8315f, -0.7071f, -0.5556f, -0.3827f, -0.1951f, 0.0f, 0.1951f, 0.3827f, 0.5556f, 0.7071f, 0.8315f, 0.9239f, 0.9808f, 1.0f, 0.9808f, 0.9239f, 0.8315f, 0.7071f, 0.5556f, 0.3827f, 0.1951f, 0.0f, -0.1951f, -0.3827f, -0.5556f, -0.7071f, -0.8315f, -0.9239f, -0.9808f}; typedef struct { bool alive; // is alive TRUE/FALSE int xcenter; // x center of asteroid int ycenter; // y center of asteroid int xmove; // x movement direction (x vector) int ymove; // y movement direction (y vector) int shape; // shape of rock (0 to 4 shapes) int size; // 1=small, 2=medium, 3=large } ASTEROID_STRUCT; ASTEROID_STRUCT Rocks[MAX_ASTEROIDS]; typedef struct { int regen; // regeneration time left for fade in float xcenter; // x center of ship float ycenter; // y center of ship float xmove; // x movement direction (x vector) float ymove; // y movement direction (y vector) int angle; // 0 to 31 angle positions for array } SHIP_STRUCT; SHIP_STRUCT Ship; typedef struct { bool alive; // is alive TRUE/FALSE float xcenter; // x center of bullet float ycenter; // y center of bullet float xmove; // x movement direction (x vector) float ymove; // y movement direction (y vector) int duration; // duration of bullet } BULLET_STRUCT; BULLET_STRUCT Bullets[MAX_BULLETS]; typedef struct { bool alive; // is alive TRUE/FALSE int size; // 2 = large dumb, 1 = small smart int xcenter; // x center of UFO int ycenter; // y center of UFO int xmove; // x movement direction (x vector) int ymove; // y movement direction (y vector) float xbullet; // x center of UFO bullet float ybullet; // y center of UFO bullet float xbmove; // x movement direction of UFO bullet float ybmove; // y movement direction of UFO bullet int duration; // duration of UFO bullet, when done fire again } UFO_STRUCT; UFO_STRUCT UFO; typedef struct { bool alive; // is alive TRUE/FALSE float xcenter; // x center of particle float ycenter; // y center of particle float xmove; // x movement direction (x vector) float ymove; // y movement direction (y vector) int duration; // duration of particle, keep on screen then fade out } PARTICLE_STRUCT; PARTICLE_STRUCT Particles[MAX_PARTICLES]; // FUNCTIONS ////////////////////////////////////////////// void GameInit(); // game initialization, go full screen etc void GameMain(); // game main loop and processing void GameQuit(); // game quit and clean up void DisplayScore(); // display text score/level bottom of screen void SetRocks(); void MoveRocks(); void SetShip(); void MoveShip(); void RotateShip(int); void MoveUFO(); // insert rocks at point x,y of type t void InsertRocks(int, int, int); void InsertBullet(); void MoveBullets(); void SetUFOBullet(); void MoveUFOBullet(); // insert particle explosion at point x,y of type t void InsertParticles(int, int, int); void MoveParticles(); bool SoundInit(); void SoundQuit(); bool JoyInit(); void JoyQuit(); void JoyStatus(); // set polygon points for rock and Ship void SetRockPoints(int); void SetShipPoints(int); void CheckCollisions(); // Check for all potential Collisions void ResetAll(); // Reset (clear) all rocks, bullets, UFO, etc // WINPROC //////////////////////////////////////////////// LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { // this is the main message handler of the system HDC hdc; // handle to a device context PAINTSTRUCT ps; // used in WM_PAINT switch(msg) // what is the message { case WM_CREATE: { // do initialization stuff here return(0); // return success } break; case WM_PAINT: { hdc = BeginPaint(hwnd, &ps); // validate the window EndPaint(hwnd, &ps); return(0); // return success } break; case WM_DESTROY: { PostQuitMessage(0); // kill the application, sends a WM_QUIT message return(0); // return success } break; default:break; } // end switch // process any default messages return (DefWindowProc(hwnd, msg, wparam, lparam)); } // end WinProc // WINMAIN //////////////////////////////////////////////// int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) { WNDCLASSEX winclass; // this will hold the class we create HWND hwnd; // generic window handle MSG msg; // generic message // save the game instance handle game_instance = hinstance; // first fill in the window class structure // WHEN DONE ADD // LoadIcon(game_instance, MAKEINTRESOURCE(ICON_VAZGAMES)) winclass.cbSize = sizeof(WNDCLASSEX); winclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW; winclass.lpfnWndProc = WinProc; winclass.cbClsExtra = 0; winclass.cbWndExtra = 0; winclass.hInstance = hinstance; winclass.hIcon = LoadIcon(game_instance, IDI_APPLICATION); winclass.hIconSm = LoadIcon(game_instance, IDI_APPLICATION); winclass.hCursor = LoadCursor(NULL, IDC_ARROW); winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); winclass.lpszMenuName = NULL; winclass.lpszClassName = WINDOW_CLASS_NAME; // register the window class if (!RegisterClassEx(&winclass)) return(0); // create the window if (!(hwnd = CreateWindowEx(NULL, // extended style WINDOW_CLASS_NAME, // class "Vazteroids", // title WS_POPUP | WS_VISIBLE, // use POPUP for full screen 0,0, // initial game window x,y WINDOW_WIDTH, // initial game width WINDOW_HEIGHT, // initial game height NULL, // handle to parent NULL, // handle to menu hinstance, // instance of this application NULL))) // extra creation parms return(0); // save the game window handle game_window = hwnd; GameInit(); // game initialization function called here // enter main event loop using PeekMessage() to retrieve messages while(TRUE) { // get initial tick count to keep game speed constant DWORD start_tick = GetTickCount(); // is there a message in queue, if so get it if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { // test if this is a quit if (msg.message == WM_QUIT) break; // translate any accelerator keys TranslateMessage(&msg); // send the message to WinProc DispatchMessage(&msg); } // end if // if we're not in pause state, erase the back buffer if (game_state != GAME_STATE_GAME_PAUSE) FillRect(back_dc, &back_rect, black_brush); GameMain(); // game main processing function called here // copy back buffer to front buffer BitBlt(game_dc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, back_dc, 0, 0, SRCCOPY); // check for key and send quit game if (KEYDOWN(VK_ESCAPE)) SendMessage (hwnd, WM_CLOSE, 0, 0); // wait until we hit correct game speed frame rate while ((GetTickCount() - start_tick) < GAME_SPEED); } // end while GameQuit(); // game quit function and clean up before exit called here return(msg.wParam); // return to Windows } // end WinMain // BEGIN GAME CODE //////////////////////////////////////// /////////////////////////////////////////////////////////// // // GAME INITIALIZATION // /////////////////////////////////////////////////////////// void GameInit() { srand(GetTickCount()); // seed the random numbers // temporary change to full screen mode ZeroMemory(&game_screen, sizeof(game_screen)); // clear out size of DEVMODE struct game_screen.dmSize = sizeof(game_screen); game_screen.dmPelsWidth = WINDOW_WIDTH; game_screen.dmPelsHeight = WINDOW_HEIGHT; game_screen.dmBitsPerPel = 16; game_screen.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; ChangeDisplaySettings(&game_screen, CDS_FULLSCREEN); game_dc = GetDC(game_window); // get the GDI device context // for back (double) buffering back_dc = CreateCompatibleDC(game_dc); back_bmp = CreateCompatibleBitmap(game_dc, WINDOW_WIDTH, WINDOW_HEIGHT); old_bmp = (HBITMAP)SelectObject(back_dc, back_bmp); ShowCursor(FALSE); // Initialize DirectSound sound_ok = SoundInit(); // Initialize Joystick joy_ok = JoyInit(); ResetAll(); } // END OF GameInit /////////////////////////////////////////////////////////// // // GAME MAIN LOOP AND PROCESSING // /////////////////////////////////////////////////////////// void GameMain() { switch(game_state) { case GAME_STATE_DEMO_INIT: { SetRocks(); game_state = GAME_STATE_DEMO_RUN; } break; case GAME_STATE_DEMO_RUN: { MoveRocks(); MoveParticles(); MoveUFO(); MoveUFOBullet(); CheckCollisions(); DisplayScore(); // check for key and if pressed move to GAME_INIT state if (KEYDOWN(VK_SPACE) || KEYDOWN(49)) // space or 1 key pressed { game_state = GAME_STATE_GAME_INIT; game_difficulty = DIFFICULTY_EASY; } if (KEYDOWN(50)) // 2 key pressed { game_state = GAME_STATE_GAME_INIT; game_difficulty = DIFFICULTY_HARD; } } break; case GAME_STATE_GAME_INIT: { // reset score, level, ships, rocks to initial values game_score = 0; game_level = 1; ships_left = NUMBER_OF_SHIPS; extra_score = SCORE_FOR_EXTRA_SHIP; ResetAll(); SetShip(); SetRocks(); game_state = GAME_STATE_GAME_RUN; } break; case GAME_STATE_GAME_RUN: { MoveBullets(); MoveShip(); MoveRocks(); MoveParticles(); MoveUFO(); MoveUFOBullet(); CheckCollisions(); DisplayScore(); // if 'p' key pressed, set state to GAME_PAUSE if (KEYDOWN(80)) game_state = GAME_STATE_GAME_PAUSE; } break; case GAME_STATE_GAME_RESET: { game_level++; SetRocks(); game_state = GAME_STATE_GAME_RUN; } break; case GAME_STATE_GAME_PAUSE: { // if key pressed resume game if (KEYDOWN(VK_SPACE)) game_state = GAME_STATE_GAME_RUN; } break; } // end switch } // END OF GameMain /////////////////////////////////////////////////////////// // // GAME QUIT AND CLEAN UP // /////////////////////////////////////////////////////////// void GameQuit() { SoundQuit(); // turn off DirectSound and release buffers JoyQuit(); // release Joystick // delete the pens and brushes DeleteObject(red_pen); DeleteObject(green_pen); DeleteObject(blue_pen); DeleteObject(white_pen); DeleteObject(regen_pen); DeleteObject(black_pen); DeleteObject(black_brush); DeleteObject(white_brush); // release the back buffer SelectObject(back_dc, old_bmp); DeleteObject(back_bmp); DeleteDC(back_dc); // release the device context (for GDI) from the game window ReleaseDC(game_window, game_dc); // return to original display settings ChangeDisplaySettings(NULL,NULL); } // END OF GameQuit ///////////////////////////////////////////////////////// // // display text score/level/ships bottom of screen // ///////////////////////////////////////////////////////// void DisplayScore() { int temp; SetTextColor(back_dc, RGB(255,255,255)); // white text color SetBkColor(back_dc, RGB(0,0,0)); // black background sprintf(text,"SCORE = %d", game_score); TextOut(back_dc, 80, 580, text, strlen(text)); sprintf(text,"LEVEL = %d", game_level); TextOut(back_dc, 210, 580, text, strlen(text)); sprintf(text,"SHIPS = %d", ships_left); TextOut(back_dc, 340, 580, text, strlen(text)); sprintf(text,"Vazteroids a game by PhilVaz (c) 2003"); TextOut(back_dc, 470, 580, text, strlen(text)); if (game_state == GAME_STATE_DEMO_RUN) { sprintf(text,"Vazteroids a game by PhilVaz (c) 2003"); TextOut(back_dc, 280, 130, text, strlen(text)); sprintf(text,"www.bringyou.to/games"); TextOut(back_dc, 320, 150, text, strlen(text)); sprintf(text,"Left/Right Arrow Keys = Rotate Ship"); TextOut(back_dc, 280, 170, text, strlen(text)); sprintf(text,"CTRL = Fire, Up Arrow = Thrust"); TextOut(back_dc, 280, 190, text, strlen(text)); sprintf(text,"JOYSTICK AVAILABLE if Joystick detected"); TextOut(back_dc, 280, 210, text, strlen(text)); temp = SCORE_FOR_LARGE_ROCK; sprintf(text,"%d Points for Large Rock", temp); TextOut(back_dc, 300, 250, text, strlen(text)); temp = SCORE_FOR_MEDIUM_ROCK; sprintf(text,"%d Points for Medium Rock", temp); TextOut(back_dc, 300, 270, text, strlen(text)); temp = SCORE_FOR_SMALL_ROCK; sprintf(text,"%d Points for Small Rock", temp); TextOut(back_dc, 300, 290, text, strlen(text)); temp = SCORE_FOR_LARGE_UFO; sprintf(text,"%d Points for Large UFO", temp); TextOut(back_dc, 300, 340, text, strlen(text)); temp = SCORE_FOR_SMALL_UFO; sprintf(text,"%d Points for Small UFO", temp); TextOut(back_dc, 300, 360, text, strlen(text)); temp = SCORE_FOR_EXTRA_SHIP; sprintf(text,"Extra Ship Every %d Points", temp); TextOut(back_dc, 300, 380, text, strlen(text)); sprintf(text,"

key pauses the game during play"); TextOut(back_dc, 280, 430, text, strlen(text)); sprintf(text,"press or 1 = easy, 2 = hard to begin new game"); TextOut(back_dc, 210, 450, text, strlen(text)); } // end of if } // END OF DisplayScore ///////////////////////////////////////////////////////// // // Set up new level of rocks // Level 1 = 4 large, 2 = 6 large, 3 = 8 large // ///////////////////////////////////////////////////////// void SetRocks() { int i, num, side; num = (game_level * 2) + 2; if (num > 8) num = 8; for (i = 0; i < num; i++) { Rocks[i].alive = TRUE; Rocks[i].size = 3; Rocks[i].shape = (rand()%5); do { Rocks[i].xmove = (rand()%7) - 3; // x speed from -3 to +3 Rocks[i].ymove = (rand()%7) - 3; // y speed from -3 to +3 } while(Rocks[i].xmove == 0 && Rocks[i].ymove == 0); // in case no movement side = (rand()%4); // pick a side for rock to appear if (side == 0) { Rocks[i].xcenter = (rand()%(WINDOW_WIDTH - 100)) + 50; Rocks[i].ycenter = (rand()%50) + 50; } if (side == 1) { Rocks[i].xcenter = (rand()%(WINDOW_WIDTH - 100)) + 50; Rocks[i].ycenter = (rand()%50) + (WINDOW_HEIGHT - 100); } if (side == 2) { Rocks[i].xcenter = (rand()%50) + 50; Rocks[i].ycenter = (rand()%(WINDOW_HEIGHT - 100)) + 50; } if (side == 3) { Rocks[i].xcenter = (rand()%50) + (WINDOW_WIDTH - 100); Rocks[i].ycenter = (rand()%(WINDOW_HEIGHT - 100)) + 50; } } // end of for if (game_level > 1) level_countdown = TIME_BETWEEN_LEVELS; rocks_hit = 0; } // END OF SetRocks ///////////////////////////////////////////////////////// // // Move all current rocks once // ///////////////////////////////////////////////////////// void MoveRocks() { int i, x, y; // check for level countdown = pause time between levels if (level_countdown > 0) { level_countdown--; return; } // move and draw all living rock asteroids to back buffer for (i = 0; i < MAX_ASTEROIDS; i++) { if (Rocks[i].alive) { // save current x and y point x = Rocks[i].xcenter; y = Rocks[i].ycenter; // move x and y point x += Rocks[i].xmove; y += Rocks[i].ymove; // check if out of range on x axis, if so set wrap around x if (x < 50) x = WINDOW_WIDTH - 50; else if (x > (WINDOW_WIDTH - 50)) x = 50; // check if out of range on y axis, if so set wrap around y if (y < 50) y = WINDOW_HEIGHT - 50; else if (y > (WINDOW_HEIGHT - 50)) y = 50; // save new x and y point Rocks[i].xcenter = x; Rocks[i].ycenter = y; // after move and/or wrap draw rock in new position // select the correct color based on size if (Rocks[i].size == 1) SelectObject(back_dc, red_pen); if (Rocks[i].size == 2) SelectObject(back_dc, blue_pen); if (Rocks[i].size == 3) SelectObject(back_dc, green_pen); SelectObject(back_dc, black_brush); // always black fill brush // set the points of the rock polygon SetRockPoints(i); // draw the rock polygon to back buffer Polygon(back_dc, points, 9); } // end of if } // end of for } // END OF MoveRocks ///////////////////////////////////////////////////////// // // Set new ship (middle of screen pointing up) // set regen time for fade in // ///////////////////////////////////////////////////////// void SetShip() { // set initial position and speed of ship Ship.xcenter = WINDOW_WIDTH / 2.0; Ship.ycenter = WINDOW_HEIGHT / 2.0; Ship.xmove = 0.0; // no movement on x Ship.ymove = 0.0; // no movement on y Ship.angle = 0; // point up to start Ship.regen = TIME_FOR_SHIP_REGENERATION; // set regen time so ship will fade in } // END OF SetShip ///////////////////////////////////////////////////////// // // Move ship once, checks for regen time // moves/updates, checks for rotate/thrust/fire // ///////////////////////////////////////////////////////// void MoveShip() { int c; // for ship color change if (Ship.regen < 225) // check if ship is barely visible { if (joy_ok) JoyStatus(); if (KEYDOWN(VK_RIGHT) || joy_right) RotateShip(1); if (KEYDOWN(VK_LEFT) || joy_left) RotateShip(-1); if (KEYDOWN(VK_CONTROL) || joy_but1) InsertBullet(); } Ship.xcenter += Ship.xmove; Ship.ycenter += Ship.ymove; // check if out of range on x or y axis, if so wrap around if (Ship.xcenter < 25) Ship.xcenter = WINDOW_WIDTH - 25; else if (Ship.xcenter > (WINDOW_WIDTH - 25)) Ship.xcenter = 25; if (Ship.ycenter < 25) Ship.ycenter = WINDOW_HEIGHT - 25; else if (Ship.ycenter > (WINDOW_HEIGHT - 25)) Ship.ycenter = 25; // draw the new ship position to back buffer // first check for regeneration time, if 0 then fully bright white if (Ship.regen == 0) { SelectObject(back_dc, white_pen); // white outline pen SelectObject(back_dc, black_brush); SetShipPoints(Ship.angle); // set points of ship at ship angle Polygon(back_dc, points, 4); // draw the ship polygon } else // regen greater than 0 so select regen color { Ship.regen--; // decrement regeneration time by one if (Ship.regen < 255) // check if within regen color range { SelectObject(back_dc, white_pen); // draw a circle (shield) around ship SelectObject(back_dc, black_brush); Ellipse(back_dc,(int)Ship.xcenter-17,(int)Ship.ycenter-17,(int)Ship.xcenter+17,(int)Ship.ycenter+17); c = 255 - Ship.regen; DeleteObject(regen_pen); regen_pen = CreatePen(PS_SOLID,2,RGB(c,c,c)); // create new regen color SelectObject(back_dc, regen_pen); c = Ship.regen; if (c == 250) { if (sound_ok) // Play Ship Regen Start Sound IDirectSoundBuffer_Play(game_sound_regen1,0,0,NULL); } if (c == 3) { if (sound_ok) // Play Ship Regen Finish Sound IDirectSoundBuffer_Play(game_sound_regen2,0,0,NULL); } if ((c>60 && c<70) || (c>40 && c<50) || (c>20 && c<30) || (c>0 && c<10)) SelectObject(back_dc, white_brush); else SelectObject(back_dc, black_brush); SetShipPoints(Ship.angle); // set points of ship at ship angle Polygon(back_dc, points, 4); // draw the ship polygon } // end of regen < 255 } // end of else regen > 0 if (Ship.regen < 225 && (KEYDOWN(VK_UP) || joy_but3)) // thrust is pressed { // speed ship up Ship.xmove += xdir[Ship.angle] * THRUST_SPEED; Ship.ymove += ydir[Ship.angle] * THRUST_SPEED; if (Ship.xmove > 20.0) Ship.xmove = 20.0; if (Ship.xmove < -20.0) Ship.xmove = -20.0; if (Ship.ymove > 20.0) Ship.ymove = 20.0; if (Ship.ymove < -20.0) Ship.ymove = -20.0; InsertParticles((int)Ship.xcenter, (int)Ship.ycenter, 0); // thrust particles } // end of if else // no thrust -- use friction to slow ship down { if (sound_ok) IDirectSoundBuffer_Stop(game_sound_thrust); // stop thrust sound if (Ship.xmove > 0) Ship.xmove -= THRUST_FRICTION; if (Ship.xmove < 0) Ship.xmove += THRUST_FRICTION; if (Ship.ymove > 0) Ship.ymove -= THRUST_FRICTION; if (Ship.ymove < 0) Ship.ymove += THRUST_FRICTION; if (Ship.xmove < .1 && Ship.xmove > -.1) Ship.xmove = 0.0; if (Ship.ymove < .1 && Ship.ymove > -.1) Ship.ymove = 0.0; } // end of else } // END OF MoveShip ////////////////////////////////////////////// // // Rotate Ship specified number of degrees // ////////////////////////////////////////////// void RotateShip(int deg) { Ship.angle += deg; // increment/decrement new angle by given degrees // check if out of range if (Ship.angle > 31) Ship.angle -= 32; if (Ship.angle < 0) Ship.angle += 32; } // END OF RotateShip ////////////////////////////////////////////////////////////// // // Move existing UFO once, randomly create one if not exist // ////////////////////////////////////////////////////////////// void MoveUFO() { int x, y, s; if (UFO.alive) { // move the UFO, randomly change direction // save current x and y point, and size x = UFO.xcenter; y = UFO.ycenter; s = UFO.size; // move x and y point x += UFO.xmove; y += UFO.ymove; // check if out of range on x axis if (x < 25 || x > (WINDOW_WIDTH - 25)) { // make disappear or bounce off side if ((rand()%10) > 5) { UFO.alive = FALSE; if (UFO.size == 1 && sound_ok) IDirectSoundBuffer_Stop(game_sound_ufo1); if (UFO.size == 2 && sound_ok) IDirectSoundBuffer_Stop(game_sound_ufo2); } else { UFO.xmove = -(UFO.xmove); x += UFO.xmove; } } // end of if // check if out of range on y axis if (y < 25 || y > (WINDOW_HEIGHT - 25)) { // make disappear or bounce off side if ((rand()%10) > 5) { UFO.alive = FALSE; if (UFO.size == 1 && sound_ok) IDirectSoundBuffer_Stop(game_sound_ufo1); if (UFO.size == 2 && sound_ok) IDirectSoundBuffer_Stop(game_sound_ufo2); } else { UFO.ymove = -(UFO.ymove); y += UFO.ymove; } } // end of if // save new x and y point UFO.xcenter = x; UFO.ycenter = y; // randomly change direction do { if (rand()%500 < 2) UFO.xmove = rand()%13 - 6; if (rand()%500 < 2) UFO.ymove = rand()%13 - 6; } while (UFO.xmove == 0 && UFO.ymove == 0); // after move draw UFO ellipses in new position SelectObject(back_dc, white_pen); SelectObject(back_dc, black_brush); // black fill top UFO part Ellipse(back_dc, x - 4*s, y - 9*s, x + 4*s, y - 4*s); SelectObject(back_dc, white_brush); // white fill bottom UFO part Ellipse(back_dc, x - 10*s, y - 4*s, x + 10*s, y + 4*s); } // end of long if else // UFO is not alive, determine chance to set one { if ((rand()%1000 < CHANCE_FOR_SMALL_UFO) && (rocks_hit > 20)) { // set small smart UFO UFO.alive = TRUE; UFO.size = 1; // Play Small UFO Sound if (game_state == GAME_STATE_GAME_RUN && sound_ok) IDirectSoundBuffer_Play(game_sound_ufo1,0,0,DSBPLAY_LOOPING); } else if (rand()%1000 < CHANCE_FOR_LARGE_UFO) { // set large dumb UFO UFO.alive = TRUE; UFO.size = 2; // Play Large UFO Sound if (game_state == GAME_STATE_GAME_RUN && sound_ok) IDirectSoundBuffer_Play(game_sound_ufo2,0,0,DSBPLAY_LOOPING); } if (UFO.alive) { // UFO was set, determine side x y and direction s = rand()%4; if (s == 0) { UFO.xcenter = (rand()%(WINDOW_WIDTH - 100)) + 50; UFO.ycenter = (rand()%50) + 50; UFO.ymove = (rand()%6) + 1; UFO.xmove = (rand()%13) - 6; } if (s == 1) { UFO.xcenter = (rand()%(WINDOW_WIDTH - 100)) + 50; UFO.ycenter = (rand()%50) + (WINDOW_HEIGHT - 100); UFO.ymove = (rand()%6) - 6; UFO.xmove = (rand()%13) - 6; } if (s == 2) { UFO.xcenter = (rand()%50) + 50; UFO.ycenter = (rand()%(WINDOW_HEIGHT - 100)) + 50; UFO.xmove = (rand()%6) + 1; UFO.ymove = (rand()%13) - 6; } if (s == 3) { UFO.xcenter = (rand()%50) + (WINDOW_WIDTH - 100); UFO.ycenter = (rand()%(WINDOW_HEIGHT - 100)) + 50; UFO.xmove = (rand()%6) - 6; UFO.ymove = (rand()%13) - 6; } // set UFO Bullet direction and speed SetUFOBullet(); } // end of if } // end of long else } // END OF MoveUFO ///////////////////////////////////////////////////////// // // Insert 2 rocks in approx place x,y // if t = 2 then insert 2 medium // if t = 1 then insert 2 small // ///////////////////////////////////////////////////////// void InsertRocks(int x, int y, int t) { int i, inserted; inserted = 0; // reset how many inserted to zero for (i = 0; i < MAX_ASTEROIDS; i++) { if (!Rocks[i].alive) // if rock is dead (free), insert one here { Rocks[i].alive = TRUE; Rocks[i].size = t; Rocks[i].shape = (rand()%5); Rocks[i].xcenter = x + (rand()%21) - 10; // insert close to center Rocks[i].ycenter = y + (rand()%21) - 10; // insert close to center do { Rocks[i].xmove = (rand()%13) - 6; // move -6 to +6 Rocks[i].ymove = (rand()%13) - 6; // move -6 to +6 if (game_difficulty == DIFFICULTY_EASY) { Rocks[i].xmove = (rand()%7) - 3; // move -3 to +3 Rocks[i].ymove = (rand()%7) - 3; // move -3 to +3 } } while (Rocks[i].xmove == 0 && Rocks[i].ymove == 0); inserted++; if (inserted == 2) return; } // end of if } // end of for } // END OF InsertRocks ///////////////////////////////////////////////////////// // // Insert one new bullet in array // travelling at ship firing direction // ///////////////////////////////////////////////////////// void InsertBullet() { int i; // for count loop if (bullet_countdown > 0) { bullet_countdown--; return; } for (i = 0; i < MAX_BULLETS; i++) { if (!Bullets[i].alive) // if bullet is dead (free), insert one here { Bullets[i].alive = TRUE; Bullets[i].xcenter = Ship.xcenter + Ship.xmove * 2; Bullets[i].ycenter = Ship.ycenter + Ship.ymove * 2; Bullets[i].xmove = xdir[Ship.angle] * BULLET_SPEED; Bullets[i].ymove = ydir[Ship.angle] * BULLET_SPEED; Bullets[i].duration = DURATION_FOR_SHIP_BULLET; bullet_countdown = TIME_BETWEEN_BULLETS; if (sound_ok) // Play Fire Bullet Sound { IDirectSoundBuffer_Stop(game_sound_fire1); IDirectSoundBuffer_Play(game_sound_fire1,0,0,NULL); } return; } // end of if } // end of for } // END OF InsertBullet ///////////////////////////////////////////////////////// // // Move all existing bullets once // ///////////////////////////////////////////////////////// void MoveBullets() { int i, xi, yi; float x, y; for (i = 0; i < MAX_BULLETS; i++) { if (Bullets[i].alive) { x = Bullets[i].xcenter; y = Bullets[i].ycenter; // save bullet x y x += Bullets[i].xmove; y += Bullets[i].ymove; // move bullet if (x < 25) x = WINDOW_WIDTH - 25; else if (x > (WINDOW_WIDTH - 25)) x = 25; if (y < 25) y = WINDOW_HEIGHT - 25; else if (y > (WINDOW_HEIGHT - 25)) y = 25; Bullets[i].xcenter = x; Bullets[i].ycenter = y; xi = (int)x; yi = (int)y; SelectObject(back_dc, white_pen); SelectObject(back_dc, white_brush); Ellipse(back_dc, xi - 1, yi - 1, xi + 1, yi + 1); Bullets[i].duration--; if (Bullets[i].duration == 0) Bullets[i].alive = FALSE; } // end of if } // end of for } // END OF MoveBullets ///////////////////////////////////////////////////////// // // Set UFO bullet for firing // ///////////////////////////////////////////////////////// void SetUFOBullet() { float dx, dy, m; // for difference in x, y, and magnitude int a; // for random angle during demo mode UFO.xbullet = (float)UFO.xcenter; UFO.ybullet = (float)UFO.ycenter; UFO.duration = DURATION_FOR_UFO_BULLET; // To make the UFO bullet deadly to ship position // // OPTION ONE: take the ArcTangent of the difference between the points // Convert from rads to degs with 57.29578 = 180 / PI approx // a = atan2(UFO.y - Ship.y, UFO.x - Ship.x) * 57.29578; // which gets the exact angle, then xb yb move can be calculated // // OPTION TWO: suggested by Jason Doucette on GameDev.net 6/2/2003 // implemented below (a non-Trig solution) thanks Jason! // // aim UFO bullet directly at ship dx = Ship.xcenter - UFO.xbullet; // difference in x dy = Ship.ycenter - UFO.ybullet; // difference in y m = (float)sqrt(dx*dx + dy*dy); // magnitude (distance) UFO.xbmove = (dx/m) * BULLET_SPEED; UFO.ybmove = (dy/m) * BULLET_SPEED; // during demo or easy use random UFO Bullet angle if (game_state == GAME_STATE_DEMO_RUN || game_difficulty == DIFFICULTY_EASY) { a = rand()%32; UFO.xbmove = xdir[a] * BULLET_SPEED; UFO.ybmove = ydir[a] * BULLET_SPEED; } // Play Fire UFO Bullet Sound if (game_state == GAME_STATE_GAME_RUN && sound_ok) { IDirectSoundBuffer_Play(game_sound_fire2,0,0,NULL); } } // END OF SetUFOBullet ///////////////////////////////////////////////////////// // // Move UFO bullet once // ///////////////////////////////////////////////////////// void MoveUFOBullet() { int xi, yi; float x, y; if (UFO.alive) { x = UFO.xbullet; y = UFO.ybullet; // save bullet x y x += UFO.xbmove; y += UFO.ybmove; // move bullet if (x < 25) x = WINDOW_WIDTH - 25; else if (x > (WINDOW_WIDTH - 25)) x = 25; if (y < 25) y = WINDOW_HEIGHT - 25; else if (y > (WINDOW_HEIGHT - 25)) y = 25; UFO.xbullet = x; UFO.ybullet = y; xi = (int)x; yi = (int)y; // draw the UFO bullet to back buffer SelectObject(back_dc, white_pen); SelectObject(back_dc, white_brush); Ellipse(back_dc, xi - 2, yi - 2, xi + 2, yi + 2); UFO.duration--; // check if duration over if (UFO.duration == 0) { if (sound_ok) IDirectSoundBuffer_Stop(game_sound_fire2); SetUFOBullet(); } } // end of if } // END OF MoveUFOBullet //////////////////////////////////////////////////////////////// // // Insert Particles for explosion at point x,y of type t // (if t = 1 then small, 2 = larger explosion, 3 = largest, etc) // (if t = 0 insert thrust particles, etc) // //////////////////////////////////////////////////////////////// void InsertParticles(int x, int y, int t) { int i, p, a0, a, d, inserted; float xc, yc, v; // Play Explosion or Thrust sound switch(t) { case 0: // Play Thrust Sound { if (sound_ok) { IDirectSoundBuffer_Play(game_sound_thrust,0,0,NULL); } } break; case 1: // Play Explosion Small { if (game_state == GAME_STATE_GAME_RUN && sound_ok) { IDirectSoundBuffer_Stop(game_sound_explode1); IDirectSoundBuffer_Play(game_sound_explode1,0,0,NULL); } } break; case 2: // Play Explosion Medium { if (game_state == GAME_STATE_GAME_RUN && sound_ok) { IDirectSoundBuffer_Stop(game_sound_explode2); IDirectSoundBuffer_Play(game_sound_explode2,0,0,NULL); } } break; case 3: // Play Explosion Large { if (game_state == GAME_STATE_GAME_RUN && sound_ok) { IDirectSoundBuffer_Stop(game_sound_explode3); IDirectSoundBuffer_Play(game_sound_explode3,0,0,NULL); } } break; case 5: // Play Explosion UFO { if (sound_ok) { IDirectSoundBuffer_Stop(game_sound_explode4); IDirectSoundBuffer_Play(game_sound_explode4,0,0,NULL); } } break; case 7: // Play Explosion Ship { if (sound_ok) { IDirectSoundBuffer_Play(game_sound_explode5,0,0,NULL); } } break; } // end switch xc = (float)x; yc = (float)y; p = t * 50; // get how many particles to insert if (t == 0) p = 10; // if thrust, insert 10 particles inserted = 0; // reset how many inserted to zero for (i = 0; i < MAX_PARTICLES; i++) { if (!Particles[i].alive) // particle space is free -- insert here { Particles[i].alive = TRUE; Particles[i].xcenter = xc; Particles[i].ycenter = yc; if (t == 0) // if thrust, slower particles from ship { a0 = Ship.angle + 16; // for angle opposite ship angle a = a0 + (rand()%7) - 3; // thrust opposite end of ship +/- 3 if (a > 31) a -= 32; // check if angle out of range if (a0 > 31) a0 -= 32; v = (float)(rand()%5 + 2); // random velocity 2 to 6 d = rand()%11 + 5; // random duration 5 to 15 Particles[i].xcenter += xdir[a0] * 18.0f; Particles[i].ycenter += ydir[a0] * 18.0f; Particles[i].xmove = xdir[a] * v + Ship.xmove; Particles[i].ymove = ydir[a] * v + Ship.ymove; Particles[i].duration = d; } // end of if thrust else // not thrust, faster particles for explosions { a = rand()%32; // get random angle 0 to 31 v = (float)(rand()%6 + 3); // get random velocity 3 to 8 d = (rand()%11 + 3) * t; // get random duration Particles[i].xmove = xdir[a] * v; Particles[i].ymove = ydir[a] * v; Particles[i].duration = d; } // end of else inserted++; if (inserted == p) return; } // end of if particle free } // end of for particles } // END OF InsertParticles ///////////////////////////////////////////////////////// // // Move all existing particles once // ///////////////////////////////////////////////////////// void MoveParticles() { int i, xi, yi; float x, y; COLORREF c = RGB(255,255,255); for (i = 0; i < MAX_PARTICLES; i++) { if (Particles[i].alive) { x = Particles[i].xcenter; y = Particles[i].ycenter; // save particle x y x += Particles[i].xmove; y += Particles[i].ymove; // move particle if (x < 25) x = WINDOW_WIDTH - 25; else if (x > (WINDOW_WIDTH - 25)) x = 25; if (y < 25) y = WINDOW_HEIGHT - 25; else if (y > (WINDOW_HEIGHT - 25)) y = 25; Particles[i].xcenter = x; Particles[i].ycenter = y; xi = (int)x; yi = (int)y; SetPixel(back_dc, xi, yi, c); // plot a white pixel Particles[i].duration--; // check if duration over if (Particles[i].duration == 0) Particles[i].alive = FALSE; } // end of if } // end of for } // END OF MoveParticles /////////////////////////////////////////////////////// // // Initialize DirectSound and individual sound buffers // /////////////////////////////////////////////////////// bool SoundInit() { if (DirectSoundCreate(NULL, &game_sound_main, NULL) != DS_OK) { MessageBox(game_window, "Sound could not be initialized -- Direct Sound Create Error","Sound Error",MB_OK); return FALSE; } // // Direct Sound object succeeded so set coop level // if (IDirectSound_SetCooperativeLevel(game_sound_main, game_window, DSSCL_PRIORITY) != DS_OK) { MessageBox(game_window, "Sound could not be initialized -- Cooperative Level Error","Sound Error",MB_OK); return FALSE; } // // Cooperative Level succeeded so set up // secondary buffers and load wave file sound resources // game_sound_fire1 = DSLoadSoundBuffer(game_sound_main, MAKEINTRESOURCE(SOUND_FIRE1)); game_sound_fire2 = DSLoadSoundBuffer(game_sound_main, MAKEINTRESOURCE(SOUND_FIRE2)); game_sound_explode1 = DSLoadSoundBuffer(game_sound_main, MAKEINTRESOURCE(SOUND_EXPLODE1)); game_sound_explode2 = DSLoadSoundBuffer(game_sound_main, MAKEINTRESOURCE(SOUND_EXPLODE2)); game_sound_explode3 = DSLoadSoundBuffer(game_sound_main, MAKEINTRESOURCE(SOUND_EXPLODE3)); game_sound_explode4 = DSLoadSoundBuffer(game_sound_main, MAKEINTRESOURCE(SOUND_EXPLODE4)); game_sound_explode5 = DSLoadSoundBuffer(game_sound_main, MAKEINTRESOURCE(SOUND_EXPLODE5)); game_sound_regen1 = DSLoadSoundBuffer(game_sound_main, MAKEINTRESOURCE(SOUND_REGEN1)); game_sound_regen2 = DSLoadSoundBuffer(game_sound_main, MAKEINTRESOURCE(SOUND_REGEN2)); game_sound_thrust = DSLoadSoundBuffer(game_sound_main, MAKEINTRESOURCE(SOUND_THRUST)); game_sound_ufo1 = DSLoadSoundBuffer(game_sound_main, MAKEINTRESOURCE(SOUND_UFO1)); game_sound_ufo2 = DSLoadSoundBuffer(game_sound_main, MAKEINTRESOURCE(SOUND_UFO2)); game_sound_extra = DSLoadSoundBuffer(game_sound_main, MAKEINTRESOURCE(SOUND_EXTRA)); // return TRUE since main DirectSound initialized ok return TRUE; } // END OF SoundInit ////////////////////////////////////////////////////// // // Stop all sounds and close DirectSound and buffers // ///////////////////////////////////////////////////// void SoundQuit() { // if sound was set okay, release DirectSound objects if (game_sound_main) { // FIRST RELEASE SECONDARY BUFFERS IDirectSound_Release(game_sound_extra); IDirectSound_Release(game_sound_ufo2); IDirectSound_Release(game_sound_ufo1); IDirectSound_Release(game_sound_thrust); IDirectSound_Release(game_sound_regen2); IDirectSound_Release(game_sound_regen1); IDirectSound_Release(game_sound_explode5); IDirectSound_Release(game_sound_explode4); IDirectSound_Release(game_sound_explode3); IDirectSound_Release(game_sound_explode2); IDirectSound_Release(game_sound_explode1); IDirectSound_Release(game_sound_fire2); IDirectSound_Release(game_sound_fire1); // THEN RELEASE MAIN DIRECT SOUND OBJECT IDirectSound_Release(game_sound_main); } } // END OF SoundQuit /////////////////////////////////////////// // // Set points for rock polygon // /////////////////////////////////////////// void SetRockPoints(int i) { int j, s; // for count loop, rock shape s = Rocks[i].shape; for (j = 0; j < 9; j++) { points[j].x = Rocks[i].xcenter + (xrock[s][j] * Rocks[i].size); points[j].y = Rocks[i].ycenter + (yrock[s][j] * Rocks[i].size); } } // END OF SetRockPoints ////////////////////////////////////////////// // // Set points for ship polygon at angle deg // ////////////////////////////////////////////// void SetShipPoints(int deg) { int j; // for count loop for (j = 0; j < 4; j++) { points[j].x = (int)Ship.xcenter + xship[j][deg]; points[j].y = (int)Ship.ycenter + yship[j][deg]; } } // END OF SetShipPoints ////////////////////////////////////////////// // // Check ALL potential collisions // ////////////////////////////////////////////// void CheckCollisions() { int i, j, x, y, s, xi, yi; bool rock_alive; // check for level countdown = pause time between levels = no rock collisions if (level_countdown == 0) { for (i = 0; i < MAX_ASTEROIDS; i++) { rock_alive = FALSE; if (Rocks[i].alive) // if the rock is alive { rock_alive = TRUE; // for following checks against same rock // save the rock x y and size x = Rocks[i].xcenter; y = Rocks[i].ycenter; s = Rocks[i].size; ///////////////////////////////////////////////////////// // Collision Check: Rock to Ship Bullets ///////////////////////////////////////////////////////// for (j = 0; j < MAX_BULLETS; j++) { if (Bullets[j].alive && rock_alive && game_state == GAME_STATE_GAME_RUN) // if the current bullet and same rock still alive { // save the bullet x y xi = (int)Bullets[j].xcenter; yi = (int)Bullets[j].ycenter; // check if bullet is inside rock (if bullet hit rock) if ((xi > x-12*s) && (xi < x+12*s) && (yi > y-12*s) && (yi < y+12*s)) { // ROCK HIT! InsertParticles(x,y,s); // explosion! Rocks[i].alive = FALSE; rock_alive = FALSE; // kill the rock Bullets[j].alive = FALSE; // kill the bullet if (s != 1) InsertRocks(x,y,s-1); // if not small, insert 2 rocks rocks_hit++; // check if all rocks on that level hit if (rocks_hit == 28 && game_level == 1) game_state = GAME_STATE_GAME_RESET; if (rocks_hit == 42 && game_level == 2) game_state = GAME_STATE_GAME_RESET; if (rocks_hit == 56) game_state = GAME_STATE_GAME_RESET; if (s == 1) game_score += SCORE_FOR_SMALL_ROCK; if (s == 2) game_score += SCORE_FOR_MEDIUM_ROCK; if (s == 3) game_score += SCORE_FOR_LARGE_ROCK; if (game_score >= extra_score) { ships_left++; extra_score += SCORE_FOR_EXTRA_SHIP; if (sound_ok) // Play Extra Ship Sound IDirectSoundBuffer_Play(game_sound_extra,0,0,NULL); } } // end of if bullet hit rock } // end of if bullet alive } // end of for bullet loop } // end of if rock alive ///////////////////////////////////////////////////////// // Collision Check: Rock to UFO Bullet ///////////////////////////////////////////////////////// // check if same rock still alive and UFO (bullet) alive if (rock_alive && UFO.alive) { xi = (int)UFO.xbullet; yi = (int)UFO.ybullet; // if so, then check against UFO Bullet if ((xi > x-12*s) && (xi < x+12*s) && (yi > y-12*s) && (yi < y+12*s)) { InsertParticles(x,y,s); // explosion! Rocks[i].alive = FALSE; rock_alive = FALSE; // kill the rock SetUFOBullet(); // kill the UFO bullet if (s != 1) InsertRocks(x,y,s-1); // if not small, insert 2 rocks rocks_hit++; if (rocks_hit == 28 && game_level == 1) { if (game_state == GAME_STATE_GAME_RUN) game_state = GAME_STATE_GAME_RESET; else game_state = GAME_STATE_DEMO_INIT; } if (rocks_hit == 42 && game_level == 2) { if (game_state == GAME_STATE_GAME_RUN) game_state = GAME_STATE_GAME_RESET; else game_state = GAME_STATE_DEMO_INIT; } if (rocks_hit == 56) { if (game_state == GAME_STATE_GAME_RUN) game_state = GAME_STATE_GAME_RESET; else game_state = GAME_STATE_DEMO_INIT; } } // end of UFO Bullet hit rock } // end of if UFO Bullet alive //////////////////////////////////////////////////////// // Collision Check: Rock to Ship //////////////////////////////////////////////////////// // check if same rock still alive and ship fully bright if (rock_alive && Ship.regen == 0 && game_state == GAME_STATE_GAME_RUN) { // if so, then check against Ship xi = (int)Ship.xcenter; yi = (int)Ship.ycenter; // check the four corners of the ship (bounding box) against the same for rock if (((xi-12 > x-12*s) && (xi-12 < x+12*s) && (yi-12 > y-12*s) && (yi-12 < y+12*s)) || ((xi+12 > x-12*s) && (xi+12 < x+12*s) && (yi-12 > y-12*s) && (yi-12 < y+12*s)) || ((xi-12 > x-12*s) && (xi-12 < x+12*s) && (yi+12 > y-12*s) && (yi+12 < y+12*s)) || ((xi+12 > x-12*s) && (xi+12 < x+12*s) && (yi+12 > y-12*s) && (yi+12 < y+12*s))) { // ship did hit rock! InsertParticles(xi,yi,7); // ship explosion! Rocks[i].alive = FALSE; rock_alive = FALSE; // kill the rock if (s != 1) InsertRocks(x,y,s-1); // if not small, insert 2 rocks rocks_hit++; // increment and check if all rocks on that level hit if (rocks_hit == 28 && game_level == 1) game_state = GAME_STATE_GAME_RESET; if (rocks_hit == 42 && game_level == 2) game_state = GAME_STATE_GAME_RESET; if (rocks_hit == 56) game_state = GAME_STATE_GAME_RESET; if (s == 1) game_score += SCORE_FOR_SMALL_ROCK; if (s == 2) game_score += SCORE_FOR_MEDIUM_ROCK; if (s == 3) game_score += SCORE_FOR_LARGE_ROCK; ships_left--; // decrement the ships left and test for none left if (ships_left == 0) game_state = GAME_STATE_DEMO_RUN; else SetShip(); // reset the ship and regeneration time } // end of ship hit rock } // end of if rock alive and ship fully bright } // end of for rock loop } // end of if level countdown //////////////////////////////////////////////////// // Collision Check: UFO to Ship Bullets //////////////////////////////////////////////////// x = UFO.xcenter; y = UFO.ycenter; s = UFO.size; for (j = 0; j < MAX_BULLETS; j++) { // check if UFO still alive and current bullet is alive if (UFO.alive && Bullets[j].alive && game_state == GAME_STATE_GAME_RUN) { // if so, then check UFO against bullet xi = (int)Bullets[j].xcenter; yi = (int)Bullets[j].ycenter; if ((xi > x-10*s) && (xi < x+10*s) && (yi > y-9*s) && (yi < y+4*s)) { // bullet did hit UFO! InsertParticles(x,y,5); // UFO explosion! UFO.alive = FALSE; // kill the UFO if (s == 1) { if (sound_ok) IDirectSoundBuffer_Stop(game_sound_ufo1); game_score += SCORE_FOR_SMALL_UFO; } if (s == 2) { if (sound_ok) IDirectSoundBuffer_Stop(game_sound_ufo2); game_score += SCORE_FOR_LARGE_UFO; } Bullets[j].alive = FALSE; // kill the bullet if (game_score >= extra_score) { ships_left++; extra_score += SCORE_FOR_EXTRA_SHIP; if (sound_ok) // Play Extra Ship Sound IDirectSoundBuffer_Play(game_sound_extra,0,0,NULL); } } // end of UFO hit } // end of if bullet hit UFO } // end of for bullets //////////////////////////////////////////////////// // Collision Check: UFO to Ship //////////////////////////////////////////////////// // check if UFO still alive and ship can be destroyed if (UFO.alive && Ship.regen == 0 && game_state == GAME_STATE_GAME_RUN) { // if so, then check ship against UFO xi = (int)Ship.xcenter; yi = (int)Ship.ycenter; if ((xi-12 > x-10*s) && (xi-12 < x+10*s) && (yi-12 > y-9*s) && (yi-12 < y+4*s) || ((xi+12 > x-10*s) && (xi+12 < x+10*s) && (yi-12 > y-9*s) && (yi-12 < y+4*s)) || ((xi-12 > x-10*s) && (xi-12 < x+10*s) && (yi+12 > y-9*s) && (yi+12 < y+4*s)) || ((xi+12 > x-10*s) && (xi+12 < x+10*s) && (yi+12 > y-9*s) && (yi+12 < y+4*s))) { // ship did hit UFO! InsertParticles(x,y,7); // ship explosion! UFO.alive = FALSE; // kill the UFO if (s == 1) { if (sound_ok) IDirectSoundBuffer_Stop(game_sound_ufo1); game_score += SCORE_FOR_SMALL_UFO; } if (s == 2) { if (sound_ok) IDirectSoundBuffer_Stop(game_sound_ufo2); game_score += SCORE_FOR_LARGE_UFO; } if (game_score >= extra_score) { ships_left++; extra_score += SCORE_FOR_EXTRA_SHIP; if (sound_ok) // Play Extra Ship Sound IDirectSoundBuffer_Play(game_sound_extra,0,0,NULL); } ships_left--; // decrement the ships left and test for none left if (ships_left == 0) game_state = GAME_STATE_DEMO_RUN; else SetShip(); // reset the ship and regeneration time } // end of ship hit UFO } // end of if ship hit UFO ////////////////////////////////////////////////////// // UFO Bullet to Ship ////////////////////////////////////////////////////// // check if UFO still alive and ship can be destroyed if (UFO.alive && Ship.regen == 0 && game_state == GAME_STATE_GAME_RUN) { // if so, then check ship against UFO Bullet x = (int)UFO.xbullet; y = (int)UFO.ybullet; xi = (int)Ship.xcenter; yi = (int)Ship.ycenter; if ((x > xi-13) && (x < xi+13) && (y > yi-13) && (y < yi+13)) { // ship did hit UFO Bullet! InsertParticles(x,y,7); // ship explosion! SetUFOBullet(); // kill (reset) the UFO Bullet ships_left--; // decrement the ships left and test for none left if (ships_left == 0) game_state = GAME_STATE_DEMO_RUN; else SetShip(); // reset the ship and regeneration time } // end of ship hit UFO Bullet } // end of if ship hit UFO Bullet } // END OF CheckCollisions ///////////////////////////////////////////////////////////////////// // // Reset (initialize/clear) all rocks, bullets, particles, and UFO // //////////////////////////////////////////////////////////////////// void ResetAll() { int i; for (i = 0; i < MAX_ASTEROIDS; i++) Rocks[i].alive = FALSE; for (i = 0; i < MAX_BULLETS; i++) Bullets[i].alive = FALSE; for (i = 0; i < MAX_PARTICLES; i++) Particles[i].alive = FALSE; UFO.alive = FALSE; if (sound_ok) { IDirectSoundBuffer_Stop(game_sound_ufo1); IDirectSoundBuffer_Stop(game_sound_ufo2); } } bool JoyInit() { // clear joystick status joy_left = 0; joy_right = 0; joy_up = 0; joy_down = 0; joy_but1 = 0; joy_but2 = 0; joy_but3 = 0; joy_but4 = 0; // make sure joystick driver is present if ((joy_num = joyGetNumDevs()) == 0) return FALSE; // make sure the joystick is attached if (joyGetPos(JOYSTICKID1, &joy_info) != JOYERR_UNPLUGGED) joy_ID = JOYSTICKID1; else return FALSE; // calculate the trip values joyGetDevCaps(joy_ID, &joy_caps, sizeof(JOYCAPS)); joy_xcenter = ((DWORD)joy_caps.wXmin + joy_caps.wXmax) / 2; joy_ycenter = ((DWORD)joy_caps.wYmin + joy_caps.wYmax) / 2; joy_trip.left = (joy_caps.wXmin + (WORD)joy_xcenter) / 2; joy_trip.right = (joy_caps.wXmax + (WORD)joy_xcenter) / 2; joy_trip.top = (joy_caps.wYmin + (WORD)joy_ycenter) / 2; joy_trip.bottom = (joy_caps.wYmax + (WORD)joy_ycenter) / 2; // capture the joystick joySetCapture(game_window, joy_ID, NULL, TRUE); return TRUE; } void JoyQuit() { // release joystick if (joy_ok) joyReleaseCapture(joy_ID); } void JoyStatus() { if (joy_ok && joyGetPos(joy_ID, &joy_info) == JOYERR_NOERROR) { // if we have no errors check the joystick position // check horizontal movement joy_left = 0; joy_right = 0; if (joy_info.wXpos < (WORD)joy_trip.left) joy_left = 1; else if (joy_info.wXpos > (WORD)joy_trip.right) joy_right = 1; // check vertical movement joy_up = 0; joy_down = 0; if (joy_info.wYpos < (WORD)joy_trip.top) joy_up = 1; else if (joy_info.wYpos > (WORD)joy_trip.bottom) joy_down = 1; // check four buttons joy_but1 = 0; joy_but2 = 0; joy_but3 = 0; joy_but4 = 0; if (joy_info.wButtons & JOY_BUTTON1) joy_but1 = 1; if (joy_info.wButtons & JOY_BUTTON2) joy_but2 = 1; if (joy_info.wButtons & JOY_BUTTON3) joy_but3 = 1; if (joy_info.wButtons & JOY_BUTTON4) joy_but4 = 1; } // end of if joy_ok AND NOERROR } // END GAME CODE //////////////////////////////////////////