基于图片单元的D3DXSprite卷动实现2

在上一个例子中,我们使用了定义好的地图数据MAPDATA,但不清楚如何构造这样的数据。在这个例子中,继续讲述上一个例子的内容,书上把Tile-Based Static Scrolling改成了什么Tile-Based Dynamic Scrolling,其实代码没什么变化,只是这个MAPDATA已经变得很简单了。下面的DirectX.h文件基本没什么改变。

View Code
 1 #pragma once
 2 
 3 //header files
 4 #define WIN32_EXTRA_LEAN
 5 #define DIRECTINPUT_VERSION 0x0800
 6 #include <windows.h>
 7 #include <d3d9.h>
 8 #include <d3dx9.h>
 9 #include <dinput.h>
 10 #include <xinput.h>
 11 #include <ctime>
 12 #include <iostream>
 13 #include <iomanip>
 14 using namespace std;  15 
 16 //libraries
 17 #pragma comment(lib,"winmm.lib")
 18 #pragma comment(lib,"user32.lib")
 19 #pragma comment(lib,"gdi32.lib")
 20 #pragma comment(lib,"dxguid.lib")
 21 #pragma comment(lib,"d3d9.lib")
 22 #pragma comment(lib,"d3dx9.lib")
 23 #pragma comment(lib,"dinput8.lib")
 24 #pragma comment(lib,"xinput.lib")
 25 
 26 //program values
 27 extern const string APPTITLE;  28 extern const int SCREENW;  29 extern const int SCREENH;  30 extern bool gameover;  31 
 32 //macro to detect key presses
 33 #define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
 34 
 35 //Direct3D objects
 36 extern LPDIRECT3D9 d3d;  37 extern LPDIRECT3DDEVICE9 d3ddev;  38 extern LPDIRECT3DSURFACE9 backbuffer;  39 extern LPD3DXSPRITE spriteobj;  40 
 41 //sprite structure
 42 struct SPRITE  43 {  44     float x,y;  45     int frame, columns;  46     int width, height;  47     float scaling, rotation;  48     int startframe, endframe;  49     int starttime, delay;  50     int direction;  51     float velx, vely;  52  D3DCOLOR color;  53 
 54  SPRITE()  55  {  56         frame = 0;  57         columns = 1;  58         width = height = 0;  59         scaling = 1.0f;  60         rotation = 0.0f;  61         startframe = endframe = 0;  62         direction = 1;  63         starttime = delay = 0;  64         velx = vely = 0.0f;  65         color = D3DCOLOR_XRGB(255,255,255);  66  }  67 };  68 
 69 //Direct3D functions
 70 bool Direct3D_Init(HWND hwnd, int width, int height, bool fullscreen);  71 void Direct3D_Shutdown();  72 LPDIRECT3DSURFACE9 LoadSurface(string filename);  73 void DrawSurface(LPDIRECT3DSURFACE9 dest, float x, float y, LPDIRECT3DSURFACE9 source);  74 LPDIRECT3DTEXTURE9 LoadTexture(string filename, D3DCOLOR transcolor = D3DCOLOR_XRGB(0,0,0));  75 void Sprite_Draw_Frame(LPDIRECT3DTEXTURE9 texture, int destx, int desty,  76     int framenum, int framew, int frameh, int columns);  77 void Sprite_Animate(int &frame, int startframe, int endframe, int direction, int &starttime, int delay);  78 
 79 void Sprite_Transform_Draw(LPDIRECT3DTEXTURE9 image, int x, int y, int width, int height,  80     int frame = 0, int columns = 1, float rotation = 0.0f, float scaling = 1.0f,  81     D3DCOLOR color = D3DCOLOR_XRGB(255,255,255));  82 
 83 //bounding box collision detection
 84 int Collision(SPRITE sprite1, SPRITE sprite2);  85 
 86 //distance based collision detection
 87 bool CollisionD(SPRITE sprite1, SPRITE sprite2);  88 
 89 //DirectInput objects, devices, and states
 90 extern LPDIRECTINPUT8 dinput;  91 extern LPDIRECTINPUTDEVICE8 dimouse;  92 extern LPDIRECTINPUTDEVICE8 dikeyboard;  93 extern DIMOUSESTATE mouse_state;  94 extern XINPUT_GAMEPAD controllers[4];  95 
 96 //DirectInput functions
 97 bool DirectInput_Init(HWND);  98 void DirectInput_Update();  99 void DirectInput_Shutdown(); 100 bool Key_Down(int); 101 int Mouse_Button(int); 102 int Mouse_X(); 103 int Mouse_Y(); 104 void XInput_Vibrate(int contNum = 0, int amount = 65535); 105 bool XInput_Controller_Found(); 106 
