用D3DXSprite简单绘制2D精灵

使用Direct3D绘制精灵有两种方法。这两种方法都要求我们保存精灵的位置、尺寸和速度,其中简单的那种是将精灵图像转载到D3D表面中,然后使用StretchRect绘制精灵,但不支持透明类型而且速度慢。难一点的方法是使用D3DXSprite的对象来处理Direct3D中的精灵。D3DXSprite使用纹理而不是表面来保存精灵图像。精灵是一个小的绘制在屏幕上的位图图像,代表游戏中的一个角色或对象。精灵通常将一系列图片单元(title)存储于一个位图文件中,每个图片单元表示该精灵动画序列中的一个帧。动画效果更像是方向的改变,而不是移动。

ID3DXSprite对象具有完整的3D渲染器的服务,将精灵处理成纹理并且以矩形(由两个三角形组成)来渲染,我们就可以对精灵进行各种变换,变换就是使用3D硬件加速能力来旋转、缩放和平移精灵。D3DXSprite并不关心精灵的源图像使用的是颜色键还是alpha通道来实现透明,它只是按需渲染图像。如果图像具有Alpha通道,那么使用D3DXSprite时将以alpha进行渲染,如果没有而使用背景颜色键来制作透明效果,例如24位位图,那么颜色键值像素就不会被绘制。使用颜色键实现透明效果在技术和质量上会有很多限制,使用alpha通道是一种更好的实现透明效果的方式。要实现这种效果,必须使用支持32位RGBA图像的文件格式,如png和tga。

这个例子以上一篇文章DirectInpu8的简单使用为基础,只需要修改部分文件即可。下面是DirectX.h的内容,添加了两个函数GetBitmapSize与LoadTexture。为了方便,我去掉了支持控制器输入的代码。这里还多了个引用变量,extern LPD3DXSPRITE spriteobj,后面着重讲述它的使用。

 1 #pragma once
 2 
 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 #pragma comment(lib, "winmm.lib")
16 #pragma comment(lib, "user32.lib")
17 #pragma comment(lib, "gdi32.lib")
18 #pragma comment(lib, "dxguid.lib")
19 #pragma comment(lib, "d3d9.lib")
20 #pragma comment(lib, "d3dx9.lib")
21 #pragma comment(lib, "dinput8.lib")
22 #pragma comment(lib, "xinput.lib")
23 
24 extern const string APPTITLE; 25 extern const int SCREENW; 26 extern const int SCREENH; 27 extern bool gameover; 28 
29 extern LPDIRECT3D9 d3d; 30 extern LPDIRECT3DDEVICE9 d3ddev; 31 extern LPDIRECT3DSURFACE9 backbuffer; 32 
33 //Direct3D functions
34 bool Direct3D_Init(HWND hwnd, int width, int height, bool fullscreen); 35 void Direct3D_Shutdown(); 36 bool LoadSurface(string filename, D3DXIMAGE_INFO &info, LPDIRECT3DSURFACE9 &image); 37 void DrawSurface(LPDIRECT3DSURFACE9 dest, float x, float y, LPDIRECT3DSURFACE9 source); 38 D3DXVECTOR2 GetBitmapSize(string filename); 39 LPDIRECT3DTEXTURE9 LoadTexture(string filename, D3DCOLOR transcolor = D3DCOLOR_XRGB(0,0,0)); 40 
41 //DirectInput objects, devices, and states
42 extern LPDIRECTINPUT8 dinput; 43 extern LPDIRECTINPUTDEVICE8 dimouse; 44 extern LPDIRECTINPUTDEVICE8 dikeyboard; 45 extern DIMOUSESTATE mouse_state; 46 extern LPD3DXSPRITE spriteobj; 47 
48 //DirectInput functions
49 bool DirectInput_Init(HWND); 50 void DirectInput_Update(); 51 void DirectInput_Shutdown(); 52 int Key_Down(int); 53 int Mouse_Button(int); 54 int Mouse_X(); 55 int Mouse_Y(); 56 
57 //game functions
58 bool Game_Init(HWND window); 59 void Game_Run(HWND window); 60 void Game_End();

 

