使用DirectX让子图形移动(精灵动画)
这是我今天从这本书上学的,这本书的名字叫做《Beginning DirectX9》这本书是英文的。好在我还看得懂英文。书上给了很多DirectX编程的初学者怎样进行DirectX编程。今天我看到了Sprite(子图形,又叫精灵图形)这一章,这一章讲了怎样使用DirectX进行精灵图形的绘制。书上的内容还是比较通俗易懂的。但是有一个缺陷,就是没有那位高人有这本书的光碟。所以我们国内的读者只好看pdf文件了。我在研究这本书的时候好在有些基础,要不然在4个月前,我根本就不知道怎样对书上的错误进行更正。正如我上面所说,书还是有很多缺陷的。这就要我们读者进行更正喽。在今天一个多小时的努力和我的基本框架的基础上,我终于把书上要显示的效果实现了。下面就是我的代码,注释是我翻译和添加的,很好懂。如果还是不懂的话,可以单独地问我或是跟帖,我会耐心地回答大家的问题的。
首先是我的MainFrame.cpp文件。
- /*---------------------------------------------------------------------------
- 蒋轶民制作E-mail:jiangcaiyang123@163.com
- 文件名:MainFrame.cpp
- 作用:载入子图像(sprite)
- ----------------------------------------------------------------------------*/
- /*--------------------------------------------------------------------------*/
- //头文件
- #include<windows.h>
- #include<d3d9.h>
- #include<d3dx9.h>
- #include<stdio.h>
- //库文件
- #pragmacomment(lib,"d3d9.lib")
- #pragmacomment(lib,"d3dx9.lib")
- //定义的宏
- #defineJCLASSNAME"优化的程序"
- #defineJCAPTION"程序演示"
- #defineWINDOW_WIDTH640
- #defineWINDOW_HEIGHT480
- #defineFULLSCREENFALSE//全屏与否的开关
- #defineSAVE_RELEASE(p)if(p)p->Release();p=NULL;
- //调整编译器设置
- #pragmawarning(disable:4100)
- #ifFULLSCREEN//全屏与否的设置
- #defineWINDOW_STYLEWS_EX_TOPMOST|WS_POPUP|WS_VISIBLE
- #else
- #defineWINDOW_STYLEWS_CAPTION|WS_SYSMENU
- #endif
- /*----------------------------------------------------------------------------*/
- //全局变量
- LPDIRECT3D9g_JD3D=NULL;//D3D结构体
- LPDIRECT3DDEVICE9g_JDevice=NULL;//D3D装置结构体
- LPD3DXFONTg_FPSFont=NULL;//指向FPS字体的指针
- RECTg_FPSFontPos={WINDOW_WIDTH-100,WINDOW_HEIGHT-15,
- WINDOW_WIDTH,WINDOW_HEIGHT};//FPS所在的矩形框
- INTg_FrameCount=0;//帧的计数器
- INTg_lastTime=0;//记录上一秒的时间
- INTg_currentTime=0;//记录当前的时间
- CHARg_FPSstr[25]={0};//记录当前帧率的字符串
- /*----------------------------------------------------------------------------*/
- //初始化子图形的头文件
- #include"Sprite.h"
- /*----------------------------------------------------------------------------*/
- //函数的声明
- BOOLInitializeD3D(HWNDhWnd)
- {
- D3DDISPLAYMODEdisplayMode;
- //创建D3D对象
- g_JD3D=Direct3DCreate9(D3D_SDK_VERSION);
- if(g_JD3D==NULL)
- returnFALSE;
- //获取显示器的模式
- if(FAILED(g_JD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&displayMode)))
- returnFALSE;
- //D3D显示的参数
- D3DPRESENT_PARAMETERSjd3dpp;
- ZeroMemory(&jd3dpp,sizeof(jd3dpp));
- //初始化D3DPRESENT_PARAMETERS
- jd3dpp.Windowed=!FULLSCREEN;
- jd3dpp.BackBufferWidth=WINDOW_WIDTH;
- jd3dpp.BackBufferHeight=WINDOW_HEIGHT;
- jd3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
- jd3dpp.BackBufferFormat=displayMode.Format;
- jd3dpp.EnableAutoDepthStencil=TRUE;
- jd3dpp.AutoDepthStencilFormat=D3DFMT_D16;
- //创建设备
- if(FAILED(g_JD3D->CreateDevice(D3DADAPTER_DEFAULT,
- D3DDEVTYPE_HAL,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,
- &jd3dpp,&g_JDevice)))
- returnFALSE;
- //设置渲染状态
- g_JDevice->SetRenderState(D3DRS_LIGHTING,FALSE);
- g_JDevice->SetRenderState(D3DRS_ZENABLE,D3DZB_TRUE);
- //创建字体
- if(FAILED(D3DXCreateFont(g_JDevice,15,0,1,1,0,DEFAULT_CHARSET,
- OUT_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH|FF_DONTCARE,
- "Impact",&g_FPSFont)))returnFALSE;
- if(InitSprites()==FALSE)
- returnFALSE;
- returnTRUE;
- }
- /*----------------------------------------------------------------------------*/
- //释放所有资源
- voidReleaseMemory(void)
- {
- SAVE_RELEASE(g_JD3D);
- SAVE_RELEASE(g_JDevice);
- SAVE_RELEASE(g_FPSFont);
- }
- /*----------------------------------------------------------------------------*/
- //渲染屏幕
- voidRenderScene(void)
- {
- //计数器开始计数(以毫秒计)
- g_currentTime=GetTickCount();
- if(g_currentTime-g_lastTime>1000)
- {
- sprintf_s(g_FPSstr,25,"当前FPS:%d",g_FrameCount);
- g_lastTime=g_currentTime;
- g_FrameCount=0;
- }
- elseg_FrameCount++;
- g_JDevice->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
- D3DCOLOR_XRGB(179,221,247),1.0f,0);//清除屏幕
- //渲染子图形
- RenderSprite();
- //开始渲染
- g_JDevice->BeginScene();
- g_FPSFont->DrawText(NULL,g_FPSstr,-1,&g_FPSFontPos,DT_CENTER,
- D3DCOLOR_XRGB(255,255,255));//显示字体
- //结束渲染
- g_JDevice->EndScene();
- g_JDevice->Present(NULL,NULL,NULL,NULL);
- }
- /*----------------------------------------------------------------------------*/
- //回调函数,用来处理消息
- HRESULTCALLBACKMyAppProc(HWNDhWnd,UINTmsg,WPARAMwParam,LPARAMlParam)
- {
- switch(msg)
- {
- caseWM_DESTROY:
- PostQuitMessage(0);
- return0;
- caseWM_KEYDOWN:
- if(wParam==VK_ESCAPE)PostQuitMessage(0);
- return0;
- }
- return(HRESULT)DefWindowProc(hWnd,msg,wParam,lParam);
- };
- /*----------------------------------------------------------------------------*/
- //程序的入口,主函数
- INTWINAPIWinMain(HINSTANCEhInst,HINSTANCEhPrevInst,LPSTRcmd,INTshow)
- {
- //设置WindowClass结构并且注册它
- WNDCLASSEXjWndCls={sizeof(jWndCls),CS_CLASSDC,MyAppProc,0L,0L,hInst,
- NULL,LoadCursor(NULL,IDC_ARROW),0,NULL,JCLASSNAME,NULL};
- RegisterClassEx(&jWndCls);
- //设置窗口并且显示窗口
- HWNDhWnd=CreateWindow(JCLASSNAME,JCAPTION,WINDOW_STYLE,100,40,
- WINDOW_WIDTH,WINDOW_HEIGHT,GetDesktopWindow(),NULL,jWndCls.hInstance,NULL);
- if(hWnd==NULL)
- returnFALSE;
- ShowWindow(hWnd,SW_SHOWDEFAULT);
- UpdateWindow(hWnd);
- //初始化设置
- if(InitializeD3D(hWnd)==FALSE)
- returnFALSE;
- //进入消息循环
- MSGmsg;
- ZeroMemory(&msg,sizeof(msg));
- while(msg.message!=WM_QUIT)
- {
- if(PeekMessage(&msg,NULL,0U,0U,PM_REMOVE))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- else
- {
- //渲染屏幕
- RenderScene();
- }
- }
- //程序结束,释放内存所有资源
- ReleaseMemory();
- //解除窗口注册
- UnregisterClass(JCLASSNAME,jWndCls.hInstance);
- return(INT)msg.wParam;
- }
然后就是我的Sprite.h文件:
- /*---------------------------------------------------------------------------
- 蒋轶民制作E-mail:jiangcaiyang123@163.com
- 文件名:Sprite.h
- 作用:载入子图像(sprite)
- ----------------------------------------------------------------------------*/
- //预编译
- #ifndef_SPRITE_H_
- #define_SPRITE_H_
- /*----------------------------------------------------------------------------*/
- //头文件
- #include<time.h>
- /*----------------------------------------------------------------------------*/
- //定义与子图形有关的宏
- #defineSPRITE_WIDTH48
- #defineSPRITE_HEIGHT48
- #defineSCRN_WIDTHWINDOW_WIDTH
- #defineSCRN_HEIGHTWINDOW_HEIGHT
- /*----------------------------------------------------------------------------*/
- //自定义子图形的结构体
- structstSprite
- {
- stSprite():moveX(1),moveY(1){}//默认构造函数
- RECTsrcRect;//位置
- intposX;//X坐标
- intposY;//Y坐标
- intmoveX;//指定了一次性走多少个X像素
- intmoveY;//指定了一次性走多少个Y像素
- }spriteStruct[10];
- /*----------------------------------------------------------------------------*/
- //全局变量
- IDirect3DSurface9*surface;//平面的指针
- /*----------------------------------------------------------------------------*/
- //初始化子图形
- boolInitSprites(void)
- {
- //创建离屏平面用来显示图形
- if(FAILED(g_JDevice->CreateOffscreenPlainSurface(480,
- 48,
- D3DFMT_X8R8G8B8,
- D3DPOOL_DEFAULT,
- &surface,
- NULL)))returnfalse;
- //装载子图形
- if(FAILED(D3DXLoadSurfaceFromFile(surface,NULL,NULL,
- "sprite.tga",NULL,D3DX_DEFAULT,0,NULL)))returnfalse;
- inti;
- srand((unsignedint)time(NULL));//产生随机数
- //初始化10个子图形
- for(i=0;i<10;i++)
- {
- spriteStruct[i].srcRect.top=0;
- spriteStruct[i].srcRect.left=i*SPRITE_WIDTH;
- spriteStruct[i].srcRect.right=spriteStruct[i].srcRect.left+SPRITE_WIDTH;
- spriteStruct[i].srcRect.bottom=SPRITE_HEIGHT;
- spriteStruct[i].posX = abs( rand()%SCRN_WIDTH - SPRITE_WIDTH );
spriteStruct[i].posY = abs( rand()%SCRN_HEIGHT - SPRITE_HEIGHT ); - }
- returntrue;
- }
- /*----------------------------------------------------------------------------*/
- //渲染子图形
- voidRenderSprite(void)
- {
- IDirect3DSurface9*backbuffer=NULL;
- inti;
- //调入后台缓存
- g_JDevice->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&backbuffer);
- //循环显示子图形
- for(i=0;i<10;i++)
- {
- RECTdestRect;//创建一个临时的ERCT,用来迭代
- //填充每个子图形的数据
- destRect.left=spriteStruct[i].posX;
- destRect.top=spriteStruct[i].posY;
- destRect.bottom=destRect.top+SPRITE_HEIGHT;
- destRect.right=destRect.left+SPRITE_WIDTH;
- //改变子图形的X坐标,让其运动
- spriteStruct[i].posX+=spriteStruct[i].moveX;
- //检查X坐标是否超过了屏幕像素640
- if(spriteStruct[i].posX>=SCRN_WIDTH-SPRITE_WIDTH)
- {
- //如果像素超过了640,将每次运动的像素取相反数,这样就实现了反走
- spriteStruct[i].moveX*=-1;
- }
- //改变图形的Y坐标
- spriteStruct[i].posY+=spriteStruct[i].moveY;
- //检测Y坐标是否超过了屏幕像素480
- if(spriteStruct[i].posY>=SCRN_HEIGHT-SPRITE_HEIGHT)
- {
- //如果像素超过了480,将每次运动的像素取相反数,这样就实现了反走
- spriteStruct[i].moveY*=-1;
- }
- //如果子图形反走过头了,我们也必须限制其超过屏幕左边和上边
- if(spriteStruct[i].posX<=0)
- {
- //如果X坐标小于0,我们必须让其继续反走
- spriteStruct[i].moveX*=-1;
- }
- //检查子图形是否走到了屏幕的最上方
- if(spriteStruct[i].posY<=0)
- {
- //如果Y坐标小于0,我们必须让其继续反走
- spriteStruct[i].moveY*=-1;
- }
- //将子图形绘制在后台缓存上
- g_JDevice->StretchRect(surface,
- &spriteStruct[i].srcRect,
- backbuffer,
- &destRect,
- D3DTEXF_NONE);
- }
- }
- /*----------------------------------------------------------------------------*/
- #endif
载入的sprite.tga图片如右所示:
程序的效果如下图所示:
这次就写到这里了,如果大家有疑问的话,可以回复我哦。