107 //game functions
108 bool Game_Init(HWND window); 109 void Game_Run(HWND window); 110 void Game_End(); 111 
112 
113 //font functions
114 LPD3DXFONT MakeFont(string name, int size); 115 void FontPrint(LPD3DXFONT font, int x, int y, string text, D3DCOLOR color = D3DCOLOR_XRGB(255,255,255));


接着的DirectX.cpp文件也没什么改变

View Code
 1 #include "DirectX.h"
 2 #include <iostream>
 3 #include <string>
 4 using namespace std;  5 
 6 //Direct3D variables
 7 LPDIRECT3D9 d3d = NULL;  8 LPDIRECT3DDEVICE9 d3ddev = NULL;  9 LPDIRECT3DSURFACE9 backbuffer = NULL;  10 LPD3DXSPRITE spriteobj;  11 
 12 //DirectInput variables
 13 LPDIRECTINPUT8 dinput = NULL;  14 LPDIRECTINPUTDEVICE8 dimouse = NULL;  15 LPDIRECTINPUTDEVICE8 dikeyboard = NULL;  16 DIMOUSESTATE mouse_state;  17 char keys[256];  18 XINPUT_GAMEPAD controllers[4];  19 
 20 
 21 bool Direct3D_Init(HWND window, int width, int height, bool fullscreen)  22 {  23     //initialize Direct3D
 24     d3d = Direct3DCreate9(D3D_SDK_VERSION);  25     if (!d3d) return false;  26 
 27     //set Direct3D presentation parameters
 28  D3DPRESENT_PARAMETERS d3dpp;  29     ZeroMemory(&d3dpp, sizeof(d3dpp));  30     d3dpp.hDeviceWindow = window;  31     d3dpp.Windowed = (!fullscreen);  32     d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;  33     d3dpp.EnableAutoDepthStencil = 1;  34     d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;  35     d3dpp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;  36     d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;  37     d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;  38     d3dpp.BackBufferCount = 1;  39     d3dpp.BackBufferWidth = width;  40     d3dpp.BackBufferHeight = height;  41 
 42     //create Direct3D device
 43     d3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window,  44         D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev);  45     if (!d3ddev) return false;  46 
 47 
 48     //get a pointer to the back buffer surface
 49     d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);  50 
 51     //create sprite object
 52     D3DXCreateSprite(d3ddev, &spriteobj);  53 
 54     return 1;  55 }  56 
 57 void Direct3D_Shutdown()  58 {  59     if (spriteobj) spriteobj->Release();  60 
 61     if (d3ddev) d3ddev->Release();  62     if (d3d) d3d->Release();  63 }  64 
 65 void DrawSurface(LPDIRECT3DSURFACE9 dest, float x, float y, LPDIRECT3DSURFACE9 source)  66 {  67     //get width/height from source surface
 68  D3DSURFACE_DESC desc;  69     source->GetDesc(&desc);  70 
 71     //create rects for drawing
 72     RECT source_rect = {0, 0, (long)desc.Width, (long)desc.Height };  73     RECT dest_rect = { (long)x, (long)y, (long)x+desc.Width, (long)y+desc.Height};  74     
 75     //draw the source surface onto the dest
 76     d3ddev->StretchRect(source, &source_rect, dest, &dest_rect, D3DTEXF_NONE);  77 
 78 }  79 
 80 LPDIRECT3DSURFACE9 LoadSurface(string filename)  81 {  82     LPDIRECT3DSURFACE9 image = NULL;  83     
 84     //get width and height from bitmap file
 85  D3DXIMAGE_INFO info;  86     HRESULT result = D3DXGetImageInfoFromFile(filename.c_str(), &info);  87     if (result != D3D_OK)  88         return NULL;  89 
 90     //create surface
 91     result = d3ddev->CreateOffscreenPlainSurface(  92         info.Width,         //width of the surface
 93         info.Height,        //height of the surface
 94         D3DFMT_X8R8G8B8,    //surface format
 95         D3DPOOL_DEFAULT,    //memory pool to use
 96         &image,             //pointer to the surface
 97         NULL);              //reserved (always NULL)
 98 
 99     if (result != D3D_OK) return NULL; 100 
101     //load surface from file into newly created surface
102     result = D3DXLoadSurfaceFromFile( 103         image,                  //destination surface
104         NULL,                   //destination palette
105         NULL,                   //destination rectangle
106         filename.c_str(),       //source filename
107         NULL,                   //source rectangle
108         D3DX_DEFAULT,           //controls how image is filtered
109         D3DCOLOR_XRGB(0,0,0),   //for transparency (0 for none)
110         NULL);                  //source image info (usually NULL) 111 
112     //make sure file was loaded okay
113     if (result != D3D_OK) return NULL; 114 
115     return image; 116 } 117 
118 
119 LPDIRECT3DTEXTURE9 LoadTexture(std::string filename, D3DCOLOR transcolor) 120 { 121     LPDIRECT3DTEXTURE9 texture = NULL; 122 
123     //get width and height from bitmap file
124  D3DXIMAGE_INFO info; 125     HRESULT result = D3DXGetImageInfoFromFile(filename.c_str(), &info); 126     if (result != D3D_OK) return NULL; 127 
128     //create the new texture by loading a bitmap image file
129  D3DXCreateTextureFromFileEx( 130         d3ddev,                //Direct3D device object
131         filename.c_str(),      //bitmap filename
132         info.Width,            //bitmap image width
133         info.Height,           //bitmap image height
134         1,                     //mip-map levels (1 for no chain)
135         D3DPOOL_DEFAULT,       //the type of surface (standard)
136         D3DFMT_UNKNOWN,        //surface format (default)
137         D3DPOOL_DEFAULT,       //memory class for the texture
138         D3DX_DEFAULT,          //image filter
139         D3DX_DEFAULT,          //mip filter
140         transcolor,            //color key for transparency
141         &info,                 //bitmap file info (from loaded file)
142         NULL,                  //color palette
143         &texture );            //destination texture 144 
145     //make sure the bitmap textre was loaded correctly
146     if (result != D3D_OK) return NULL; 147 
148     return texture; 149 } 150 
151 
152 void Sprite_Draw_Frame(LPDIRECT3DTEXTURE9 texture, int destx, int desty, int framenum, int framew, int frameh, int columns) 153 { 154     D3DXVECTOR3 position( (float)destx, (float)desty, 0 ); 155     D3DCOLOR white = D3DCOLOR_XRGB(255,255,255); 156 
157  RECT rect; 158      rect.left = (framenum % columns) * framew; 159     rect.top = (framenum / columns) * frameh; 160     rect.right = rect.left + framew; 161     rect.bottom = rect.top + frameh; 162 
163     spriteobj->Draw( texture, &rect, NULL, &position, white); 164 } 165 
166 void Sprite_Animate(int &frame, int startframe, int endframe, int direction, int &starttime, int delay) 167 { 168     if ((int)GetTickCount() > starttime + delay) 169  { 170         starttime = GetTickCount(); 171 
172         frame += direction; 173         if (frame > endframe) frame = startframe; 174         if (frame < startframe) frame = endframe; 175  } 176 } 177 void Sprite_Transform_Draw(LPDIRECT3DTEXTURE9 image, int x, int y, int width, int height, 178     int frame, int columns, float rotation, float scaling, D3DCOLOR color) 179 { 180     //create a scale vector
181  D3DXVECTOR2 scale( scaling, scaling ); 182 
183     //create a translate vector
184  D3DXVECTOR2 trans( x, y ); 185 
186     //set center by dividing width and height by two
187     D3DXVECTOR2 center( (float)( width * scaling )/2, (float)( height * scaling )/2); 188 
189     //create 2D transformation matrix
190  D3DXMATRIX mat; 191     D3DXMatrixTransformation2D( &mat, NULL, 0, &scale, &center, rotation, &trans ); 192     
193     //tell sprite object to use the transform
194     spriteobj->SetTransform( &mat ); 195 
196     //calculate frame location in source image
197     int fx = (frame % columns) * width; 198     int fy = (frame / columns) * height; 199     RECT srcRect = {fx, fy, fx + width, fy + height}; 200 
201     //draw the sprite frame
202     spriteobj->Draw( image, &srcRect, NULL, NULL, color ); 203 } 204 
205 //bounding box collision detection
206 int Collision(SPRITE sprite1, SPRITE sprite2) 207 { 208  RECT rect1; 209     rect1.left = (long)sprite1.x; 210     rect1.top = (long)sprite1.y; 211     rect1.right = (long)sprite1.x + sprite1.width * sprite1.scaling; 212     rect1.bottom = (long)sprite1.y + sprite1.height * sprite1.scaling; 213 
214  RECT rect2; 215     rect2.left = (long)sprite2.x; 216     rect2.top = (long)sprite2.y; 217     rect2.right = (long)sprite2.x + sprite2.width * sprite2.scaling; 218     rect2.bottom = (long)sprite2.y + sprite2.height * sprite2.scaling; 219 
220     RECT dest; //ignored
221     return IntersectRect(&dest, &rect1, &rect2); 222 } 223 
224 
225 bool CollisionD(SPRITE sprite1, SPRITE sprite2) 226 { 227     double radius1, radius2; 228 
229     //calculate radius 1
230     if (sprite1.width > sprite1.height) 231         radius1 = (sprite1.width * sprite1.scaling) / 2.0; 232     else
233         radius1 = (sprite1.height * sprite1.scaling) / 2.0; 234 
235     //center point 1
236     double x1 = sprite1.x + radius1; 237     double y1 = sprite1.y + radius1; 238  D3DXVECTOR2 vector1(x1, y1); 239 
240     //calculate radius 2
241     if (sprite2.width > sprite2.height) 242         radius2 = (sprite2.width * sprite2.scaling) / 2.0; 243     else
244         radius2 = (sprite2.height * sprite2.scaling) / 2.0; 245 
246     //center point 2
247     double x2 = sprite2.x + radius2; 248     double y2 = sprite2.y + radius2; 249  D3DXVECTOR2 vector2(x2, y2); 250 
251     //calculate distance
252     double deltax = vector1.x - vector2.x; 253     double deltay = vector2.y - vector1.y; 254     double dist = sqrt((deltax * deltax) + (deltay * deltay)); 255 
256     //return distance comparison
257     return (dist < radius1 + radius2); 258 } 259 
260 bool DirectInput_Init(HWND hwnd) 261 { 262     //initialize DirectInput object
263  DirectInput8Create( 264  GetModuleHandle(NULL), 265  DIRECTINPUT_VERSION, 266  IID_IDirectInput8, 267         (void**)&dinput, 268  NULL); 269 
270     //initialize the keyboard
271     dinput->CreateDevice(GUID_SysKeyboard, &dikeyboard, NULL); 272     dikeyboard->SetDataFormat(&c_dfDIKeyboard); 273     dikeyboard->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); 274     dikeyboard->Acquire(); 275 
276     //initialize the mouse
277     dinput->CreateDevice(GUID_SysMouse, &dimouse, NULL); 278     dimouse->SetDataFormat(&c_dfDIMouse); 279     dimouse->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); 280     dimouse->Acquire(); 281     d3ddev->ShowCursor(false); 282 
283     return true; 284 } 285 
286 void DirectInput_Update() 287 { 288     //update mouse
289     dimouse->Poll(); 290     if (!SUCCEEDED(dimouse->GetDeviceState(sizeof(DIMOUSESTATE),&mouse_state))) 291  { 292         //mouse device lose, try to re-acquire
293         dimouse->Acquire(); 294  } 295 
296     //update keyboard
297     dikeyboard->Poll(); 298     if (!SUCCEEDED(dikeyboard->GetDeviceState(256,(LPVOID)&keys))) 299  { 300         //keyboard device lost, try to re-acquire
301         dikeyboard->Acquire(); 302  } 303 
304     //update controllers
305     for (int i=0; i< 4; i++ ) 306  { 307         ZeroMemory( &controllers[i], sizeof(XINPUT_STATE) ); 308 
309         //get the state of the controller
310  XINPUT_STATE state; 311         DWORD result = XInputGetState( i, &state ); 312 
313         //store state in global controllers array
314         if (result == 0) controllers[i] = state.Gamepad; 315  } 316 } 317 
318 
319 int Mouse_X() 320 { 321     return mouse_state.lX; 322 } 323 
324 int Mouse_Y() 325 { 326     return mouse_state.lY; 327 } 328 
329 int Mouse_Button(int button) 330 { 331     return mouse_state.rgbButtons[button] & 0x80; 332 } 333 
334 bool Key_Down(int key) 335 { 336     return (bool)(keys[key] & 0x80); 337 } 338 
339 
340 void DirectInput_Shutdown() 341 { 342     if (dikeyboard) 343  { 344         dikeyboard->Unacquire(); 345         dikeyboard->Release(); 346         dikeyboard = NULL; 347  } 348     if (dimouse) 349  { 350         dimouse->Unacquire(); 351         dimouse->Release(); 352         dimouse = NULL; 353  } 354 } 355 
356 bool XInput_Controller_Found() 357 { 358  XINPUT_CAPABILITIES caps; 359     ZeroMemory(&caps, sizeof(XINPUT_CAPABILITIES)); 360     XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps); 361     if (caps.Type != 0) return false; 362     
363     return true; 364 } 365 
366 void XInput_Vibrate(int contNum, int amount) 367 { 368  XINPUT_VIBRATION vibration; 369     ZeroMemory( &vibration, sizeof(XINPUT_VIBRATION) ); 370     vibration.wLeftMotorSpeed = amount; 371     vibration.wRightMotorSpeed = amount; 372     XInputSetState( contNum, &vibration ); 373 } 374 
375 LPD3DXFONT MakeFont(string name, int size) 376 { 377     LPD3DXFONT font = NULL; 378 
379     D3DXFONT_DESC desc = { 380         size,                   //height
381         0,                      //width
382         0,                      //weight
383         0,                      //miplevels
384         false,                  //italic
385         DEFAULT_CHARSET,        //charset
386         OUT_TT_PRECIS,          //output precision
387         CLIP_DEFAULT_PRECIS,    //quality
388         DEFAULT_PITCH,          //pitch and family
389         ""                      //font name
390  }; 391 
392  strcpy(desc.FaceName, name.c_str()); 393 
394     D3DXCreateFontIndirect(d3ddev, &desc, &font); 395 
396     return font; 397 } 398 
399 void FontPrint(LPD3DXFONT font, int x, int y, string text, D3DCOLOR color) 400 { 401     //figure out the text boundary
402     RECT rect = { x, y, 0, 0 }; 403     font->DrawText( NULL, text.c_str(), text.length(), &rect, DT_CALCRECT, color); 404 
405     //print the text
406     font->DrawText(spriteobj, text.c_str(), text.length(), &rect, DT_LEFT, color); 407 }


