您的位置:首页 > 编程语言

使用DirectX让子图形移动(精灵动画)

2010-11-27 19:44 232 查看
使用DirectX让子图形移动(精灵动画)

  这是我今天从这本书上学的,这本书的名字叫做《Beginning DirectX9》这本书是英文的。

好在我还看得懂英文。书上给了很多DirectX编程的初学者怎样进行DirectX编程。今天我看到了Sprite(子图形,又叫精灵图形)这一章,这一章讲了怎样使用DirectX进行精灵图形的绘制。书上的内容还是比较通俗易懂的。但是有一个缺陷,就是没有那位高人有这本书的光碟。所以我们国内的读者只好看pdf文件了。我在研究这本书的时候好在有些基础,要不然在4个月前,我根本就不知道怎样对书上的错误进行更正。正如我上面所说,书还是有很多缺陷的。这就要我们读者进行更正喽。在今天一个多小时的努力和我的基本框架的基础上,我终于把书上要显示的效果实现了。下面就是我的代码,注释是我翻译和添加的,很好懂。如果还是不懂的话,可以单独地问我或是跟帖,我会耐心地回答大家的问题的。

 首先是我的MainFrame.cpp文件。

 

 

 

 

 

 

Code:

/*---------------------------------------------------------------------------  

蒋轶民制作 E-mail:jiangcaiyang123@163.com  

文件名:MainFrame.cpp  

作用:载入子图像(sprite)  

----------------------------------------------------------------------------*/  

/*--------------------------------------------------------------------------*/  

  

// 头文件   

#include<windows.h>   

#include<d3d9.h>   

#include<d3dx9.h>   

#include<stdio.h>   

  

// 库文件   

#pragma comment( lib, "d3d9.lib")   

#pragma comment( lib, "d3dx9.lib")   

  

// 定义的宏   

#define JCLASSNAME  "优化的程序"   

#define JCAPTION  "程序演示"   

#define WINDOW_WIDTH 640   

#define WINDOW_HEIGHT 480   

#define FULLSCREEN  FALSE// 全屏与否的开关   

#define SAVE_RELEASE( p ) if ( p ) p->Release(); p = NULL;   

  

// 调整编译器设置   

#pragma warning( disable: 4100 )   

  

#if FULLSCREEN    // 全屏与否的设置   

#define WINDOW_STYLE WS_EX_TOPMOST | WS_POPUP | WS_VISIBLE   

#else   

#define WINDOW_STYLE WS_CAPTION | WS_SYSMENU   

#endif   

  

/*----------------------------------------------------------------------------*/  

  

// 全局变量   

LPDIRECT3D9 g_JD3D = NULL;// D3D结构体   

LPDIRECT3DDEVICE9 g_JDevice = NULL;// D3D装置结构体   

LPD3DXFONT g_FPSFont = NULL;// 指向FPS字体的指针   

RECT g_FPSFontPos = { WINDOW_WIDTH - 100, WINDOW_HEIGHT - 15,    

WINDOW_WIDTH, WINDOW_HEIGHT};// FPS所在的矩形框   

INT g_FrameCount = 0;// 帧的计数器   

INT g_lastTime = 0;// 记录上一秒的时间   

INT g_currentTime = 0;// 记录当前的时间   

CHAR g_FPSstr[25] = { 0 };// 记录当前帧率的字符串   

  

/*----------------------------------------------------------------------------*/  

// 初始化子图形的头文件   

#include"Sprite.h"   

  

/*----------------------------------------------------------------------------*/  

// 函数的声明   

BOOL InitializeD3D( HWND hWnd )   

{   

 D3DDISPLAYMODE displayMode;   

  

 //创建D3D对象   

 g_JD3D = Direct3DCreate9( D3D_SDK_VERSION );   

 if ( g_JD3D == NULL )   

  return FALSE;   

  

 // 获取显示器的模式   

 if ( FAILED( g_JD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &displayMode ) ) )   

  return FALSE;   

  

 // D3D显示的参数   

 D3DPRESENT_PARAMETERS jd3dpp;   

 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 ) ) )   

  return FALSE;   

  

 // 设置渲染状态   

 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 ) ) ) return FALSE;   

  

 if ( InitSprites() == FALSE )   

  return FALSE;   

  

 return TRUE;   

}   

/*----------------------------------------------------------------------------*/  

// 释放所有资源   

void ReleaseMemory( void )   

{   

 SAVE_RELEASE( g_JD3D );   

 SAVE_RELEASE( g_JDevice );   

 SAVE_RELEASE( g_FPSFont );   

}   

