游戏编程入门之碰撞检测

在进行以下内容前我们需先做好准备,明白都要做什么

(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, &center, 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);

和上面个那个函数效果是一致的

猜你喜欢

转载自www.cnblogs.com/Trojan00/p/9562375.html