main.cpp文件没改变

View Code
 1 #include "DirectX.h"
 2 using namespace std;  3 
 4 bool gameover = false;  5 
 6 //windows event handling function
 7 LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)  8 {  9     switch (message) 10  { 11     case WM_DESTROY: 12         gameover = true; 13         PostQuitMessage(0); 14         return 0; 15  } 16 
17     return DefWindowProc(hwnd, message, wParam, lParam); 18 } 19 
20 
21 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR lpCmdLine, int nCmdShow) 22 { 23     //set the windows properties
24  WNDCLASSEX wc; 25     wc.cbSize = sizeof(WNDCLASSEX); 26     wc.style = CS_HREDRAW | CS_VREDRAW; 27     wc.lpfnWndProc = (WNDPROC)WinProc; 28     wc.cbClsExtra = 0; 29     wc.cbWndExtra = 0; 30     wc.hInstance = hInstance; 31     wc.hIcon = NULL; 32     wc.hCursor = LoadCursor(NULL, IDC_ARROW); 33     wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 34     wc.lpszMenuName = NULL; 35     wc.lpszClassName = APPTITLE.c_str(); 36     wc.hIconSm = NULL; 37     RegisterClassEx(&wc); 38 
39     //determine the resolution of the clients desktop screen
40     int screenWidth = GetSystemMetrics(SM_CXSCREEN); 41     int screenHeight = GetSystemMetrics(SM_CYSCREEN); 42 
43     //place the window in the middle of screen
44     int posX = (GetSystemMetrics(SM_CXSCREEN) - SCREENW) / 2; 45     int posY = (GetSystemMetrics(SM_CYSCREEN) - SCREENH) / 2; 46 
47     //Create a window
48  HWND window; 49     window = CreateWindow(APPTITLE.c_str(), APPTITLE.c_str(), 50         WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU, posX, posY, SCREENW, SCREENH, 51  NULL, NULL, hInstance, NULL); 52     if (window == 0) 53         return false; 54 
55     //display the window
56  ShowWindow(window, nCmdShow); 57  UpdateWindow(window); 58 
59     //initialize the game
60     if (!Game_Init(window)) 61         return 0; 62 
63     //main message loop
64  MSG msg; 65     while (!gameover) 66  { 67         //process windows events
68         if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 69  { 70             //handle any event messages
71             TranslateMessage(&msg); 72             DispatchMessage(&msg); 73  } 74 
75         //process game loop
76  Game_Run(window); 77  } 78 
79     //free game resources
80  Game_End(); 81 
82     return msg.wParam; 83 }


