www.pudn.com > dx9_2d_demo_game.zip > dx9_2d_demo_game.cpp
//----------------------------------------------------------------------------- // Name: dx9_2d_demo_game.cpp // Author: Kevin Harris (kevin@codesampler.com) // Last Modified: 10/04/04 // Description: 2D Sample game written in DirectX 9.0 // Controls: Use the arrow keys to move and the space bar to shoot! //----------------------------------------------------------------------------- #define STRICT #define WIN32_LEAN_AND_MEAN #define INITGUID #define DIRECTINPUT_VERSION 0x0800 #include#include #include #include #include #include "resource.h" #include "sprite.h" #include using namespace std; //----------------------------------------------------------------------------- // SYMBOLIC CONSTANTS //----------------------------------------------------------------------------- const int SCREEN_WIDTH = 800; const int SCREEN_HEIGHT = 600; const int SCREEN_BPP = 16; const int TOTAL_STARS = 100; const int TOTAL_PARTICLES = 250; const int SHIP_SPEED = 5; //----------------------------------------------------------------------------- // MACROS //----------------------------------------------------------------------------- #define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } #define KEYDOWN(name,key) (name[key] & 0x80) //----------------------------------------------------------------------------- // GLOBALS //----------------------------------------------------------------------------- HWND g_hWnd = NULL; LPDIRECT3D9 g_pD3D = NULL; LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; LPDIRECTINPUT8 g_lpdi = NULL; LPDIRECTINPUTDEVICE8 g_pKeyboard = NULL; RECT g_rcWindow; RECT g_rcViewport; RECT g_rcScreen; BOOL g_bWindowed = true; BOOL g_bActive = false; DWORD g_dwLastFireTick = 0; int g_nShipsLeft = 3; int g_nScore = 0; int g_nPowerLevel = 20; int g_nCurrentLevel = 0; double g_dElpasedTime; double g_dCurTime; double g_dLastTime; double g_dAnimationTimer = 0.0; struct STAR { int x; // Star posit x int y; // Star posit y int nVelocity; // Star velocity COLORREF color; // Star color }; STAR g_stars[TOTAL_STARS]; // Star field array struct PARTICLE { int x; // Particle posit x int y; // Particle posit y int nVelocity; // Particle velocity bool bVisible; // Is particle visible or active COLORREF color; // Particle color }; PARTICLE g_exhaust[TOTAL_PARTICLES]; // Particle array for engine exhaust // Create a linked list with STL to hold and manage CSprite objects typedef list
SPRITELIST; SPRITELIST g_SpriteList; SPRITELIST::iterator g_sprite_i; SPRITELIST::iterator g_sprite_j; SPRITELIST::iterator g_sprite_k; //----------------------------------------------------------------------------- // PROTOTYPES //----------------------------------------------------------------------------- LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); HRESULT WinInit(HINSTANCE hInst, int nCmdShow, HWND* phWnd, HACCEL* phAccel); HRESULT GameStart(HWND hWnd); HRESULT GameMain(HWND hWnd); void GameOver(void); HRESULT InitDirect3D(HWND hWnd, BOOL bWindowed); void FreeDirect3D(void); HRESULT InitDirectInput(HWND hWnd); void FreeDirectInput(void); void InitializeSprites(void); void InitializeStars(void); void InitializeExhaust(void); void MoveShip(void); void MoveSprites(void); void MoveStars(void); void MoveExhaust(void); void CheckCollisions(void); bool SpriteCollisionTest(CSprite& sprite1, CSprite& sprite2); bool CollisionTest(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2); void ComputeScore(void); HRESULT DisplayFrame(void); HRESULT DrawStars(void); HRESULT DrawExhaust(void); HRESULT DrawPowerBar(void); int RandomInt(int nLow, int nHigh); //----------------------------------------------------------------------------- // Name: WinMain() // Desc: Entry point to the program. Initializes everything and calls. //----------------------------------------------------------------------------- int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int nCmdShow ) { MSG msg; HWND hWnd; HACCEL hAccel; memset(&msg,0,sizeof(msg)); WinInit( hInst, nCmdShow, &hWnd, &hAccel ); GameStart( hWnd ); while( TRUE ) { // Look for messages, if none are found then // update the state and display it if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) { if( 0 == GetMessage(&msg, NULL, 0, 0 ) ) { // WM_QUIT was posted, so exit return (int)msg.wParam; } // Translate and dispatch the message if( 0 == TranslateAccelerator( hWnd, hAccel, &msg ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } } else { if( g_bActive ) { // Move the sprites, blt them to the back buffer, then // flip or blt the back buffer to the primary buffer g_dCurTime = timeGetTime(); g_dElpasedTime = ((g_dCurTime - g_dLastTime) * 0.001); g_dLastTime = g_dCurTime; if( FAILED( GameMain( hWnd ) ) ) { //SAFE_DELETE( g_pDisplay ); MessageBox( hWnd, TEXT("GameMain() failed. ") TEXT("The game will now exit. "), TEXT("PrototypeX"), MB_ICONERROR | MB_OK ); return FALSE; } } else { // Go to sleep if we have nothing else to do WaitMessage(); // Ignore time spent inactive //g_dwLastTick = timeGetTime(); } } } } //----------------------------------------------------------------------------- // Name: WinInit() // Desc: Init our game's window //----------------------------------------------------------------------------- HRESULT WinInit( HINSTANCE hInst, int nCmdShow, HWND *phWnd, HACCEL *phAccel ) { WNDCLASSEX wc; HWND hWnd; HACCEL hAccel; // Register the window class wc.cbSize = sizeof(wc); wc.lpszClassName = TEXT("MY_WINDOWS_CLASS"); wc.lpfnWndProc = MainWndProc; wc.style = CS_VREDRAW | CS_HREDRAW; wc.hInstance = hInst; wc.hIcon = LoadIcon( hInst, MAKEINTRESOURCE(IDI_MAIN_ICON) ); wc.hIconSm = LoadIcon( hInst, MAKEINTRESOURCE(IDI_MAIN_ICON) ); wc.hCursor = LoadCursor( NULL, IDC_ARROW ); wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU); wc.cbClsExtra = 0; wc.cbWndExtra = 0; if( RegisterClassEx( &wc ) == 0 ) return E_FAIL; // Load keyboard accelerators hAccel = LoadAccelerators( hInst, MAKEINTRESOURCE(IDR_MAIN_ACCEL) ); // Calculate the proper size for the window given a client of 640x480 DWORD dwFrameWidth = GetSystemMetrics( SM_CXSIZEFRAME ); DWORD dwFrameHeight = GetSystemMetrics( SM_CYSIZEFRAME ); DWORD dwMenuHeight = GetSystemMetrics( SM_CYMENU ); DWORD dwCaptionHeight = GetSystemMetrics( SM_CYCAPTION ); DWORD dwWindowWidth = SCREEN_WIDTH + dwFrameWidth * 2; DWORD dwWindowHeight = SCREEN_HEIGHT + dwFrameHeight * 2 + dwMenuHeight + dwCaptionHeight; // Create and show the main window DWORD dwStyle = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX; hWnd = CreateWindowEx( 0, TEXT("MY_WINDOWS_CLASS"), TEXT("Direct3D (DX8) - 2D Demo Game"), dwStyle, CW_USEDEFAULT, CW_USEDEFAULT, dwWindowWidth, dwWindowHeight, NULL, NULL, hInst, NULL ); if( hWnd == NULL ) return E_FAIL; ShowWindow( hWnd, nCmdShow ); UpdateWindow( hWnd ); // Save the window size/pos for switching modes GetWindowRect( hWnd, &g_rcWindow ); *phWnd = hWnd; *phAccel = hAccel; return S_OK; } //----------------------------------------------------------------------------- // Name: MainWndProc() // Desc: The main window procedure //----------------------------------------------------------------------------- LRESULT CALLBACK MainWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { switch( msg ) { case WM_COMMAND: switch( LOWORD(wParam) ) { case IDM_TOGGLEFULLSCREEN: /* // Toggle the fullscreen/window mode if( g_bWindowed ) GetWindowRect( hWnd, &g_rcWindow ); g_bWindowed = !g_bWindowed; SAFE_RELEASE( g_pd3dDevice ); //FreeDirect3D(); if( FAILED( InitDirect3D( hWnd, g_bWindowed ) ) ) { SAFE_RELEASE( g_pd3dDevice ); MessageBox( hWnd, TEXT("InitDirect3D() failed. ") TEXT("The game will now exit. "), TEXT("PrototypeX"), MB_ICONERROR | MB_OK ); PostMessage( hWnd, WM_CLOSE, 0, 0 ); } //*/ return 0L; case IDM_EXIT: // Received key/menu command to exit app PostMessage( hWnd, WM_CLOSE, 0, 0 ); return 0L; } break; case WM_GETMINMAXINFO: { // Don't allow resizing in windowed mode. // Fix the size of the window to 800x600 (client size) MINMAXINFO* pMinMax = (MINMAXINFO*) lParam; DWORD dwFrameWidth = GetSystemMetrics( SM_CXSIZEFRAME ); DWORD dwFrameHeight = GetSystemMetrics( SM_CYSIZEFRAME ); DWORD dwMenuHeight = GetSystemMetrics( SM_CYMENU ); DWORD dwCaptionHeight = GetSystemMetrics( SM_CYCAPTION ); pMinMax->ptMinTrackSize.x = SCREEN_WIDTH + dwFrameWidth * 2; pMinMax->ptMinTrackSize.y = SCREEN_HEIGHT + dwFrameHeight * 2 + dwMenuHeight + dwCaptionHeight; pMinMax->ptMaxTrackSize.x = pMinMax->ptMinTrackSize.x; pMinMax->ptMaxTrackSize.y = pMinMax->ptMinTrackSize.y; } return 0L; case WM_SIZE: // Check to see if we are losing our window... if( SIZE_MAXHIDE == wParam || SIZE_MINIMIZED == wParam ) g_bActive = FALSE; else g_bActive = TRUE; break; case WM_SETCURSOR: // Hide the cursor if in full screen if( !g_bWindowed ) { SetCursor( NULL ); return TRUE; } break; case WM_EXITMENULOOP: // Ignore time spent in menu //g_dwLastTick = timeGetTime(); break; case WM_EXITSIZEMOVE: // Ignore time spent resizing //g_dwLastTick = timeGetTime(); break; case WM_SYSCOMMAND: // Prevent moving/sizing and power loss in full screen mode switch( wParam ) { case SC_MOVE: case SC_SIZE: case SC_MAXIMIZE: case SC_MONITORPOWER: if( !g_bWindowed ) return TRUE; } break; case WM_ACTIVATE: if( WA_INACTIVE != wParam && g_pKeyboard ) { // Make sure the device is acquired, if we are gaining focus. g_pKeyboard->Acquire(); } break; case WM_DESTROY: // Cleanup and close the app GameOver(); PostQuitMessage( 0 ); return 0L; } return DefWindowProc(hWnd, msg, wParam, lParam); } //----------------------------------------------------------------------------- // Name: GameStart() // Desc: Initialize all DirectX objects to be used //----------------------------------------------------------------------------- HRESULT GameStart( HWND hWnd ) { HRESULT hr; // Initialize all the surfaces we need if( FAILED( hr = InitDirect3D( hWnd, g_bWindowed ) ) ) return hr; // Initialize all DirectInput if( FAILED( hr = InitDirectInput( hWnd ) ) ) return hr; InitializeSprites(); InitializeStars(); InitializeExhaust(); g_dwLastFireTick = timeGetTime(); return S_OK; } //----------------------------------------------------------------------------- // Name: GameMain() // Desc: Move the sprites, blit them to the back buffer, then // flip or blit the back buffer to the primary buffer //----------------------------------------------------------------------------- HRESULT GameMain( HWND hWnd ) { g_dAnimationTimer += g_dElpasedTime; if( g_dAnimationTimer >= 0.016 ) g_dAnimationTimer = 0.0; // Target of 1/60th of a second (60 FPS) reached. Render a new frame. else return S_OK; // It's too early. Return now and render nothing. // Collect user input and move the player's ship MoveShip(); // Move the game sprites MoveSprites(); // Check to see who's hitting who and react to it CheckCollisions(); // Assign the proper number sprites for the score ComputeScore(); // Display the sprites on the screen DisplayFrame(); return S_OK; } //----------------------------------------------------------------------------- // Name: GameOver() // Desc: Release all the DirectDraw objects //----------------------------------------------------------------------------- VOID GameOver() { FreeDirect3D(); FreeDirectInput(); for( g_sprite_i = g_SpriteList.begin(); g_sprite_i != g_SpriteList.end(); ++g_sprite_i ) g_sprite_i->releaseMemory(); // Cleanup the STL generated linked list g_SpriteList.erase( g_SpriteList.begin(), g_SpriteList.end() ); } //----------------------------------------------------------------------------- // Name: InitDirect3D() // Desc: //----------------------------------------------------------------------------- HRESULT InitDirect3D( HWND hWnd, BOOL bWindowed ) { g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ); D3DCAPS9 d3dCaps; g_pD3D->GetDeviceCaps( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps ); D3DDISPLAYMODE d3ddm; g_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ); D3DPRESENT_PARAMETERS d3dpp; ZeroMemory( &d3dpp, sizeof(d3dpp) ); if( bWindowed == TRUE ) { d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = d3ddm.Format; } else { d3dpp.Windowed = FALSE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferWidth = SCREEN_WIDTH; d3dpp.BackBufferHeight = SCREEN_HEIGHT; d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; } d3dpp.EnableAutoDepthStencil = TRUE; d3dpp.AutoDepthStencilFormat = D3DFMT_D16; d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // Do NOT sync to vertical retrace //d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; // Sync to vertical retrace d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice ); D3DXMATRIX matProj; D3DXMatrixPerspectiveFovLH( &matProj, D3DXToRadian( 45.0f ), SCREEN_WIDTH / SCREEN_HEIGHT, 0.1f, 100.0f ); g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj ); g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE); g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); return S_OK; } //----------------------------------------------------------------------------- // Name: FreeDirect3D() // Desc: Free all DirectDraw objects //----------------------------------------------------------------------------- void FreeDirect3D( void ) { SAFE_RELEASE( g_pd3dDevice ); SAFE_RELEASE( g_pD3D ); } //----------------------------------------------------------------------------- // Name: InitDirectInput() // Desc: Creates a keyboard device using DirectInput //----------------------------------------------------------------------------- HRESULT InitDirectInput( HWND hWnd ) { HRESULT hr; FreeDirectInput(); // Create a DInput object if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&g_lpdi, NULL ) ) ) return hr; // Obtain an interface to the system keyboard device. if( FAILED( hr = g_lpdi->CreateDevice( GUID_SysKeyboard, &g_pKeyboard, NULL ) ) ) return hr; // Set the data format to "keyboard format" - a predefined data format // // A data format specifies which controls on a device we // are interested in, and how they should be reported. // // This tells DirectInput that we will be passing an array // of 256 bytes to IDirectInputDevice::GetDeviceState. if( FAILED( hr = g_pKeyboard->SetDataFormat( &c_dfDIKeyboard ) ) ) return hr; // Set the cooperative level to let DirectInput know how // this device should interact with the system and with other // DirectInput applications. hr = g_pKeyboard->SetCooperativeLevel( hWnd, DISCL_NOWINKEY | DISCL_NONEXCLUSIVE | DISCL_FOREGROUND ); if( hr == DIERR_UNSUPPORTED ) { FreeDirectInput(); MessageBox( hWnd, TEXT("SetCooperativeLevel() returned DIERR_UNSUPPORTED.\n") TEXT("For security reasons, background exclusive keyboard\n") TEXT("access is not allowed."), TEXT("PrototypeX"), MB_OK ); return S_OK; } if( FAILED(hr) ) return hr; // Acquire the newly created device g_pKeyboard->Acquire(); return S_OK; } //----------------------------------------------------------------------------- // Name: FreeDirectInput() // Desc: Initialize the DirectInput variables. //----------------------------------------------------------------------------- void FreeDirectInput( void ) { // Unacquire the device one last time just in case // the app tried to exit while the device is still acquired. if( g_pKeyboard ) g_pKeyboard->Unacquire(); // Release any DirectInput objects. SAFE_RELEASE( g_pKeyboard ); SAFE_RELEASE( g_lpdi ); } //----------------------------------------------------------------------------- // Name: InitializeSprites() // Desc: Creates each sprite, sets their properties, and then loads them // into a linked list for future use. //----------------------------------------------------------------------------- void InitializeSprites(void) { CSprite sprite; int i = 0; sprite.zeroSpriteValues(); sprite.m_nID = 555; strcpy( sprite.m_chType, "ship" ); strcpy( sprite.m_chSpriteTextureName, "fighter.bmp" ); sprite.m_nWidth = 1152; sprite.m_nHeight = 216; sprite.m_fPosition_x = 0; sprite.m_fPosition_y = 250; sprite.m_bAutoAnimate = false; // We'll control the animation ourself through incFrame() and decFrame() sprite.m_nFrameRateModifier = -2; sprite.m_nCurrentFrame = 14; // Point forward until further notice! sprite.m_nFrameWidth = 144; sprite.m_nFrameHeight = 108; sprite.m_nFramesAcross = 8; sprite.m_nWidthScaling = -10; // Shrink the sprite's width sprite.m_nHeightScaling = -10; // Shrink the sprite's height sprite.m_bModifyCollision = true; sprite.m_nCollisionRight = -5; // Reduce sprite 's collision area on the right side sprite.m_nCollisionLeft = -15; // Reduce sprite 's collision area on the left side sprite.m_nCollisionBottom = -50; // Reduce sprite 's collision area on the bottom sprite.m_nCollisionTop = -20; // Reduce sprite 's collision area on the top sprite.loadAnimationString( 0, "7 7 6 6 5 5 4 4 3 3 2 2 1 1 0 0 9 9 10 10 11 11 12 12 13 13 14 14 15 15", CSprite::MAINTAIN_LAST_FRAME ); g_SpriteList.push_back(sprite); // Create an animated sprite for engine exhaust sprite.zeroSpriteValues(); strcpy( sprite.m_chType, "animeflame" ); strcpy( sprite.m_chSpriteTextureName, "misc.bmp" ); sprite.m_nWidth = 200; sprite.m_nHeight = 200; sprite.m_bActive = false; sprite.m_fPosition_x = 0; sprite.m_fPosition_y = 0; sprite.m_nFrameRateModifier = -10; sprite.m_nFrameOffset_x = 0; sprite.m_nFrameOffset_y = 74; sprite.m_nFramesAcross = 3; sprite.m_nFrameWidth = 46; sprite.m_nFrameHeight = 13; sprite.loadAnimation( 0, 0, 5, CSprite::MAINTAIN_LAST_FRAME ); g_SpriteList.push_back(sprite); // Create a sprite for keeping track of the number // of ships the player has left sprite.zeroSpriteValues(); strcpy( sprite.m_chType, "shipcount" ); strcpy( sprite.m_chSpriteTextureName, "misc.bmp" ); sprite.m_nWidth = 200; sprite.m_nHeight = 200; sprite.m_bSingleFrame = true; sprite.m_fPosition_x = 375; sprite.m_fPosition_y = 5; sprite.m_nFrameOffset_x = 0; sprite.m_nFrameOffset_y = 17; sprite.m_nFrameWidth = 67; sprite.m_nFrameHeight = 38; g_SpriteList.push_back(sprite); // Create a single number sprite for keeping track of // the number of ships the player has left sprite.zeroSpriteValues(); strcpy( sprite.m_chType, "shipnumber" ); strcpy( sprite.m_chSpriteTextureName, "numbers.bmp" ); sprite.m_nWidth = 185; sprite.m_nHeight = 27; sprite.m_fPosition_x = 428; sprite.m_fPosition_y = 28; sprite.m_bAutoAnimate = false; sprite.m_nFrameWidth = 17; sprite.m_nFrameHeight = 17; sprite.m_nFramesAcross = 10; sprite.m_nFrameOffset_x = 9; sprite.m_nFrameOffset_y = 5; sprite.loadAnimation( 0, 0, 9, CSprite::LOOP_ANIMATION ); g_SpriteList.push_back(sprite); // Create power bar sprite sprite.zeroSpriteValues(); strcpy( sprite.m_chType, "powerbar" ); strcpy( sprite.m_chSpriteTextureName, "misc.bmp" ); sprite.m_nWidth = 200; sprite.m_nHeight = 200; sprite.m_bActive = false; sprite.m_bSingleFrame = true; sprite.m_nFrameOffset_x = 0; sprite.m_nFrameOffset_y = 56; sprite.m_nFrameWidth = 105; sprite.m_nFrameHeight = 17; g_SpriteList.push_back(sprite); // Create a red hashmark for the power level display sprite.zeroSpriteValues(); strcpy( sprite.m_chType, "redmark" ); strcpy( sprite.m_chSpriteTextureName, "misc.bmp" ); sprite.m_nWidth = 200; sprite.m_nHeight = 200; sprite.m_bActive = false; sprite.m_bSingleFrame = true; sprite.m_nFrameOffset_x = 51; sprite.m_nFrameOffset_y = 0; sprite.m_nFrameWidth = 4; sprite.m_nFrameHeight = 13; g_SpriteList.push_back(sprite); // Create a yellow hashmark for the power level display sprite.zeroSpriteValues(); strcpy( sprite.m_chType, "yellowmark" ); strcpy( sprite.m_chSpriteTextureName, "misc.bmp" ); sprite.m_nWidth = 200; sprite.m_nHeight = 200; sprite.m_bActive = false; sprite.m_bSingleFrame = true; sprite.m_nFrameOffset_x = 56; sprite.m_nFrameOffset_y = 0; sprite.m_nFrameWidth = 4; sprite.m_nFrameHeight = 13; g_SpriteList.push_back(sprite); // Create a green hashmark for the power level display sprite.zeroSpriteValues(); strcpy( sprite.m_chType, "greenmark" ); strcpy( sprite.m_chSpriteTextureName, "misc.bmp" ); sprite.m_nWidth = 200; sprite.m_nHeight = 200; sprite.m_bActive = false; sprite.m_bSingleFrame = true; sprite.m_nFrameOffset_x = 61; sprite.m_nFrameOffset_y = 0; sprite.m_nFrameWidth = 4; sprite.m_nFrameHeight = 13; g_SpriteList.push_back(sprite); // Create 4 numbers for keeping score for( i = 0; i < 4; i++ ) { sprite.zeroSpriteValues(); strcpy( sprite.m_chType, "numbers" ); strcpy( sprite.m_chSpriteTextureName, "numbers.bmp" ); sprite.m_nWidth = 185; sprite.m_nHeight = 27; sprite.m_nState = i; sprite.m_fPosition_x = (float)300 + (i * 17); sprite.m_fPosition_y = 5; sprite.m_bAutoAnimate = false; sprite.m_nFrameOffset_x = 9; sprite.m_nFrameOffset_y = 5; sprite.m_nFramesAcross = 10; sprite.m_nFrameWidth = 17; sprite.m_nFrameHeight = 17; sprite.loadAnimationString( 0, "0 1 2 3 4 5 6 7 8 9", CSprite::LOOP_ANIMATION ); g_SpriteList.push_back(sprite); } // Create 20 mines to shoot at! for( i = 0; i < 20; i++ ) { sprite.zeroSpriteValues(); strcpy( sprite.m_chType, "mine" ); strcpy( sprite.m_chSpriteTextureName, "misc.bmp" ); sprite.m_nWidth = 200; sprite.m_nHeight = 200; sprite.m_bSingleFrame = true; sprite.m_fPosition_x = 800; sprite.m_fPosition_y = (float)RandomInt( 0, 560 ); sprite.m_fVelocity_x = (float)-(RandomInt( 1, 10 )); sprite.m_nFrameWidth = 16; sprite.m_nFrameHeight = 16; sprite.m_nFrameOffset_x = 16; sprite.m_nFrameOffset_y = 1; g_SpriteList.push_back(sprite); } // Create 20 laser shots for blowing up mines! for( i = 0; i < 20; i++ ) { sprite.zeroSpriteValues(); strcpy( sprite.m_chType, "shot" ); strcpy( sprite.m_chSpriteTextureName, "misc.bmp" ); sprite.m_nWidth = 200; sprite.m_nHeight = 200; sprite.m_bActive = false; sprite.m_bSingleFrame = true; sprite.m_nFrameOffset_x = 32; sprite.m_nFrameOffset_y = 0; sprite.m_nFrameWidth = 18; sprite.m_nFrameHeight = 3; g_SpriteList.push_back(sprite); } // Create 20 explosions to cover each possible laser impact with a mine! for( i = 0; i < 20; i++ ) { sprite.zeroSpriteValues(); strcpy( sprite.m_chType, "explosion" ); strcpy( sprite.m_chSpriteTextureName, "explosion.bmp" ); sprite.m_nWidth = 294; sprite.m_nHeight = 72; sprite.m_bActive = false; sprite.m_nFramesAcross = 7; sprite.m_nFrameWidth = 42; sprite.m_nFrameHeight = 36; sprite.m_nFrameRateModifier = -3; sprite.loadAnimation( 0, 0, 13, CSprite::GO_INACTIVE ); g_SpriteList.push_back(sprite); } } //----------------------------------------------------------------------------- // Name: InitializeStars() // Desc: Give each star a random starting position and velocity //----------------------------------------------------------------------------- void InitializeStars(void) { for( int i = 0; i < TOTAL_STARS; i++ ) { g_stars[i].x = rand()%SCREEN_WIDTH; g_stars[i].y = rand()%SCREEN_HEIGHT; g_stars[i].nVelocity = 1 + rand()%16; g_stars[i].color = RGB(255,255,255); } } //----------------------------------------------------------------------------- // Name: InitializeExhaust() // Desc: Initialize all exhaust particles //----------------------------------------------------------------------------- void InitializeExhaust(void) { for( int i = 0; i < TOTAL_PARTICLES; i++ ) { g_exhaust[i].x = 0; g_exhaust[i].y = 0; g_exhaust[i].nVelocity = 1 + rand()%16; g_exhaust[i].color = 700; g_exhaust[i].bVisible = false; } } //----------------------------------------------------------------------------- // Name: MoveShip() // Desc: Collects user input and acts on it by modifying the ship sprite //----------------------------------------------------------------------------- void MoveShip(void) { char buffer[256]; int nShips_x = 0; int nShips_y = 0; bool bFlameOn = false; // Get keyboard input g_pKeyboard->GetDeviceState(sizeof(buffer),(LPVOID)&buffer); // Find the ship and modify it... for( g_sprite_i = g_SpriteList.begin(); g_sprite_i != g_SpriteList.end(); ++g_sprite_i ) { if( !lstrcmp(g_sprite_i->m_chType, "ship") ) { if( KEYDOWN(buffer, DIK_UP) ) { if( g_sprite_i->m_fPosition_y > 0 ) g_sprite_i->m_fPosition_y -= SHIP_SPEED; if( g_sprite_i->m_nCurrentFrame < 28 ) g_sprite_i->incFrame(); } else if( KEYDOWN(buffer, DIK_DOWN) ) { if( g_sprite_i->m_fPosition_y < 520 ) g_sprite_i->m_fPosition_y += SHIP_SPEED; if( g_sprite_i->m_nCurrentFrame > 0 ) g_sprite_i->decFrame(); } else { if( g_sprite_i->m_nCurrentFrame > 14) g_sprite_i->decFrame(); if( g_sprite_i->m_nCurrentFrame < 14) g_sprite_i->incFrame(); } if( KEYDOWN(buffer, DIK_LEFT) ) { if( g_sprite_i->m_fPosition_x > 0 ) g_sprite_i->m_fPosition_x -= SHIP_SPEED; } if( KEYDOWN(buffer, DIK_RIGHT) ) { if( g_sprite_i->m_fPosition_x < (SCREEN_WIDTH - 144)) g_sprite_i->m_fPosition_x += SHIP_SPEED; nShips_x = (int)g_sprite_i->m_fPosition_x; nShips_y = (int)g_sprite_i->m_fPosition_y; bFlameOn = true; } if( KEYDOWN(buffer, DIK_SPACE) ) { /* // Single shot laser fire for( g_sprite_j = g_SpriteList.begin(); g_sprite_j != g_SpriteList.end(); ++g_sprite_j ) { if( !lstrcmp(g_sprite_j->m_chType, "shot") && g_sprite_j->m_bActive == false ) { g_sprite_j->m_fPosition_x = ( g_sprite_i->m_fPosition_x + 120 ); g_sprite_j->m_fPosition_y = ( g_sprite_i->m_fPosition_y + 48 ); g_sprite_j->m_fVelocity_x = 20; g_sprite_j->m_bActive = true; break; } } //*/ //* // Triple shot laser fire // Figure how much time has passed since the last tri-shot DWORD dwCurrTick = timeGetTime(); DWORD dwTickDiff = dwCurrTick - g_dwLastFireTick; int nShots = 0; if( dwTickDiff >= 75 ) { for( g_sprite_j = g_SpriteList.begin(); g_sprite_j != g_SpriteList.end(); ++g_sprite_j ) { if( !lstrcmp(g_sprite_j->m_chType, "shot") && g_sprite_j->m_bActive == false ) { g_sprite_j->m_fPosition_x = ( g_sprite_i->m_fPosition_x + 120 ); g_sprite_j->m_fPosition_y = ( g_sprite_i->m_fPosition_y + 48 ); g_sprite_j->m_bActive = true; if( nShots == 0 ) g_sprite_j->m_fVelocity_x = 20; if( nShots == 1 ) { g_sprite_j->m_fVelocity_x = 20; g_sprite_j->m_fVelocity_y = 2; } if( nShots == 2 ) { g_sprite_j->m_fVelocity_x = 20; g_sprite_j->m_fVelocity_y = -2; } ++nShots; if( nShots == 3 ) break; } } g_dwLastFireTick = dwCurrTick; } //*/ } break; } } for( g_sprite_i = g_SpriteList.begin(); g_sprite_i != g_SpriteList.end(); ++g_sprite_i ) { if( !lstrcmp(g_sprite_i->m_chType, "animeflame") ) { if( bFlameOn == true ) { g_sprite_i->m_bActive = true; g_sprite_i->m_fPosition_x = (float)(nShips_x - 40); g_sprite_i->m_fPosition_y = (float)(nShips_y + 50); for( int i = 0; i< TOTAL_PARTICLES; i++ ) { if( g_exhaust[i].bVisible == false ) { int nCenter = (nShips_y + 56); g_exhaust[i].x = nShips_x; g_exhaust[i].y = RandomInt( (nCenter - 10), (nCenter + 10) ); g_exhaust[i].bVisible = true; break; } } bFlameOn = false; } else { g_sprite_i->m_bActive = false; g_sprite_i->m_nCurrentFrame = 0; } break; } } } //----------------------------------------------------------------------------- // Name: MoveSprites() // Desc: Identifies sprites in the linked list and moves each one accordingly //----------------------------------------------------------------------------- void MoveSprites() { // Move all active player shots for( g_sprite_i = g_SpriteList.begin(); g_sprite_i != g_SpriteList.end(); ++g_sprite_i ) { if( !lstrcmp(g_sprite_i->m_chType, "shot") && g_sprite_i->m_bActive == true ) { if( g_sprite_i->m_fPosition_x < SCREEN_WIDTH ) { g_sprite_i->m_fPosition_x += g_sprite_i->m_fVelocity_x; g_sprite_i->m_fPosition_y += g_sprite_i->m_fVelocity_y; } else { // Recycle player shots that have left the viewable area! g_sprite_i->m_bActive = false; g_sprite_i->m_fPosition_x = 0; g_sprite_i->m_fPosition_y = 0; g_sprite_i->m_fVelocity_x = 0; g_sprite_i->m_fVelocity_y = 0; } } if( !lstrcmp(g_sprite_i->m_chType, "mine") ) { g_sprite_i->m_fPosition_x += g_sprite_i->m_fVelocity_x; g_sprite_i->m_fPosition_y += g_sprite_i->m_fVelocity_y; if( g_sprite_i->m_fPosition_x > 800 ) g_sprite_i->m_fPosition_x = 0; if( g_sprite_i->m_fPosition_x < -64 ) { g_sprite_i->m_fPosition_x = 800; g_sprite_i->m_fPosition_y = (float)RandomInt( 0, 560 ); g_sprite_i->m_fVelocity_x = (float)-(RandomInt( 1, 10 )); } } } } //----------------------------------------------------------------------------- // Name: MoveStars() // Desc: Update each star's position according to its velocity //----------------------------------------------------------------------------- void MoveStars(void) { // Scroll stars to the left for( int i = 0; i< TOTAL_STARS; i++ ) { // Move the star g_stars[i].x -= g_stars[i].nVelocity; // If the star falls off the screen's edge, wrap it around if( g_stars[i].x <= 0 ) g_stars[i].x = SCREEN_WIDTH; } } //----------------------------------------------------------------------------- // Name: MoveExhaust() // Desc: Move all visible exhaust particles to the right //----------------------------------------------------------------------------- void MoveExhaust(void) { // Move particles to the left for( int i = 0; i < TOTAL_PARTICLES; i++ ) { // Move the particle if( g_exhaust[i].bVisible == true ) { g_exhaust[i].x -= g_exhaust[i].nVelocity; if( g_exhaust[i].x <= 0 ) { g_exhaust[i].x = 1; g_exhaust[i].bVisible = false; } } } } //----------------------------------------------------------------------------- // Name: CheckCollisions() // Desc: Search the sprite linked-list for sprites that touch //----------------------------------------------------------------------------- void CheckCollisions(void) { // Perfrom collision detection int nCount1 = 0; int nCount2 = 0; int size = g_SpriteList.size(); for( g_sprite_i = g_SpriteList.begin(); g_sprite_i != g_SpriteList.end(); ++g_sprite_i ) { ++nCount1; // Next sprite to process for( g_sprite_j = g_SpriteList.begin(); g_sprite_j != g_SpriteList.end(); ++g_sprite_j ) { // Don't check g_sprite_i against sprites that it's already been checked against while( nCount2 != nCount1 ) { ++g_sprite_j; // Don't check sprites that've already been checked. ++nCount2; // Skip ahead... } // Don't bother checking the last sprite... if( nCount2 == size ) break; if( g_sprite_i->m_bCollide == true && g_sprite_j->m_bCollide == true && g_sprite_i->m_bActive == true && g_sprite_j->m_bActive == true) { if( SpriteCollisionTest( *g_sprite_i, *g_sprite_j ) ) { // Has a mine hit a shot? if( !lstrcmp(g_sprite_i->m_chType, "mine") && !lstrcmp(g_sprite_j->m_chType, "shot") ) { g_nScore += 5; // Kill shot g_sprite_j->m_bActive = false; // Find an explosion sprite to assign for( g_sprite_k = g_SpriteList.begin(); g_sprite_k != g_SpriteList.end(); ++g_sprite_k ) { if( !lstrcmp(g_sprite_k->m_chType, "explosion") && g_sprite_k->m_bActive == false ) { // Assign explosion to the collided mine's position and speed g_sprite_k->m_fPosition_x = (g_sprite_i->m_fPosition_x - 10); g_sprite_k->m_fPosition_y = (g_sprite_i->m_fPosition_y - 20); g_sprite_k->m_fVelocity_x = g_sprite_i->m_fVelocity_x; g_sprite_k->m_bActive = true; // Place the mine into a waiting off-screen until the script engine using it again g_sprite_i->m_fPosition_x = -100; g_sprite_i->m_fPosition_y = -100; g_sprite_i->m_fVelocity_x = 0; g_sprite_i->m_fVelocity_y = 0; g_sprite_i->m_bScripting = false; break; } } } // Has a shot hit a mine? if( !lstrcmp(g_sprite_i->m_chType, "shot") && !lstrcmp(g_sprite_j->m_chType, "mine") ) { g_nScore += 5; // Kill shot g_sprite_i->m_bActive = false; // Find an explosion sprite to assign for( g_sprite_k = g_SpriteList.begin(); g_sprite_k != g_SpriteList.end(); ++g_sprite_k ) { if( !lstrcmp(g_sprite_k->m_chType, "explosion") && g_sprite_k->m_bActive == false ) { // Assign explosion to the collided mine's position and speed g_sprite_k->m_fPosition_x = (g_sprite_j->m_fPosition_x - 10); g_sprite_k->m_fPosition_y = (g_sprite_j->m_fPosition_y - 20); g_sprite_k->m_fVelocity_x = g_sprite_j->m_fVelocity_x; g_sprite_k->m_bActive = true; // Place the mine into a waiting off-screen g_sprite_j->m_fPosition_x = -100; g_sprite_j->m_fPosition_y = -100; g_sprite_j->m_fVelocity_x = 0; g_sprite_j->m_fVelocity_y = 0; break; } } } // Has the ship hit a mine if( !lstrcmp(g_sprite_i->m_chType, "ship") && !lstrcmp(g_sprite_j->m_chType, "mine") ) { if( g_nPowerLevel != 0 ) --g_nPowerLevel; if( g_nPowerLevel == 0 ) { if( g_nShipsLeft != 0 ) --g_nShipsLeft; g_nPowerLevel = 20; } // Find an explosion sprite to assign for( g_sprite_k = g_SpriteList.begin(); g_sprite_k != g_SpriteList.end(); ++g_sprite_k ) { if( !lstrcmp(g_sprite_k->m_chType, "explosion") && g_sprite_k->m_bActive == false ) { // Assign explosion to the collided mine's position and speed g_sprite_k->m_fPosition_x = (g_sprite_j->m_fPosition_x - 10); g_sprite_k->m_fPosition_y = (g_sprite_j->m_fPosition_y - 20); g_sprite_k->m_fVelocity_x = g_sprite_j->m_fVelocity_x; g_sprite_k->m_bActive = true; // Place the mine into a waiting off-screen g_sprite_j->m_fPosition_x = -100; g_sprite_j->m_fPosition_y = -100; g_sprite_j->m_fVelocity_x = 0; g_sprite_j->m_fVelocity_y = 0; break; } } } } } } nCount2 = 0; } } //----------------------------------------------------------------------------- // Name: SpriteCollisionTest() // Desc: Simple function wrapper that passes the proper sprite values // to CollisionTest() for checking. //----------------------------------------------------------------------------- bool SpriteCollisionTest( CSprite& sprite1, CSprite& sprite2 ) { // This function passes sprite values to the CollisionTest() function // in several different ways depending on whether or not the sprites // involved are being scaled or have had there size properties adjusted // for the purposes of fine-tuning collision detection. bool bCollide = false; if( sprite1.m_bModifyCollision == true && sprite2.m_bModifyCollision == true ) { // Both sprites require modification before sending. bCollide = CollisionTest( (int)sprite1.m_fPosition_x + sprite1.m_nCollisionLeft, (int)sprite1.m_fPosition_y - sprite1.m_nCollisionTop, sprite1.m_nFrameWidth + sprite1.m_nWidthScaling + sprite1.m_nCollisionRight, sprite1.m_nFrameHeight + sprite1.m_nHeightScaling + sprite1.m_nCollisionBottom, (int)sprite2.m_fPosition_x + sprite2.m_nCollisionLeft, (int)sprite2.m_fPosition_y - sprite2.m_nCollisionTop, sprite2.m_nFrameWidth + sprite2.m_nWidthScaling + sprite2.m_nCollisionRight, sprite2.m_nFrameHeight + sprite2.m_nHeightScaling + sprite2.m_nCollisionBottom); } else if( sprite1.m_bModifyCollision == true && sprite2.m_bModifyCollision == false ) { // Only the first sprite requires modification before sending. bCollide = CollisionTest( (int)sprite1.m_fPosition_x + sprite1.m_nCollisionLeft, (int)sprite1.m_fPosition_y - sprite1.m_nCollisionTop, sprite1.m_nFrameWidth + sprite1.m_nWidthScaling + sprite1.m_nCollisionRight, sprite1.m_nFrameHeight + sprite1.m_nHeightScaling + sprite1.m_nCollisionBottom, (int)sprite2.m_fPosition_x, (int)sprite2.m_fPosition_y, sprite2.m_nFrameWidth, sprite2.m_nFrameHeight); } else if( sprite1.m_bModifyCollision == false && sprite2.m_bModifyCollision == true ) { // Only the second sprite requires modification before sending. bCollide = CollisionTest( (int)sprite1.m_fPosition_x, (int)sprite1.m_fPosition_y, sprite1.m_nFrameWidth, sprite1.m_nFrameHeight, (int)sprite2.m_fPosition_x + sprite2.m_nCollisionLeft, (int)sprite2.m_fPosition_y - sprite2.m_nCollisionTop, sprite2.m_nFrameWidth + sprite2.m_nWidthScaling + sprite2.m_nCollisionRight, sprite2.m_nFrameHeight + sprite2.m_nHeightScaling + sprite2.m_nCollisionBottom); } else { // Neither of the sprites require modification before sending. bCollide = CollisionTest( (int)sprite1.m_fPosition_x, (int)sprite1.m_fPosition_y, sprite1.m_nFrameWidth, sprite1.m_nFrameHeight, (int)sprite2.m_fPosition_x, (int)sprite2.m_fPosition_y, sprite2.m_nFrameWidth, sprite2.m_nFrameHeight); } return(bCollide); } //----------------------------------------------------------------------------- // Name: CollisionTest() // Desc: Checks to see if two rectangular regions overlap or not. //----------------------------------------------------------------------------- bool CollisionTest(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) { // This function tests if the two rectangles overlap // Get the radi of each rect int width1 = (w1>>1) - (w1>>3); int height1 = (h1>>1) - (h1>>3); int width2 = (w2>>1) - (w2>>3); int height2 = (h2>>1) - (h2>>3); // Compute center of each rect int cx1 = x1 + width1; int cy1 = y1 + height1; int cx2 = x2 + width2; int cy2 = y2 + height2; // Compute deltas int dx = abs(cx2 - cx1); int dy = abs(cy2 - cy1); // Test if rects overlap if(dx < (width1+width2) && dy < (height1+height2)) return true; else // Else no collision return false; } //----------------------------------------------------------------------------- // Name: ComputeScore() // Desc: Animates the number sprites according to the current score //----------------------------------------------------------------------------- void ComputeScore(void) { // Calculate the frame for each number sprite based on current score int number4 = g_nScore%10; // Ones Place int number3 = (g_nScore%100)/10; // Tens Place int number2 = (g_nScore%1000)/100; // Hundreds Place int number1 = (g_nScore%10000)/1000; // Thousands Place int ships1 = g_nShipsLeft%10; // Ones Place // Go through the linked list looking for the number sprites and assign values for( g_sprite_i = g_SpriteList.begin(); g_sprite_i != g_SpriteList.end(); ++g_sprite_i ) { if( !lstrcmp(g_sprite_i->m_chType, "numbers") ) { if( g_sprite_i->m_nState == 0 ) g_sprite_i->m_nCurrentFrame = number1; if( g_sprite_i->m_nState == 1 ) g_sprite_i->m_nCurrentFrame = number2; if( g_sprite_i->m_nState == 2 ) g_sprite_i->m_nCurrentFrame = number3; if( g_sprite_i->m_nState == 3 ) g_sprite_i->m_nCurrentFrame = number4; } if( !lstrcmp(g_sprite_i->m_chType, "shipnumber") ) { g_sprite_i->m_nCurrentFrame = ships1; } } } //----------------------------------------------------------------------------- // Name: DisplayFrame() // Desc: Blts the sprites to the back buffer, then it blts or flips the // back buffer onto the primary buffer. //----------------------------------------------------------------------------- HRESULT DisplayFrame() { HRESULT hr; g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_COLORVALUE(0.0f, 0.0f, 0.0f, 1.0f), 1.0f, 0 ); g_pd3dDevice->BeginScene(); DrawStars(); DrawExhaust(); DrawPowerBar(); //if( g_bWindowed ) //{ // WriteToSurface( "Press Escape to quit. Press Alt-Enter to switch to Full-Screen mode.", // NULL, 5, (SCREEN_HEIGHT - 20), g_pDisplay->GetBackBuffer(), false); //} //else //{ // WriteToSurface( "Press Escape to quit. Press Alt-Enter to switch to Windowed mode.", // NULL, 5, (SCREEN_HEIGHT - 20), g_pDisplay->GetBackBuffer(), false); //} g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); for( g_sprite_i = g_SpriteList.begin(); g_sprite_i != g_SpriteList.end(); ++g_sprite_i ) g_sprite_i->drawSprite( g_pd3dDevice ); g_pd3dDevice->EndScene(); if( FAILED( hr = g_pd3dDevice->Present( NULL, NULL, NULL, NULL ) ) ) return hr; return S_OK; } //----------------------------------------------------------------------------- // Name: DrawStars() // Desc: Draws the stars as pixel points on the back buffer. //----------------------------------------------------------------------------- HRESULT DrawStars( void ) { LPDIRECT3DSURFACE9 pBackBuffer = NULL; D3DSURFACE_DESC ddsd; int linearPitch = 0; int nColorDepth = 0; int x = 0; int y = 0; // Move and draw the stars MoveStars(); g_pd3dDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer ); pBackBuffer->GetDesc( &ddsd ); D3DLOCKED_RECT lockedRectBackBuffer; if( FAILED( pBackBuffer->LockRect( &lockedRectBackBuffer, NULL, 0 ) ) ) { pBackBuffer->Release(); return S_FALSE; } // Get the color-depth of the back buffer. These are the only formats used // by a Direct3D back-buffer. Find which one is being used and resolve the // color-depth from it. switch( ddsd.Format ) { case D3DFMT_A2R10G10B10: // 32-bit pixel format using 10 bits each for red, green, and blue, // and 2 bits for alpha. Used only inn full-screen mode. nColorDepth = 32; break; case D3DFMT_A8R8G8B8: // 32-bit ARGB pixel format with alpha, using 8 bits per channel. nColorDepth = 32; break; case D3DFMT_X8R8G8B8: // 32-bit RGB pixel format, where 8 bits are reserved for each color. nColorDepth = 32; break; case D3DFMT_A1R5G5B5: // 16-bit pixel format where 5 bits are reserved for each color // and 1 bit is reserved for alpha. nColorDepth = 16; break; case D3DFMT_X1R5G5B5: // 16-bit pixel format where 5 bits are reserved for each color. nColorDepth = 16; break; case D3DFMT_R5G6B5: // 16-bit RGB pixel format with 5 bits for red, 6 bits for green, // and 5 bits for blue. nColorDepth = 16; break; default: break; } linearPitch = (int)lockedRectBackBuffer.Pitch; // It seems that 8 bit color is no longer in use for Direct3D back-buffers. //if( nColorDepth == 8 ) //{ // // Use a BYTE because 1 byte per pixel in 8 bit color // BYTE *surfaceBuffer = static_cast (lockedRectBackBuffer.pBits); // // for( int i = 0; i < TOTAL_STARS; i++ ) // { // x = g_stars[i].x; // y = g_stars[i].y; // // // Plot the pixel // surfaceBuffer[x+y*linearPitch] = g_stars[i].color; // } //} if( nColorDepth == 16 ) { // Use a USHORT because 2 bytes per pixel in 16 bit color USHORT *surfaceBuffer = static_cast (lockedRectBackBuffer.pBits); // And half the linear pitch because each pixel is now worth 2 bytes linearPitch = (linearPitch>>1); for( int i = 0; i < TOTAL_STARS; i++ ) { int x = g_stars[i].x; int y = g_stars[i].y; // Plot the pixel surfaceBuffer[x+y*linearPitch] = (USHORT)g_stars[i].color; } } else if( nColorDepth == 32 ) { // Use a UINT because 4 bytes per pixel in 32 bit color UINT *surfaceBuffer = static_cast (lockedRectBackBuffer.pBits); // And half the linear pitch twice because each pixel is now worth 4 bytes linearPitch = (linearPitch>>2); for( int i = 0; i < TOTAL_STARS; i++ ) { x = g_stars[i].x; y = g_stars[i].y; // Plot the pixel surfaceBuffer[x+y*linearPitch] = g_stars[i].color; } } if( FAILED( pBackBuffer->UnlockRect() ) ) return S_FALSE; pBackBuffer->Release(); return S_OK; } //----------------------------------------------------------------------------- // Name: DrawExhaust() // Desc: Draw all visible exhaust particles. //----------------------------------------------------------------------------- HRESULT DrawExhaust( void ) { LPDIRECT3DSURFACE9 pBackBuffer = NULL; D3DSURFACE_DESC ddsd; int linearPitch = 0; int nColorDepth = 0; int x = 0; int y = 0; // Move and draw the particles MoveExhaust(); g_pd3dDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer ); pBackBuffer->GetDesc( &ddsd ); D3DLOCKED_RECT lockedRectBackBuffer; if( FAILED( pBackBuffer->LockRect( &lockedRectBackBuffer, NULL, 0 ) ) ) { pBackBuffer->Release(); return S_FALSE; } // Get the color-depth of the back buffer. These are the only formats used // by a Direct3D back-buffer. Find which one is being used and resolve the // color-depth from it. switch( ddsd.Format ) { case D3DFMT_A2R10G10B10: // 32-bit pixel format using 10 bits each for red, green, and blue, // and 2 bits for alpha. Used only inn full-screen mode. nColorDepth = 32; break; case D3DFMT_A8R8G8B8: // 32-bit ARGB pixel format with alpha, using 8 bits per channel. nColorDepth = 32; break; case D3DFMT_X8R8G8B8: // 32-bit RGB pixel format, where 8 bits are reserved for each color. nColorDepth = 32; break; case D3DFMT_A1R5G5B5: // 16-bit pixel format where 5 bits are reserved for each color // and 1 bit is reserved for alpha. nColorDepth = 16; break; case D3DFMT_X1R5G5B5: // 16-bit pixel format where 5 bits are reserved for each color. nColorDepth = 16; break; case D3DFMT_R5G6B5: // 16-bit RGB pixel format with 5 bits for red, 6 bits for green, // and 5 bits for blue. nColorDepth = 16; break; default: break; } linearPitch = (int)lockedRectBackBuffer.Pitch; //if( nColorDepth == 8 ) //{ // // Use a BYTE because 1 byte per pixel in 8 bit color // BYTE *surfaceBuffer = static_cast (lockedRectBackBuffer.pBits); // // for( int i = 0; i < TOTAL_PARTICLES; i++ ) // { // if( g_exhaust[i].bVisible == true ) // { // x = g_exhaust[i].x; // y = g_exhaust[i].y; // // // Plot the center pixel // surfaceBuffer[x+(y*linearPitch)] = g_exhaust[i].color; // // Plot the left pixel // surfaceBuffer[(x+1)+(y*linearPitch)] = g_exhaust[i].color; // // Plot the right pixel // surfaceBuffer[(x-1)+(y*linearPitch)] = g_exhaust[i].color; // // Plot the top pixel // surfaceBuffer[x+((y-1)*linearPitch)] = g_exhaust[i].color; // // Plot the bottom pixel // surfaceBuffer[x+((y+1)*linearPitch)] = g_exhaust[i].color; // } // } //} if( nColorDepth == 16 ) { // Use a USHORT because 2 bytes per pixel in 16 bit color USHORT *surfaceBuffer = static_cast (lockedRectBackBuffer.pBits); // And half the linear pitch because each pixel is now worth 2 bytes linearPitch = (linearPitch>>1); for( int i = 0; i < TOTAL_PARTICLES; i++ ) { if( g_exhaust[i].bVisible == true ) { x = g_exhaust[i].x; y = g_exhaust[i].y; // Plot the center pixel surfaceBuffer[x+(y*linearPitch)] = (USHORT)g_exhaust[i].color; // Plot the left pixel surfaceBuffer[(x+1)+(y*linearPitch)] = (USHORT)g_exhaust[i].color; // Plot the right pixel surfaceBuffer[(x-1)+(y*linearPitch)] = (USHORT)g_exhaust[i].color; // Plot the top pixel surfaceBuffer[x+((y-1)*linearPitch)] = (USHORT)g_exhaust[i].color; // Plot the bottom pixel surfaceBuffer[x+((y+1)*linearPitch)] = (USHORT)g_exhaust[i].color; } } } else if( nColorDepth == 32 ) { // Use a UINT because 4 bytes per pixel in 32 bit color UINT *surfaceBuffer = static_cast (lockedRectBackBuffer.pBits); // And half the linear pitch twice because each pixel is now worth 4 bytes linearPitch = (linearPitch>>2); for( int i = 0; i < TOTAL_PARTICLES; i++ ) { if( g_exhaust[i].bVisible == true ) { x = g_exhaust[i].x; y = g_exhaust[i].y; // Plot the center pixel surfaceBuffer[x+(y*linearPitch)] = g_exhaust[i].color; // Plot the left pixel surfaceBuffer[(x+1)+(y*linearPitch)] = g_exhaust[i].color; // Plot the right pixel surfaceBuffer[(x-1)+(y*linearPitch)] = g_exhaust[i].color; // Plot the top pixel surfaceBuffer[x+((y-1)*linearPitch)] = g_exhaust[i].color; // Plot the bottom pixel surfaceBuffer[x+((y+1)*linearPitch)] = g_exhaust[i].color; } } } if( FAILED( pBackBuffer->UnlockRect() ) ) return S_FALSE; pBackBuffer->Release(); return S_OK; } //----------------------------------------------------------------------------- // Name: DrawPowerBar() // Desc: Draws the power bar and the colored hash mark sprites that make up // the power bar indicator. //----------------------------------------------------------------------------- HRESULT DrawPowerBar( void ) { // Warning: This function assumes that the sprites that make up the power // bar have been placed in the linked list in a certain order. If this // order is changed, the power bar will be drawn incorrectly or not at all. int nStartingPosit_x = 450; int nStartingPosit_y = 10; int nMarkSpacing = 5; int nMarkCount = 0; int nTotalRed = 5; int nTotalYellow = 5; int nTotalGreen = 10; int i = 0; for( g_sprite_i = g_SpriteList.begin(); g_sprite_i != g_SpriteList.end(); ++g_sprite_i ) { if( !lstrcmp(g_sprite_i->m_chType, "powerbar") ) { g_sprite_i->m_bActive = true; g_sprite_i->m_fPosition_x = (float)nStartingPosit_x - 3; g_sprite_i->m_fPosition_y = (float)nStartingPosit_y - 2; g_sprite_i->drawSprite( g_pd3dDevice ); g_sprite_i->m_bActive = false; } if( !lstrcmp(g_sprite_i->m_chType, "redmark") ) { // Keep drawing red hash marks until we hit the limit or // they're no longer required. g_sprite_i->m_bActive = true; if( g_nPowerLevel > 0 ) { for( i = 0; i < nTotalRed; ++i ) { g_sprite_i->m_fPosition_x = (float)nStartingPosit_x; g_sprite_i->m_fPosition_y = (float)nStartingPosit_y; g_sprite_i->drawSprite( g_pd3dDevice ); nStartingPosit_x += nMarkSpacing; ++nMarkCount; if( nMarkCount >= g_nPowerLevel ) break; } } g_sprite_i->m_bActive = false; } if( !lstrcmp(g_sprite_i->m_chType, "yellowmark") ) { // Keep drawing yellow hash marks until we hit the limit or // they're no longer required. g_sprite_i->m_bActive = true; if( g_nPowerLevel > nTotalYellow ) { for( i = 0; i < nTotalYellow; ++i ) { g_sprite_i->m_fPosition_x = (float)nStartingPosit_x; g_sprite_i->m_fPosition_y = (float)nStartingPosit_y; g_sprite_i->drawSprite( g_pd3dDevice ); nStartingPosit_x += nMarkSpacing; ++nMarkCount; if( nMarkCount >= g_nPowerLevel ) break; } } g_sprite_i->m_bActive = false; } if( !lstrcmp(g_sprite_i->m_chType, "greenmark") ) { // Keep drawing green hash marks until we hit the limit or // they're no longer required. g_sprite_i->m_bActive = true; if( g_nPowerLevel > nTotalGreen ) { for( i = 0; i < nTotalGreen; ++i ) { g_sprite_i->m_fPosition_x = (float)nStartingPosit_x; g_sprite_i->m_fPosition_y = (float)nStartingPosit_y; g_sprite_i->drawSprite( g_pd3dDevice ); nStartingPosit_x += nMarkSpacing; ++nMarkCount; if( nMarkCount >= g_nPowerLevel ) break; } } g_sprite_i->m_bActive = false; break; // There's no reason to keep searching the linked list - Bail out! } } return S_OK; } //----------------------------------------------------------------------------- // Name: RandomInt() // Desc: Produces a random int value between some given range //----------------------------------------------------------------------------- int RandomInt( int nLow, int nHigh ) { int nRange = nHigh - nLow; int nNum = rand() % nRange; return( nNum + nLow ); }