接着是DirectX.cpp文件的内容

 1 #include "DirectX.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 
 18 bool Direct3D_Init(HWND window, int width, int height, bool fullscreen)  19 {  20     //Initialize Direct3D
 21     d3d = Direct3DCreate9(D3D_SDK_VERSION);  22     if (!d3d)  23         return false;  24 
 25     //set Direct3D presentation parameters
 26  D3DPRESENT_PARAMETERS d3dpp;  27     ZeroMemory(&d3dpp, sizeof(d3dpp));  28     d3dpp.Windowed = (!fullscreen);  29     d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;  30     d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;  31     d3dpp.BackBufferCount = 1;  32     d3dpp.BackBufferWidth = width;  33     d3dpp.BackBufferHeight = height;  34     d3dpp.hDeviceWindow = window;  35 
 36     //create Direct3D device
 37     d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window,  38         D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev);  39     if (!d3ddev)  40         return false;  41 
 42     //get a pointer to the back buffer surface
 43     d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);  44 
 45     //create sprite object
 46     D3DXCreateSprite(d3ddev, &spriteobj);  47 
 48     return true;  49 }  50 
 51 void Direct3D_Shutdown()  52 {  53     if (spriteobj)  54         spriteobj->Release();  55     if (d3ddev)  56         d3ddev->Release();  57     if (d3d)  58         d3d->Release();  59 }  60 
 61 void DrawSurface(LPDIRECT3DSURFACE9 dest, float x, float y, LPDIRECT3DSURFACE9 source)  62 {  63     //get width height from source surface
 64  D3DSURFACE_DESC desc;  65     source->GetDesc(&desc);  66 
 67     //create rects for drawing
 68     RECT source_rect = {0, 0, (long)desc.Width, (long)desc.Height };  69     RECT dest_rect = { (long)x, (long)y, (long)x + desc.Width, (long)y + desc.Height};  70 
 71     //draw the source surface onto the dest
 72     d3ddev->StretchRect(source, &source_rect, dest, &dest_rect, D3DTEXF_NONE);  73 }  74 
 75 bool LoadSurface(string filename, D3DXIMAGE_INFO &info, LPDIRECT3DSURFACE9 &image)  76 {  77     //get width and height from bitmap file
 78     HRESULT result = D3DXGetImageInfoFromFile(filename.c_str(), &info);  79     if (result != D3D_OK)  80         return false;  81 
 82     //create surface
 83     result = d3ddev->CreateOffscreenPlainSurface(  84  info.Width, info.Height,  85  D3DFMT_X8R8G8B8,  86  D3DPOOL_DEFAULT,  87         &image,  88  NULL);  89     if (result != D3D_OK)  90         return false;  91 
 92     //load surface from file into newly created surface
 93     result = D3DXLoadSurfaceFromFile(  94         image,    //destination surface
 95         NULL,    //destination palette
 96         NULL,    //destination rectangle
 97  filename.c_str(),  98         NULL,    //source rectangle
 99         D3DX_DEFAULT, //controls how image is filtered
100         D3DCOLOR_XRGB(0,0,0), 101         NULL);    //source image info
102     if (result != D3D_OK) 103         return false; 104 
105     return true; 106 } 107 
108 bool DirectInput_Init(HWND hwnd) 109 { 110     //initialize DirectInput object
111     HRESULT result = DirectInput8Create( 112  GetModuleHandle(NULL), 113  DIRECTINPUT_VERSION, 114  IID_IDirectInput8, 115         (void**)&dinput, 116  NULL); 117 
118     //initialize the keyboard
119     dinput->CreateDevice(GUID_SysKeyboard, &dikeyboard, NULL); 120     dikeyboard->SetDataFormat(&c_dfDIKeyboard); 121     dikeyboard->SetCooperativeLevel(hwnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND); 122     dikeyboard->Acquire(); 123 
124     //initialize the mouse
125     dinput->CreateDevice(GUID_SysMouse, &dimouse, NULL); 126     dimouse->SetDataFormat(&c_dfDIMouse); 127     dimouse->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); 128     dimouse->Acquire(); 129     
130     ShowCursor(true); 131 
132     return true; 133 } 134 
135 void DirectInput_Update() 136 { 137     //update mouse
138     dimouse->GetDeviceState(sizeof(mouse_state), (LPVOID)&mouse_state); 139 
140     //update keyboard
141     dikeyboard->GetDeviceState(sizeof(keys), (LPVOID)&keys); 142 } 143 
144 int Mouse_X() 145 { 146     return mouse_state.lX; 147 } 148 
149 int Mouse_Y() 150 { 151     return mouse_state.lY; 152 } 153 
154 //return mouse button state
155 int Mouse_Button(int button) 156 { 157     return mouse_state.rgbButtons[button] & 0x80; 158 } 159 
160 //return key press state
161 int Key_Down(int key) 162 { 163     return (keys[key] & 0x80); 164 } 165 
166 void DirectInput_Shutdown() 167 { 168     if (dikeyboard) 169  { 170         dikeyboard->Unacquire(); 171         dikeyboard->Release(); 172         dikeyboard = NULL; 173  } 174 
175     if (dimouse) 176  { 177         dimouse->Unacquire(); 178         dimouse->Release(); 179         dimouse = NULL; 180  } 181 }

 