下面是game.cpp文件,先看开头部分。还是之前那些变量,但MAPDATA变化很大,从1到192,为了扩大地图,又加了1到192。作者这里使用的是Mappy这个地图软件,即这里使用的原始图片被分割为了192个方格。

 1 #include "DirectX.h"
 2 #include <sstream>
 3 using namespace std;  4 
 5 const string APPTITLE = "Tile-Based Dynamic Scrolling";  6 const int SCREENW = 800;  7 const int SCREENH = 600;  8 
 9 LPD3DXFONT font; 10 
11 //settings for the scroller
12 const int TILEWIDTH = 64; 13 const int TILEHEIGHT = 64; 14 const int MAPWIDTH = 16; 15 const int MAPHEIGHT = 24; 16 
17 //scrolling window size
18 const int WINDOWWIDTH = (SCREENW / TILEWIDTH) * TILEWIDTH; 19 const int WINDOWHEIGHT = (SCREENH / TILEHEIGHT) * TILEHEIGHT; 20 
21 const int GAMEWORLDWIDTH = TILEWIDTH * MAPWIDTH; 22 const int GAMEWORLDHEIGHT = TILEHEIGHT * MAPHEIGHT; 23 
24 int ScrollX, ScrollY; 25 int SpeedX, SpeedY; 26 long start; 27 LPDIRECT3DSURFACE9 scrollbuffer=NULL; 28 LPDIRECT3DSURFACE9 tiles=NULL; 29 
30 int MAPDATA[MAPWIDTH*MAPHEIGHT] = { 31 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25, 32 26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, 33 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69, 34 70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91, 35 92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109, 36 110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125, 37 126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141, 38 142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157, 39 158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173, 40 174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189, 41 190,191,192,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20, 42 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41, 43 42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62, 44 63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83, 45 84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103, 46 104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119, 47 120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135, 48 136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151, 49 152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167, 50 168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183, 51 184,185,186,187,188,189,190,191,192
52 };

 

