// PhilVaz Asteroids Demo // Moving Asteroids around the screen // Full Screen GDI demo // Apr 25, 2003 // May 26, 2003 -- BACKBUFFERING ADDED // INCLUDES /////////////////////////////////////////////// #define WIN32_LEAN_AND_MEAN #include // include all the windows headers #include // include useful macros #include // for rand functions #include #include // 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) // 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}; DEVMODE game_screen; // global for full screen mode // global pen and brush HPEN red_pen = CreatePen(PS_SOLID, 1, RGB(255,0,0)); HPEN green_pen = CreatePen(PS_SOLID, 1, RGB(0,255,0)); HPEN blue_pen = CreatePen(PS_SOLID, 1, RGB(0,0,255)); HPEN black_pen = CreatePen(PS_SOLID, 1, RGB(0,0,0)); HBRUSH black_brush = CreateSolidBrush(RGB(0,0,0)); // global asteroid definition POINT points[9]; // for temp erase/display of asteroid polygon points // asteroid shape relative to center point (24 x 24 square total) int xshape[9] = { -10, -11, -10, -8, 0, 9, 12, 8, 1}; int yshape[9] = { -11, -3, 2, 7, 11, 7, -1, -9, -10}; typedef struct { 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 size; // 1=small, 2=medium, 3=large } ASTEROID; ASTEROID Rocks[50]; // up to 50 rock asteroids // FUNCTIONS //////////////////////////////////////////////////////////// void GameInit(); void GameMain(); void GameQuit(); void SetPoints(int); // set the points for polygon erase/draw // 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 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 // first fill in the window class structure 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(NULL, IDI_APPLICATION); winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION); winclass.hCursor = LoadCursor(NULL, IDC_ARROW); winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); winclass.lpszMenuName = NULL; winclass.lpszClassName = WINDOW_CLASS_NAME; // save the game instance handle game_instance = hinstance; // register the window class if (!RegisterClassEx(&winclass)) return(0); // create the window if (!(hwnd = CreateWindowEx(NULL, // extended style WINDOW_CLASS_NAME, // class "Asteroid Demo", // 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 GameMain(); // game main processing function called here // 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() { int i; // for count loop 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); // set initial position, size, and speed of rocks for (i = 0; i < 30; i++) { Rocks[i].xcenter = (rand()%400) + 150; // set random x center Rocks[i].ycenter = (rand()%300) + 150; // set random y center Rocks[i].size = (rand()%3) + 1; // set random size 1=small, 2=med, 3=large do { Rocks[i].xmove = (rand()%6) - 3; // x speed from -3 to +3 Rocks[i].ymove = (rand()%6) - 3; // y speed from -3 to +3 } while(Rocks[i].xmove == 0 && Rocks[i].ymove == 0); // in case no movement } // end of for } // END OF GameInit /////////////////////////////////////////////////////////// // // GAME MAIN LOOP AND PROCESSING // /////////////////////////////////////////////////////////// void GameMain() { int i; // for count loop int x,y; // temp storage for x,y point // erase the back buffer FillRect(back_dc, &back_rect, black_brush); // draw the rock asteroids to back buffer for (i = 0; i < 30; i++) { // 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)) x = WINDOW_WIDTH - x; // check if out of range on y axis, if so set wrap around y if (y < 50 || y > (WINDOW_HEIGHT - 50)) y = WINDOW_HEIGHT - y; // save new x and y point Rocks[i].xcenter = x; Rocks[i].ycenter = y; // after move and/or wrap redraw 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 SetPoints(i); // draw the rock to back buffer Polygon(back_dc, points, 9); } // end of for loop // copy back buffer to front buffer BitBlt(game_dc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, back_dc, 0, 0, SRCCOPY); } // END OF GameMain /////////////////////////////////////////////////////////// // // GAME QUIT AND CLEAN UP // /////////////////////////////////////////////////////////// void GameQuit() { // delete the pens and brushes DeleteObject(red_pen); DeleteObject(green_pen); DeleteObject(blue_pen); DeleteObject(black_pen); DeleteObject(black_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 // // set the points for draw/erase polygon i of size s // void SetPoints(int i) { int j; // for count loop for (j = 0; j < 9; j++) { points[j].x = Rocks[i].xcenter + (xshape[j] * Rocks[i].size); points[j].y = Rocks[i].ycenter + (yshape[j] * Rocks[i].size); } } // END GAME CODE //////////////////////////////////////////