游戏编程入门之碰撞检测
在进行以下内容前我们需先做好准备,明白都要做什么
(1)编写碰撞函数(此时的函数不是完整的下面会对其修改):
我们首先需要创建两个矩形并且调用IntersetRect函数来检查他们是否碰撞的函数。这个函数名为Collision,可重用性很好哦。
1 int Collision(SPRITE sprite1, SPRITE sprite2) 2 { 3 RECT rect1; 4 rect1.left = sprite1.x; 5 rect1.top = sprite1.y; 6 rect1.right = sprite1.x + sprite1.width; 7 rect1.bottom = sprite1.y + sprite1.height; 8 9 RECT rect2; 10 rect2.left = sprite2.x; 11 rect2.top = sprite2.y; 12 rect2.right = sprite2.x + sprite2.width; 13 rect2.bottom = sprite2.y + sprite2.height; 14 15 RECT dest; //ignored 16 return IntersectRect(&dest, &rect1, &rect2); 17 }
建议:你将注意到在collision函数上有编译器警告信息,因为SPRITE.x和SPRITE.y属性是浮点数,而RECT属性是长整型。要想去除这些警告,可将精灵属性轻质住阿奴按成
long。
(2)新的精灵结构:
1 struct SPRITE { 2 float x, y; 3 int frame, columns; 4 int width, height; 5 float scaling, rotation; 6 int startframe, endframe; 7 int starttime, delay; 8 int direction; 9 float velx, vely; 10 D3DCOLOR color; 11 SPRITE() 12 { 13 frame = 0; 14 columns = 1; 15 width = height = 0; 16 scaling = 1.0f; 17 rotation = 0.0f; 18 startframe = endframe = 0; 19 direction = 1; 20 starttime = delay = 0; 21 velx = vely = 0.0f; 22 color = D3DCOLOR_XRGB(255, 255, 255); 23 } 24 };
(3)为精灵的缩放进行调整:
1 int Collision(SPRITE sprite1, SPRITE sprite2) 2 { 3 RECT rect1; 4 rect1.left = (long)sprite1.x; 5 rect1.top = (long)sprite1.y; 6 rect1.right = (long)sprite1.x + sprite1.width + sprite1.scaling; 7 rect1.bottom = (long)sprite1.y + sprite1.height + sprite1.scaling; 8 9 RECT rect2; 10 rect2.left = (long)sprite2.x; 11 rect2.top = (long)sprite2.y; 12 rect2.right = (long)sprite2.x + sprite2.width + sprite2.scaling; 13 rect2.bottom = (long)sprite2.y + sprite2.height + sprite2.scaling; 14 15 RECT dest; //ignored 16 return IntersectRect(&dest, &rect1, &rect2); 17 }
OK,到这里准备工作已完成(其实只是对MyDirectX.h和MyDirectX.cpp两个代码块进行了添加操作,其他的无变化哦),示例代码如下:
MyDirectX.h:
1 #pragma once 2 //header files 3 #define WIN32_EXTRA_LEAN 4 #define DIRECTINPUT_VERSION 0x0800 5 #include <windows.h> 6 #include <d3d9.h> 7 #include <d3dx9.h> 8 #include <dinput.h> 9 #include <xinput.h> 10 #include <ctime> 11 #include <iostream> 12 #include <iomanip> 13 using namespace std; 14 15 //libraries 16 #pragma comment(lib,"winmm.lib") 17 #pragma comment(lib,"user32.lib") 18 #pragma comment(lib,"gdi32.lib") 19 #pragma comment(lib,"dxguid.lib") 20 #pragma comment(lib,"d3d9.lib") 21 #pragma comment(lib,"d3dx9.lib") 22 #pragma comment(lib,"dinput8.lib") 23 #pragma comment(lib,"xinput.lib") 24 25 //program values 26 extern const string APPTITLE; 27 extern const int SCREENW; 28 extern const int SCREENH; 29 extern bool gameover; 30 31 //macro to detect key presses 32 #define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0) 33 34 //Direct3D objects 35 extern LPDIRECT3D9 d3d; 36 extern LPDIRECT3DDEVICE9 d3ddev; 37 extern LPDIRECT3DSURFACE9 backbuffer; 38 extern LPD3DXSPRITE spriteobj; 39 40 //Direct3D functions 41 bool Direct3D_Init(HWND hwnd, int width, int height, bool fullscreen); 42 void Direct3D_Shutdown(); 43 LPDIRECT3DSURFACE9 LoadSurface(string filename); 44 void DrawSurface(LPDIRECT3DSURFACE9 dest, float x, float y, LPDIRECT3DSURFACE9 source); 45 D3DXVECTOR2 GetBitmapSize(string filename); 46 LPDIRECT3DTEXTURE9 LoadTexture(string filename, D3DCOLOR transcolor = D3DCOLOR_XRGB(0, 0, 0)); 47 void Sprite_Draw_Frame(LPDIRECT3DTEXTURE9 texture, int destx, int desty, int framenum, int framew, int frameh, int columns); 48 void Sprite_Animate(int &frame, int startframe, int endframe, int direction, int &starttime, int delay); 49 void Sprite_Transform_Draw(LPDIRECT3DTEXTURE9 image, int x, int y, int width, int height, int frame = 0, int columns = 1, 50 float rotation = 0.0f, float scaling = 1.0f, D3DCOLOR color = D3DCOLOR_XRGB(255, 255, 255)); 51 52 //DirectInput objects, devices, and states 53 extern LPDIRECTINPUT8 dinput; 54 extern LPDIRECTINPUTDEVICE8 dimouse; 55 extern LPDIRECTINPUTDEVICE8 dikeyboard; 56 extern DIMOUSESTATE mouse_state; 57 extern XINPUT_GAMEPAD controllers[4]; 58 59 //DirectInput functions 60 bool DirectInput_Init(HWND); 61 void DirectInput_Update(); 62 void DirectInput_Shutdown(); 63 bool Key_Down(int); 64 int Mouse_Button(int); 65 int Mouse_X(); 66 int Mouse_Y(); 67 void XInput_Vibrate(int contNum = 0, int amount = 65535); 68 bool XInput_Controller_Found(); 69 70 //game functions 71 bool Game_Init(HWND window); 72 void Game_Run(HWND window); 73 void Game_End(); 74 75 //sprite structure 76 struct SPRITE { 77 float x, y; 78 int frame, columns; 79 int width, height; 80 float scaling, rotation; 81 int startframe, endframe; 82 int starttime, delay; 83 int direction; 84 float velx, vely; 85 D3DCOLOR color; 86 SPRITE() 87 { 88 frame = 0; 89 columns = 1; 90 width = height = 0; 91 scaling = 1.0f; 92 rotation = 0.0f; 93 startframe = endframe = 0; 94 direction = 1; 95 starttime = delay = 0; 96 velx = vely = 0.0f; 97 color = D3DCOLOR_XRGB(255, 255, 255); 98 } 99 }; 100 //bouding box collision detection 101 int Collision(SPRITE sprite1, SPRITE sprite2);
MyDirectX.cpp:
1 #include "MyDirectX.h" 2 #include <iostream> 3 using namespace std; 4 5 //Direct3D variables 6 LPDIRECT3D9 d3d = NULL; 7 LPDIRECT3DDEVICE9 d3ddev = NULL; 8 LPDIRECT3DSURFACE9 backbuffer = NULL; 9 LPD3DXSPRITE spriteobj; 10 11 //DirectInput variables 12 LPDIRECTINPUT8 dinput = NULL; 13 LPDIRECTINPUTDEVICE8 dimouse = NULL; 14 LPDIRECTINPUTDEVICE8 dikeyboard = NULL; 15 DIMOUSESTATE mouse_state; 16 char keys[256]; 17 XINPUT_GAMEPAD controllers[4]; 18 19 20 bool Direct3D_Init(HWND window, int width, int height, bool fullscreen) 21 { 22 //initialize Direct3D 23 d3d = Direct3DCreate9(D3D_SDK_VERSION); 24 if (!d3d) return false; 25 26 //set Direct3D presentation parameters 27 D3DPRESENT_PARAMETERS d3dpp; 28 ZeroMemory(&d3dpp, sizeof(d3dpp)); 29 d3dpp.hDeviceWindow = window; 30 d3dpp.Windowed = (!fullscreen); 31 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; 32 d3dpp.EnableAutoDepthStencil = 1; 33 d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; 34 d3dpp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL; 35 d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; 36 d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; 37 d3dpp.BackBufferCount = 1; 38 d3dpp.BackBufferWidth = width; 39 d3dpp.BackBufferHeight = height; 40 41 //create Direct3D device 42 d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window, 43 D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev); 44 if (!d3ddev) return false; 45 46 47 //get a pointer to the back buffer surface 48 d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer); 49 50 //create sprite object 51 D3DXCreateSprite(d3ddev, &spriteobj); 52 53 return 1; 54 } 55 56 void Direct3D_Shutdown() 57 { 58 if (spriteobj) spriteobj->Release(); 59 60 if (d3ddev) d3ddev->Release(); 61 if (d3d) d3d->Release(); 62 } 63 64 void DrawSurface(LPDIRECT3DSURFACE9 dest, float x, float y, LPDIRECT3DSURFACE9 source) 65 { 66 //get width/height from source surface 67 D3DSURFACE_DESC desc; 68 source->GetDesc(&desc); 69 70 //create rects for drawing 71 RECT source_rect = { 0, 0, (long)desc.Width, (long)desc.Height }; 72 RECT dest_rect = { (long)x, (long)y, (long)x + desc.Width, (long)y + desc.Height }; 73 74 //draw the source surface onto the dest 75 d3ddev->StretchRect(source, &source_rect, dest, &dest_rect, D3DTEXF_NONE); 76 77 } 78 79 LPDIRECT3DSURFACE9 LoadSurface(string filename) 80 { 81 LPDIRECT3DSURFACE9 image = NULL; 82 83 //get width and height from bitmap file 84 D3DXIMAGE_INFO info; 85 HRESULT result = D3DXGetImageInfoFromFile(filename.c_str(), &info); 86 if (result != D3D_OK) 87 return NULL; 88 89 //create surface 90 result = d3ddev->CreateOffscreenPlainSurface( 91 info.Width, //width of the surface 92 info.Height, //height of the surface 93 D3DFMT_X8R8G8B8, //surface format 94 D3DPOOL_DEFAULT, //memory pool to use 95 &image, //pointer to the surface 96 NULL); //reserved (always NULL) 97 98 if (result != D3D_OK) return NULL; 99 100 //load surface from file into newly created surface 101 result = D3DXLoadSurfaceFromFile( 102 image, //destination surface 103 NULL, //destination palette 104 NULL, //destination rectangle 105 filename.c_str(), //source filename 106 NULL, //source rectangle 107 D3DX_DEFAULT, //controls how image is filtered 108 D3DCOLOR_XRGB(0, 0, 0), //for transparency (0 for none) 109 NULL); //source image info (usually NULL) 110 111 //make sure file was loaded okay 112 if (result != D3D_OK) return NULL; 113 114 return image; 115 } 116 117 118 D3DXVECTOR2 GetBitmapSize(string filename) 119 { 120 D3DXIMAGE_INFO info; 121 D3DXVECTOR2 size = D3DXVECTOR2(0.0f, 0.0f); 122 123 HRESULT result = D3DXGetImageInfoFromFile(filename.c_str(), &info); 124 125 if (result == D3D_OK) 126 size = D3DXVECTOR2((float)info.Width, (float)info.Height); 127 else 128 size = D3DXVECTOR2((float)info.Width, (float)info.Height); 129 130 return size; 131 } 132 133 LPDIRECT3DTEXTURE9 LoadTexture(std::string filename, D3DCOLOR transcolor) 134 { 135 LPDIRECT3DTEXTURE9 texture = NULL; 136 137 //get width and height from bitmap file 138 D3DXIMAGE_INFO info; 139 HRESULT result = D3DXGetImageInfoFromFile(filename.c_str(), &info); 140 if (result != D3D_OK) return NULL; 141 142 //create the new texture by loading a bitmap image file 143 D3DXCreateTextureFromFileEx( 144 d3ddev, //Direct3D device object 145 filename.c_str(), //bitmap filename 146 info.Width, //bitmap image width 147 info.Height, //bitmap image height 148 1, //mip-map levels (1 for no chain) 149 D3DPOOL_DEFAULT, //the type of surface (standard) 150 D3DFMT_UNKNOWN, //surface format (default) 151 D3DPOOL_DEFAULT, //memory class for the texture 152 D3DX_DEFAULT, //image filter 153 D3DX_DEFAULT, //mip filter 154 transcolor, //color key for transparency 155 &info, //bitmap file info (from loaded file) 156 NULL, //color palette 157 &texture); //destination texture 158 159 //make sure the bitmap textre was loaded correctly 160 if (result != D3D_OK) return NULL; 161 162 return texture; 163 } 164 165 166 bool DirectInput_Init(HWND hwnd) 167 { 168 //initialize DirectInput object 169 DirectInput8Create( 170 GetModuleHandle(NULL), 171 DIRECTINPUT_VERSION, 172 IID_IDirectInput8, 173 (void**)&dinput, 174 NULL); 175 176 //initialize the keyboard 177 dinput->CreateDevice(GUID_SysKeyboard, &dikeyboard, NULL); 178 dikeyboard->SetDataFormat(&c_dfDIKeyboard); 179 dikeyboard->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); 180 dikeyboard->Acquire(); 181 182 //initialize the mouse 183 dinput->CreateDevice(GUID_SysMouse, &dimouse, NULL); 184 dimouse->SetDataFormat(&c_dfDIMouse); 185 dimouse->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); 186 dimouse->Acquire(); 187 d3ddev->ShowCursor(false); 188 189 return true; 190 } 191 192 void DirectInput_Update() 193 { 194 //update mouse 195 dimouse->Poll(); 196 if (!SUCCEEDED(dimouse->GetDeviceState(sizeof(DIMOUSESTATE), &mouse_state))) 197 { 198 //mouse device lose, try to re-acquire 199 dimouse->Acquire(); 200 } 201 202 //update keyboard 203 dikeyboard->Poll(); 204 if (!SUCCEEDED(dikeyboard->GetDeviceState(256, (LPVOID)&keys))) 205 { 206 //keyboard device lost, try to re-acquire 207 dikeyboard->Acquire(); 208 } 209 210 //update controllers 211 for (int i = 0; i< 4; i++) 212 { 213 ZeroMemory(&controllers[i], sizeof(XINPUT_STATE)); 214 215 //get the state of the controller 216 XINPUT_STATE state; 217 DWORD result = XInputGetState(i, &state); 218 219 //store state in global controllers array 220 if (result == 0) controllers[i] = state.Gamepad; 221 } 222 } 223 224 225 int Mouse_X() 226 { 227 return mouse_state.lX; 228 } 229 230 int Mouse_Y() 231 { 232 return mouse_state.lY; 233 } 234 235 int Mouse_Button(int button) 236 { 237 return mouse_state.rgbButtons[button] & 0x80; 238 } 239 240 bool Key_Down(int key) 241 { 242 return (bool)(keys[key] & 0x80); 243 } 244 245 246 void DirectInput_Shutdown() 247 { 248 if (dikeyboard) 249 { 250 dikeyboard->Unacquire(); 251 dikeyboard->Release(); 252 dikeyboard = NULL; 253 } 254 if (dimouse) 255 { 256 dimouse->Unacquire(); 257 dimouse->Release(); 258 dimouse = NULL; 259 } 260 } 261 262 bool XInput_Controller_Found() 263 { 264 XINPUT_CAPABILITIES caps; 265 ZeroMemory(&caps, sizeof(XINPUT_CAPABILITIES)); 266 XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps); 267 if (caps.Type != 0) return false; 268 269 return true; 270 } 271 272 void XInput_Vibrate(int contNum, int amount) 273 { 274 XINPUT_VIBRATION vibration; 275 ZeroMemory(&vibration, sizeof(XINPUT_VIBRATION)); 276 vibration.wLeftMotorSpeed = amount; 277 vibration.wRightMotorSpeed = amount; 278 XInputSetState(contNum, &vibration); 279 } 280 void Sprite_Draw_Frame(LPDIRECT3DTEXTURE9 texture, int destx, int desty, int framenum, int framew, int frameh, int columns) 281 { 282 D3DXVECTOR3 position((float)destx, (float)desty, 0); 283 D3DCOLOR white = D3DCOLOR_XRGB(255, 255, 255); 284 285 RECT rect; 286 rect.left = (framenum % columns) * framew; 287 rect.top = (framenum / columns) * frameh; 288 rect.right = rect.left + framew; 289 rect.bottom = rect.top + frameh; 290 291 spriteobj->Draw(texture, &rect, NULL, &position, white); 292 } 293 294 void Sprite_Animate(int &frame, int startframe, int endframe, int direction, int &starttime, int delay) 295 { 296 if ((int)GetTickCount() > starttime + delay) 297 { 298 starttime = GetTickCount(); 299 300 frame += direction; 301 if (frame > endframe) frame = startframe; 302 if (frame < startframe) frame = endframe; 303 } 304 } 305 void Sprite_Transform_Draw(LPDIRECT3DTEXTURE9 image, int x, int y, int width, int height, int frame, int columns, float rotation, float scaling, D3DCOLOR color) 306 { 307 //create a scale vector 308 D3DXVECTOR2 scale(scaling, scaling); 309 //create a translate vector 310 D3DXVECTOR2 trans(x, y); 311 //set center by dividing width and height by two 312 D3DXVECTOR2 center((float)(width * scaling) / 2, (float)(height * scaling) / 2); 313 //create 2D transformation matrix 314 D3DXMATRIX mat; 315 D3DXMatrixTransformation2D(&mat, NULL, 0, &scale, ¢er, rotation, &trans); 316 317 //tell sprite object to use the transform 318 spriteobj->SetTransform(&mat); 319 //calculate frame location in source image 320 int fx = (frame % columns) * width; 321 int fy = (frame / columns) * height; 322 RECT srcRect = { fx, fy, fx + width, fy + height }; 323 //draw the sprite frame 324 spriteobj->Draw(image, &srcRect, NULL, NULL, color); 325 } 326 327 //bouding box collision detection 328 int Collision(SPRITE sprite1, SPRITE sprite2) 329 { 330 RECT rect1; 331 rect1.left = (long)sprite1.x; 332 rect1.top = (long)sprite1.y; 333 rect1.right = (long)sprite1.x + sprite1.width + sprite1.scaling; 334 rect1.bottom = (long)sprite1.y + sprite1.height + sprite1.scaling; 335 336 RECT rect2; 337 rect2.left = (long)sprite2.x; 338 rect2.top = (long)sprite2.y; 339 rect2.right = (long)sprite2.x + sprite2.width + sprite2.scaling; 340 rect2.bottom = (long)sprite2.y + sprite2.height + sprite2.scaling; 341 342 RECT dest; //ignored 343 return IntersectRect(&dest, &rect1, &rect2); 344 }
MyGame.cpp:
1 #include "MyDirectX.h" 2 3 const string APPTITLE = "Bounding Box Demo"; 4 const int SCREENW = 1024; 5 const int SCREENH = 768; 6 SPRITE ship, asteroid1, asteroid2; 7 LPDIRECT3DTEXTURE9 imgShip = NULL; 8 LPDIRECT3DTEXTURE9 imgAsteroid = NULL; 9 10 bool Game_Init(HWND window) 11 { 12 //initialize Direct3D 13 if (!Direct3D_Init(window, SCREENW, SCREENH, false)) 14 { 15 MessageBox(0, "Error initializing Direct3D", "ERROR", 0); 16 return false; 17 } 18 19 //initialize DirectInput 20 if (!DirectInput_Init(window)) 21 { 22 MessageBox(0, "Error initializing DirectInput", "ERROR", 0); 23 return false; 24 } 25 //load the sprite texture 26 imgShip = LoadTexture("fatship.tga"); 27 if (!imgShip) return false; 28 imgAsteroid = LoadTexture("asteroid.tga"); 29 if (!imgAsteroid) return false; 30 31 //set properties for sprites 32 ship.x = 450; 33 ship.y = 300; 34 ship.width = ship.height = 128; 35 36 asteroid1.x = 50; 37 asteroid1.y = 200; 38 asteroid1.width = asteroid1.height = 60; 39 asteroid1.columns = 8; 40 asteroid1.startframe = 0; 41 asteroid1.endframe = 63; 42 asteroid1.velx = -2.0f; 43 44 asteroid2.x = 900; 45 asteroid2.y = 500; 46 asteroid2.width = asteroid2.height = 60; 47 asteroid2.columns = 8; 48 asteroid2.startframe = 0; 49 asteroid2.endframe = 63; 50 asteroid2.velx = 2.0f; 51 52 return true; 53 } 54 55 void Game_Run(HWND window) 56 { 57 //make sure the Direct3D device is valid 58 if (!d3ddev) return; 59 60 //update input devices 61 DirectInput_Update(); 62 63 //clear the scene 64 d3ddev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 100), 1.0f, 0); 65 66 //move the ship up/down with arrow keys 67 if (Key_Down(DIK_UP)) 68 { 69 ship.y -= 1.0f; 70 if (ship.y < 0) 71 ship.y = 0; 72 } 73 if (Key_Down(DIK_DOWN)) 74 { 75 ship.y += 1.0f; 76 if (ship.y > SCREENH - ship.height) 77 ship.y = SCREENH - ship.height; 78 } 79 80 //move and animate the asteroids 81 asteroid1.x += asteroid1.velx; 82 if (asteroid1.x<0 || asteroid1.x>SCREENW - asteroid1.width) 83 asteroid1.velx *= -1; 84 Sprite_Animate(asteroid1.frame, asteroid1.startframe, asteroid1.endframe, asteroid1.direction, asteroid1.starttime, asteroid1.delay); 85 86 asteroid2.x += asteroid2.velx; 87 if (asteroid2.x<0 || asteroid2.x>SCREENW - asteroid2.width) 88 asteroid2.velx *= -1; 89 Sprite_Animate(asteroid2.frame, asteroid2.startframe, asteroid2.endframe, asteroid2.direction, asteroid2.starttime, asteroid2.delay); 90 91 //test for collisions 92 if (Collision(ship, asteroid1)) 93 asteroid1.velx *= -1; 94 if (Collision(ship, asteroid2)) 95 asteroid2.velx *= -1; 96 97 //start rendering 98 if (d3ddev->BeginScene()) 99 { 100 //begin sprite rendering 101 spriteobj->Begin(D3DXSPRITE_ALPHABLEND); 102 Sprite_Transform_Draw(imgShip, ship.x, ship.y, ship.width, ship.height, ship.frame, ship.columns); 103 Sprite_Transform_Draw(imgAsteroid, asteroid1.x, asteroid1.y, asteroid1.width, asteroid1.height, asteroid1.frame, asteroid1.columns); 104 Sprite_Transform_Draw(imgAsteroid, asteroid2.x, asteroid2.y, asteroid2.width, asteroid2.height, asteroid2.frame, asteroid2.columns); 105 106 //stop sprite rendering 107 spriteobj->End(); 108 //stop rendering 109 d3ddev->EndScene(); 110 d3ddev->Present(NULL, NULL, NULL, NULL); 111 } 112 113 //Escape key ends program 114 if (KEY_DOWN(VK_ESCAPE)) gameover = true; 115 116 //controller Back button also ends 117 if (controllers[0].wButtons & XINPUT_GAMEPAD_BACK) 118 gameover = true; 119 } 120 121 void Game_End() 122 { 123 //free memory and shut down 124 if (imgShip) imgShip->Release(); 125 if (imgAsteroid) imgAsteroid->Release(); 126 127 DirectInput_Shutdown(); 128 Direct3D_Shutdown(); 129 }
MyWindows.cpp:
1 #include "MyDirectX.h" 2 using namespace std; 3 bool gameover = false; 4 5 6 LRESULT WINAPI WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 7 { 8 switch (msg) 9 { 10 case WM_DESTROY: 11 gameover = true; 12 PostQuitMessage(0); 13 return 0; 14 } 15 return DefWindowProc(hWnd, msg, wParam, lParam); 16 } 17 18 19 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 20 { 21 //initialize window settings 22 WNDCLASSEX wc; 23 wc.cbSize = sizeof(WNDCLASSEX); 24 wc.style = CS_HREDRAW | CS_VREDRAW; 25 wc.lpfnWndProc = (WNDPROC)WinProc; 26 wc.cbClsExtra = 0; 27 wc.cbWndExtra = 0; 28 wc.hInstance = hInstance; 29 wc.hIcon = NULL; 30 wc.hCursor = LoadCursor(NULL, IDC_ARROW); 31 wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 32 wc.lpszMenuName = NULL; 33 wc.lpszClassName = APPTITLE.c_str(); 34 wc.hIconSm = NULL; 35 RegisterClassEx(&wc); 36 37 //create a new window 38 HWND window = CreateWindow(APPTITLE.c_str(), APPTITLE.c_str(), 39 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 40 SCREENW, SCREENH, NULL, NULL, hInstance, NULL); 41 if (window == 0) return 0; 42 43 //display the window 44 ShowWindow(window, nCmdShow); 45 UpdateWindow(window); 46 47 //initialize the game 48 if (!Game_Init(window)) return 0; 49 50 // main message loop 51 MSG message; 52 while (!gameover) 53 { 54 if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) 55 { 56 TranslateMessage(&message); 57 DispatchMessage(&message); 58 } 59 60 //process game loop 61 Game_Run(window); 62 } 63 64 //shutdown 65 Game_End(); 66 return message.wParam; 67 }
结果:
当然了,边界碰撞检测产生相当精确的碰撞结果,而且非常快速。但是有些情况下这种方法不能很好的适应,比如使用带有圆角的美工作品或非常复杂的形状(比如带有突出机翼的飞机)。
在非常情况下,具有另外一种检测碰撞的方法僵尸有好处的,而在这种情况下我们可以使用级与距离的碰撞算法。
在使用距离确定两个精灵是否碰撞时,我们必须要做的是计算每个精灵中心点,计算精灵的半径(从中心点到边缘),然后检查两个中心点之间的距离。如果这个距离少于两个半径的
和,那么就可以确定两个精灵有重叠。为什么呢?每个精灵的半径加起来必须小于两个精灵之间的距离。
(1)计算距离:
要计算任意两点之间的距离,我们只需参考经典的数学距离公式即可。通过将两点作为直角三角形两条边的顶点,任意两点都可转换成直角三角形。取得每个点的X和
Y的delta值(差值),将每个delta值平方然后相加,然后求其平方根,就是两点间的距离。如下图:
delta_x = x1 - x2
delta_y = y1 - y2
distance = square root ((delta_x * delta_x) + (delta_y * delta_y))
(2)编写距离计算的代码:
我们可以把这些内容编写到函数中,它使用两个精灵作为参数并从精灵的属性计算出delta值和距离。缩放因子也必须考虑在内,就如在边界框碰撞检测中所作的一样。
此外,精灵的最大尺寸(不是宽度就是高度)将用于计算半径。我们首先计算第一个精灵的半径。
1 if (sprite1.width > sprite1.height) 2 radius1 = (sprite1.width * sprite1.scaling) / 2.0; 3 else 4 radius1 = (sprite1.height * sprite1.scaling) / 2.0;
有了半径之后,在计算第一个精灵的中心点。我将把中心值存储存在的向量中。
1 double x1 = sprite1.x + radius1; 2 double y1 = sprite1.y + radius1; 3 D3DXVECTOR2 vector1(x1, y1);
这个名为vector1的向量包含了第一个精灵的中心点,无论他是否为与屏幕上。经相同的代码复制给第二个精灵,我们就会得到两个精灵的中心点和半径。一旦有了这
些值,就可以开始进行距离计算了。首先涉及的是计算X和Y的delta值。
1 double deltax = vector1.x - vector2.x; 2 double deltay = vector2.y - vector1.y;
有了这些delta值之后计算距离那就是非常容易的事情了。
1 double dist = sqrt((deltax * deltax) + (deltay * deltay));
我们将此编写到一个可重用的函数中。我将这个命名为CollisionD以便与边界框(Collision)区分开
1 bool CollisionD(SPRITE sprite1, SPRITE sprite2) 2 { 3 double radius1, radius2; 4 5 //calculate radius 1 6 if (sprite1.width > sprite1.height) 7 radius1 = (sprite1.width * sprite1.scaling) / 2.0; 8 else 9 radius1 = (sprite1.height * sprite1.scaling) / 2.0; 10 11 //center point 1 12 double x1 = sprite1.x + radius1; 13 double y1 = sprite1.y + radius1; 14 D3DXVECTOR2 vector1(x1, y1); 15 16 //calculate radius 2 17 if (sprite2.width > sprite2.height) 18 radius2 = (sprite2.width * sprite2.scaling) / 2.0; 19 else 20 radius2 = (sprite2.height * sprite2.scaling) / 2.0; 21 22 //center point 2 23 double x2 = sprite2.x + radius2; 24 double y2 = sprite2.y + radius2; 25 D3DXVECTOR2 vector2(x2, y2); 26 27 //calculate distance 28 double deltax = vector1.x - vector2.x; 29 double deltay = vector2.y - vector1.y; 30 double dist = sqrt((deltax * deltax) + (deltay * deltay)); 31 32 //return distance comparison 33 return (dist < radius1 + radius2); 34 }
现在正是将这个函数复制到框架中的时候,我们这就来做,将这个函数添加到MyDirectX.cpp中,将原形添加到MyDirectX.h中。
1 bool CollisionD(SPRITE sprite1, SPRITE sprite2);
和上面个那个函数效果是一致的