接着是函数UpdateScrollPosition,和之前的代码没什么变化,只是放在了一个独立的函数中。ScrollX与ScrollY同样表示我们的窗口视图区在原始图片上的起始坐标,这里要检查视图区是否越界。

 1 //This function updates the scrolling position and speed
 2 void UpdateScrollPosition()  3 {  4     //update horizontal scrolling position and speed
 5     ScrollX += SpeedX;  6 
 7     if (ScrollX < 0)  8  {  9         ScrollX = 0; 10         SpeedX = 0; 11  } 12     else if (ScrollX > GAMEWORLDWIDTH - WINDOWWIDTH) 13  { 14         ScrollX = GAMEWORLDWIDTH - WINDOWWIDTH; 15         SpeedX = 0; 16  } 17     
18     //update vertical scrolling position and speed
19     ScrollY += SpeedY; 20     if (ScrollY < 0) 21  { 22         ScrollY = 0; 23         SpeedY = 0; 24  } 25     else if (ScrollY > GAMEWORLDHEIGHT - WINDOWHEIGHT) 26  { 27         ScrollY = GAMEWORLDHEIGHT - WINDOWHEIGHT; 28         SpeedY = 0; 29  } 30 }

 

接着是那个原先的函数DrawTile,没什么变化,就是绘制一个图片单元到指定的视图区域。

 1 //This function does the real work of drawing a single tile from the  2 //source image onto the tile scroll buffer. 
 3 void DrawTile(LPDIRECT3DSURFACE9 source,    // source surface image
 4                 int tilenum,                // tile #
 5                 int width,                    // tile width
 6                 int height,                    // tile height
 7                 int columns,                // columns of tiles
 8                 LPDIRECT3DSURFACE9 dest,    // destination surface
 9                 int destx,                    // destination x
10                 int desty)                    // destination y
11 { 12     
13     //create a RECT to describe the source image
14  RECT r1; 15     r1.left = (tilenum % columns) * width; 16     r1.top = (tilenum / columns) * height; 17     r1.right = r1.left + width; 18     r1.bottom = r1.top + height; 19     
20     //set destination rect
21     RECT r2 = {destx,desty,destx+width,desty+height}; 22     
23     //draw the tile 
24     d3ddev->StretchRect(source, &r1, dest, &r2, D3DTEXF_NONE); 25 }

 