我把新增的两个函数代码放在了下面

 1 //load texture
 2 LPDIRECT3DTEXTURE9 LoadTexture(string filename, D3DCOLOR transcolor)  3 {  4     LPDIRECT3DTEXTURE9 texture = NULL;  5     
 6     //get width and height from bitmap file
 7  D3DXIMAGE_INFO info;  8     HRESULT result = D3DXGetImageInfoFromFile(filename.c_str(), &info);  9     if (result != D3D_OK) 10         return NULL; 11 
12     //create the new texture by loading a bitmap image file
13     result = D3DXCreateTextureFromFileEx( 14         d3ddev, //Direct3D device object
15         filename.c_str(), //filename
16         info.Width, //image width
17         info.Height, //image height
18         1, //mip-map levels (1 for no chain)
19         D3DPOOL_DEFAULT, //the type of surface
20         D3DFMT_UNKNOWN, //surface format
21         D3DPOOL_DEFAULT, //memory class for the texture
22         D3DX_DEFAULT, //image filter
23         D3DX_DEFAULT, //mip filter
24         transcolor, //color key for transparency
25         &info, //bitmap file info
26         NULL, //color palette
27         &texture); //destination texture
28     if (result != D3D_OK) 29         return NULL; 30 
31     return texture; 32 } 33 
34 D3DXVECTOR2 GetBitmapSize(string filename) 35 { 36  D3DXIMAGE_INFO info; 37     D3DXVECTOR2 size = D3DXVECTOR2(0.0f, 0.0f); 38     HRESULT result = D3DXGetImageInfoFromFile(filename.c_str(), &info); 39     if (result == D3D_OK) 40         size = D3DXVECTOR2((float)info.Width, (float)info.Height); 41 
42     return size; 43 }

先看到GetBitmapSize函数,这个函数只是简单的获取文件信息,然后将文件的宽度与高度信息填入一个二维向量size中。在LoadTexture函数中,先用函数D3DXGetImageInfoFromFile来获取到图片信息info,接着用D3DXCreateTexureFromFileEx把图片加载到texture变量中。

 