/*----------------------------------------------------------------------------*/  

// 渲染屏幕   

void RenderScene( 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;   

 }   

 else g_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 );   

}   

/*----------------------------------------------------------------------------*/  

// 回调函数,用来处理消息   

HRESULT CALLBACK MyAppProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )   

{   

 switch ( msg )   

 {   

 case WM_DESTROY:   

  PostQuitMessage( 0 );   

  return 0;   

 case WM_KEYDOWN:   

  if ( wParam == VK_ESCAPE ) PostQuitMessage( 0 );   

  return 0;   

 }   

 return (HRESULT)DefWindowProc( hWnd, msg, wParam, lParam );   

};   

/*----------------------------------------------------------------------------*/  

// 程序的入口,主函数   

INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmd, INT show )   

{   

 // 设置Window Class结构并且注册它   

 WNDCLASSEX jWndCls = { sizeof( jWndCls ), CS_CLASSDC, MyAppProc, 0L, 0L, hInst,    

  NULL, LoadCursor( NULL, IDC_ARROW) , 0, NULL, JCLASSNAME, NULL };   

 RegisterClassEx( &jWndCls );   

  

 // 设置窗口并且显示窗口   

 HWND hWnd = CreateWindow( JCLASSNAME, JCAPTION, WINDOW_STYLE, 100, 40,   

  WINDOW_WIDTH, WINDOW_HEIGHT, GetDesktopWindow(), NULL, jWndCls.hInstance, NULL);   

 if ( hWnd == NULL )   

  return FALSE;   

 ShowWindow( hWnd, SW_SHOWDEFAULT );   

 UpdateWindow( hWnd );   

  

 // 初始化设置   

 if ( InitializeD3D( hWnd ) == FALSE )   

  return FALSE;   

  

 // 进入消息循环   

 MSG msg;   

 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文件:

 

Code:

/*---------------------------------------------------------------------------  

蒋轶民制作 E-mail:jiangcaiyang123@163.com  

文件名:Sprite.h  

作用:载入子图像(sprite)  

----------------------------------------------------------------------------*/  

// 预编译   

#ifndef _SPRITE_H_   

#define _SPRITE_H_   

/*----------------------------------------------------------------------------*/  

// 头文件   

#include<time.h>   

/*----------------------------------------------------------------------------*/  

// 定义与子图形有关的宏   

#define SPRITE_WIDTH 48   

#define SPRITE_HEIGHT 48   

#define SCRN_WIDTH  WINDOW_WIDTH   

#define SCRN_HEIGHT  WINDOW_HEIGHT   

/*----------------------------------------------------------------------------*/  

// 自定义子图形的结构体   

struct stSprite   

{   

 stSprite():moveX( 1 ),moveY( 1 ){}//默认构造函数   

 RECT srcRect;  // 位置   

 int posX;           // X坐标   

 int posY;           // Y坐标   

 int moveX;  // 指定了一次性走多少个X像素   

 int moveY;  // 指定了一次性走多少个Y像素   

  

} spriteStruct[10];   

/*----------------------------------------------------------------------------*/  

// 全局变量   

IDirect3DSurface9* surface;// 平面的指针   

  

/*----------------------------------------------------------------------------*/  

// 初始化子图形   

bool InitSprites( void )   

{   

 // 创建离屏平面用来显示图形   

 if ( FAILED( g_JDevice->CreateOffscreenPlainSurface( 480,    

  48,    

  D3DFMT_X8R8G8B8,    

  D3DPOOL_DEFAULT,    

  &surface,    

  NULL ) ) ) return false;   

  

 // 装载子图形   

 if ( FAILED( D3DXLoadSurfaceFromFile( surface, NULL, NULL,    

  "sprite.tga", NULL, D3DX_DEFAULT, 0, NULL ) ) ) return false;   

  

 int i;   

 srand( ( unsigned int )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 );

   

 }   

 return true;   

}   

/*----------------------------------------------------------------------------*/  

// 渲染子图形   

void RenderSprite( void )   

{   

 IDirect3DSurface9* backbuffer = NULL;   

 int i;   

 // 调入后台缓存   

 g_JDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);   

 // 循环显示子图形   

 for ( i = 0; i< 10; i++ )   

 {   

  RECT destRect;            // 创建一个临时的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图片如右所示:


 程序的效果如下图所示:



 这次就写到这里了,如果大家有疑问的话,可以回复我哦。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息