下面的DrawTiles函数定义了新变量tilx与tiley,就表示在x与y方向上有多少个方格,用于决定图片单元的位置。我们看到下面的tilenum = MAPDATA[(tiley + y) * MAPWIDTH + (tilex + x)]这句,这里假设x与y都为0,既我们先在窗口中绘制第一块方格。然后有tiley * MAPWIDTH + tilex,MAPWIDTH表示有多少列方格,这里是16。再次假设要绘制的图片单元上面有2行图片单元,左边有3列图片单元,那么tiley就是2,tilex就是3,所以这个公式自然就决定了总共有多少个图片单元。最后在MAPDATA中直接取出这个值就可以了。

 1 //This function fills the tilebuffer with tiles representing  2 //the current scroll display based on scrollx/scrolly.
 3 void DrawTiles()  4 {  5     int tilex, tiley;  6     int columns, rows;  7     int x, y;  8     int tilenum;  9     
10     //calculate starting tile position
11     tilex = ScrollX / TILEWIDTH; 12     tiley = ScrollY / TILEHEIGHT; 13     
14     //calculate the number of columns and rows
15     columns = WINDOWWIDTH / TILEWIDTH; 16     rows = WINDOWHEIGHT / TILEHEIGHT; 17     
18     //draw tiles onto the scroll buffer surface
19     for (y=0; y<=rows; y++) 20  { 21         for (x=0; x<=columns; x++) 22  { 23             //retrieve the tile number from this position
24             tilenum = MAPDATA[((tiley + y) * MAPWIDTH + (tilex + x))]; 25 
26             //draw the tile onto the scroll buffer
27             DrawTile(tiles,tilenum,TILEWIDTH,TILEHEIGHT,16,scrollbuffer, 28                 x*TILEWIDTH,y*TILEHEIGHT); 29  } 30  } 31 }

 