再看个简单的文件main.cpp,实现创建windows窗口这些功能,前面也已讲过了。

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

 1 #include "DirectX.h"
 2 using namespace std;  3 
 4 const string APPTITLE = "TransparentSprite";  5 const int SCREENW = 1024;  6 const int SCREENH = 576;  7 
 8 LPDIRECT3DTEXTURE9 image_colorkey = NULL;  9 LPDIRECT3DTEXTURE9 image_alpha = NULL; 10 LPDIRECT3DTEXTURE9 image_notrans = NULL; 11 
12 //game initialization
13 bool Game_Init(HWND window) 14 { 15     Direct3D_Init(window, SCREENW, SCREENH, false); 16  DirectInput_Init(window); 17 
18     //load non-transparent image
19     image_notrans = LoadTexture("shuttle_notrans.bmp"); 20     if (!image_notrans) 21         return false; 22 
23     //load color-keyed transparent image
24     image_colorkey = LoadTexture("shuttle_colorkey.bmp", D3DCOLOR_XRGB(255, 0, 255)); 25     if (!image_colorkey) 26         return false; 27 
28     //load alpha transparent image
29     image_alpha = LoadTexture("shuttle_alpha.tga"); 30     if (!image_alpha) 31         return false; 32 
33     return true; 34 }

三个变量中,image_colorkey表示用颜色键实现透明的贴图,image_alpha代表使用alpha通道,image_notrans代表不使用透明效果。在Game_Init中,分别加载三个贴图,本程序需要使用三个不同单的文件,可以下载后面的源代码查看。

 

下面是游戏运行函数Game_Run,我们从spriteobj->Begin(D3DXSPRITE_ALPHABLEND)开始看起,这句代表启动精灵渲染器,然后可以使用Draw函数绘制精灵。接下来定义了一个三维向量D3DXVECTOR3 pos1,用它表示要把精灵绘制到窗口的哪个位置上,我们这里只改变横坐标x的值,所以pos2与pos3也是如此。最后,要记得停止使用精灵渲染器,即spriteobj->End()。

 1 //game update
 2 void Game_Run(HWND window)  3 {  4     //make sure the Direct3D device is valid
 5     if (!d3ddev)  6         return;  7 
 8     //update input devices
 9  DirectInput_Update(); 10 
11     //clear the scene
12     d3ddev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 100), 1.0f, 0); 13 
14     //start rendering
15     if (d3ddev->BeginScene()) 16  { 17         //start drawing
18         spriteobj->Begin(D3DXSPRITE_ALPHABLEND); 19 
20         //draw the sprite
21         D3DXVECTOR3 pos1(10, 0, 0); 22         spriteobj->Draw(image_notrans, NULL, NULL, &pos1, D3DCOLOR_XRGB(255,255,255)); 23 
24         D3DXVECTOR3 pos2(350, 0, 0); 25         spriteobj->Draw(image_colorkey, NULL, NULL, &pos2, D3DCOLOR_XRGB(255,255,255)); 26 
27         D3DXVECTOR3 pos3(700, 0, 0); 28         spriteobj->Draw(image_alpha, NULL, NULL, &pos3, D3DCOLOR_XRGB(255,255,255)); 29 
30         //stop drawing
31         spriteobj->End(); 32 
33         //stop rendering
34         d3ddev->EndScene(); 35         d3ddev->Present(NULL, NULL, NULL, NULL); 36  } 37 
38     //escape key exits
39     if (Key_Down(DIK_ESCAPE)) 40         gameover = true; 41 }

 

 最后是简单的释放资源,程序到这里就结束了。

 1 void Game_End()  2 {  3     //free memory
 4     image_notrans->Release();  5     image_colorkey->Release();  6     image_alpha->Release();  7 
 8  DirectInput_Shutdown();  9  Direct3D_Shutdown(); 10 }

 

运行截图如下,可以看到最终的透明效果,分别为不使用透明、使用了颜色键、使用了Alpha通道,源代码,本文参照游戏编程入门一书。

用D3DXSprite简单绘制2D精灵_第1张图片

 

你可能感兴趣的:(Sprite)