下面是函数DrawScrollWindow,注意scrollbuffer与backbuffer这两个Direct3D表面,只有把scrollbuffer通过函数StretchRect绘制到backbuffer中才能在屏幕上显示。backbuffer是后台缓冲区,在Game_Init中初始化;scrollbuffer也在函数Game_Init中初始化,表示要绘制的卷动区域,在DrawTiles函数中把它作为目标区域。

 1 //This function draws the portion of the scroll buffer onto the back buffer  2 //according to the current "partial tile" scroll position.
 3 void DrawScrollWindow(bool scaled = false)  4 {  5     //calculate the partial sub-tile lines to draw using modulus
 6     int partialx = ScrollX % TILEWIDTH;  7     int partialy = ScrollY % TILEHEIGHT;  8     
 9     //set dimensions of the source image as a rectangle
10     RECT r1 = {partialx,partialy,partialx+WINDOWWIDTH-1,partialy+WINDOWHEIGHT-1}; 11         
12     //set the destination rectangle
13  RECT r2; 14     if (scaled) { 15         //use this line for scaled display
16         RECT r = {0, 0, WINDOWWIDTH-1, WINDOWHEIGHT-1}; 17         r2 = r; 18  } 19     else { 20         //use this line for non-scaled display
21         RECT r = {0, 0, SCREENW-1, SCREENH-1}; 22         r2 = r; 23  } 24 
25     //draw the "partial tile" scroll window onto the back buffer
26     d3ddev->StretchRect(scrollbuffer, &r1, backbuffer, &r2, D3DTEXF_NONE); 27 }

 

下面是初始化函数Game_Init,对tiles、backbuffer与scrollbuffer进行初始化,还有创建字体font。

 1 bool Game_Init(HWND window)  2 {  3     Direct3D_Init(window, SCREENW, SCREENH, false);  4  DirectInput_Init(window);  5 
 6     //create pointer to the back buffer
 7     d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);  8 
 9     //create a font
10     font = MakeFont("Arial", 24); 11 
12     //load the tile images
13     tiles = LoadSurface("spacemap.bmp"); 14     if (!tiles) return false; 15 
16     //create the scroll buffer surface in memory, slightly bigger 17     //than the screen
18     const int SCROLLBUFFERWIDTH = SCREENW + TILEWIDTH * 2; 19     const int SCROLLBUFFERHEIGHT = SCREENH + TILEHEIGHT * 2; 20 
21     HRESULT result = d3ddev->CreateOffscreenPlainSurface( 22  SCROLLBUFFERWIDTH, SCROLLBUFFERHEIGHT, 23  D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, 24         &scrollbuffer, 25  NULL); 26     if (result != S_OK) return false; 27 
28     start = GetTickCount(); 29 
30     return true; 31 }

 

 在程序运行了一次Game_Init函数后,就循环调用下面这个Game_Run函数,如果不清楚程序是如何运行的,可以仔细看看这个函数。

 1 void Game_Run(HWND window)  2 {  3     if (!d3ddev) return;  4  DirectInput_Update();  5     d3ddev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,100), 1.0f, 0);  6 
 7     //scroll based on key or controller input
 8     if (Key_Down(DIK_S))  9         ScrollY += 1; 10 
11     if (Key_Down(DIK_W)) 12         ScrollY -= 1; 13 
14     if (Key_Down(DIK_A)) 15         ScrollX -= 1; 16 
17     if (Key_Down(DIK_D)) 18         ScrollX += 1; 19 
20     //keep the game running at a steady frame rate
21     if (GetTickCount() - start >= 30) 22  { 23         //reset timing
24         start = GetTickCount(); 25 
26         //update the scrolling view
27  UpdateScrollPosition(); 28 
29         //start rendering
30         if (d3ddev->BeginScene()) 31  { 32             
33             //draw tiles onto the scroll buffer
34  DrawTiles(); 35 
36             //draw the scroll window onto the back buffer
37  DrawScrollWindow(); 38 
39 
40             spriteobj->Begin(D3DXSPRITE_ALPHABLEND); 41 
42  std::ostringstream oss; 43             oss << "Scroll Position = " << ScrollX << "," << ScrollY; 44             FontPrint(font, 0, 0, oss.str()); 45    
46             spriteobj->End(); 47 
48             //stop rendering
49             d3ddev->EndScene(); 50             d3ddev->Present(NULL, NULL, NULL, NULL); 51  } 52  } 53 
54     //to exit 
55     if (KEY_DOWN(VK_ESCAPE)) 56         gameover = true; 57 }

 

最后是Game_End函数

1 void Game_End() 2 { 3     if (scrollbuffer) scrollbuffer->Release(); 4     if (tiles) tiles->Release(); 5  DirectInput_Shutdown(); 6  Direct3D_Shutdown(); 7 }

 

这个例子只是对上一个例子的修改而已,内容没什么改变,只是改变了MAPDATA。下面是运行截图,源代码,参考自游戏编程入门。

基于图片单元的D3DXSprite卷动实现2_第1张图片

 

你可能感兴趣的:(Sprite)