DirectX游戏开发之3D角色动起(下)
直接先上图吧!
动作idle
动作attack
动作walk
动作run
看,多动作的模型搞下来了。原则上只要在此基础上略做修改就可以实现3d游戏的基本制作啦!
切换动作的精髓代码就是
DWORD dwNewTrack = ( currentTrack == 0 ? 1 : 0 );
LPD3DXANIMATIONSET pAnimationSet = NULL;
pAnimController->GetAnimationSetByName( name , &pAnimationSet );
pAnimController->SetTrackAnimationSet( dwNewTrack, pAnimationSet );
pAnimationSet->Release();
pAnimController->UnkeyAllTrackEvents( currentTrack );
pAnimController->UnkeyAllTrackEvents( dwNewTrack );
pAnimController->KeyTrackEnable( currentTrack, FALSE, curTime + 0.125f );
pAnimController->KeyTrackSpeed( currentTrack, 0.0f, curTime, 0.125f, D3DXTRANSITION_LINEAR );
pAnimController->KeyTrackWeight( currentTrack, 0.0f, curTime, 0.125f, D3DXTRANSITION_LINEAR );
pAnimController->SetTrackEnable( dwNewTrack, TRUE );
pAnimController->KeyTrackSpeed( dwNewTrack, 1.0f, curTime, 0.125f, D3DXTRANSITION_LINEAR );
pAnimController->KeyTrackWeight( dwNewTrack, 1.0f, curTime, 0.125f, D3DXTRANSITION_LINEAR );
currentTrack = dwNewTrack;
原理上来讲就是相当于用了两个轨道来分别进行不同的动画,显示其中一个,当要切换动作时,就在两个动作之间进行插值运算,尽量让两个动作的切换过程变得连贯些,衔接起来的感觉。原理看起来是很简单的,实现起来也不是很难,有一定的套路走。
废话少说,先放出重要的3个代码文件。还是建议下载整个代码回去,跑一跑。
main.cpp
//-----------------------------------【程序说明】----------------------------------------------
// 程序名称:005
// 2016年8月 by UltramanGaia520
// 描述:DirectX游戏开发之3D角色动起来
//------------------------------------------------------------------------------------------------
//-----------------------------------【宏定义部分】--------------------------------------------
// 描述:辅助宏
//------------------------------------------------------------------------------------------------
#define WINDOW_TITLE _T("GAIA By UltramanGaia ") //窗口标题
//-----------------------------------【头文件包含部分】---------------------------------------
// 描述:包含头文件
//------------------------------------------------------------------------------------------------
#include <d3d9.h>
#include <d3dx9.h>
#include <tchar.h>
#include <time.h>
#include <vector>
#include "Input.h" //获取输入信息的类
#include "Camera.h" //虚拟摄像机的类
#include "Terrain.h" //地形的类
#include "AllocateHierarchy.h" //骨骼动画的类
#include "D3DUtil.h"
#include "Character.h"
using namespace std;
//-----------------------------------【库文件包含部分】---------------------------------------
// 描述:包含库文件
//------------------------------------------------------------------------------------------------
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib, "dinput8.lib")
#pragma comment(lib,"dxguid.lib")
#pragma comment(lib, "winmm.lib")
/*
// 地板的顶点结构
struct CUSTOMVERTEX
{
float _x, _y, _z;
float _u, _v ;
CUSTOMVERTEX(float x, float y, float z, float u, float v)
: _x(x), _y(y), _z(z), _u(u), _v(v) {}
};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_TEX1)
*/
//-----------------------------------【全局变量声明部分】-------------------------------------
// 描述:全局变量声明
//----------------------------------------------------------------------------------------------
bool g_isFullscreen = false; //是否全屏
int WINDOW_WIDTH = 1366; //默认窗口宽度
int WINDOW_HEIGHT = 768; //默认窗口高度
bool g_Destroying = false;
Character* g_pCharacter;
DWORD g_currentTrack = DWORD(0);
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; //Direct3D设备对象
LPD3DXFONT g_pTextFPS = NULL; //字体COM接口
LPD3DXFONT g_pTextAdaperName = NULL; //显卡信息的2D文本
LPD3DXFONT g_pTextHelper = NULL; //帮助信息的2D文本
LPD3DXFONT g_pTextInfor = NULL; //摄像机信息的2D文本
float g_FPS = 0.0f; //帧速率
wchar_t g_strFPS[50] ={0}; //储存显示帧速率的字符数组
wchar_t g_strAdapterName[60] ={0}; //储存显示显卡名称的字符数组
D3DXMATRIX g_matWorld; //世界矩阵
D3DLIGHT9 g_Light; //全局光照
Input* g_pDInput = NULL; //Input类的指针
Camera* g_pCamera = NULL; //摄像机类的指针
Terrain* g_pTerrain = NULL; //地形类的指针
//和骨骼动画相关的全局变量
LPD3DXFRAME g_pFrameRoot = NULL;
CAllocateHierarchy* g_pAllocateHier = NULL;
LPD3DXANIMATIONCONTROLLER g_pAnimController = NULL;
bool g_LMBDown = false; // GUI中,鼠标左键是否按下
int g_MouseX = 0;
int g_MouseY = 0; //鼠标坐标
//-----------------------------------【全局函数声明部分】-------------------------------------
// 描述:全局函数声明
//------------------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ); //窗口过程处理函数
HRESULT Direct3D_Init(HWND hwnd,HINSTANCE hInstance); //Direct3D初始化函数
bool ObjectsFor3D_Init(); //3D游戏渲染资源初始化函数
void Direct3D_Render( HWND hwnd,float fTimeDelta); //Direct3D渲染函数
void Direct3D_Update( HWND hwnd,float fTimeDelta); //Direct3D更新函数
void Direct3D_CleanUp( ); //清理COM接口对象
float Get_FPS(); //计算帧速率函数
void HelpText_Render(HWND hwnd); //显示帮助信息函数
void GUICallback(int id, int state); //GUI界面回调函数
void MainMsgLoop(HWND hwnd); //主消息循环
//-----------------------------------【WinMain( )函数】--------------------------------------
// 描述:Windows应用程序入口函数
//------------------------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nShowCmd)
{
//设计窗口类
WNDCLASSEX wndClass={0} ;
wndClass.cbSize = sizeof( WNDCLASSEX ) ;
wndClass.style = CS_HREDRAW | CS_VREDRAW; //窗口的样式
wndClass.lpfnWndProc = WndProc; //设置窗口过程函数
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon=(HICON)::LoadImage(NULL,_T("GameMedia\\icon.ico"),IMAGE_ICON,0,0,LR_DEFAULTSIZE|LR_LOADFROMFILE); //从本地加载ico图标
wndClass.hCursor = LoadCursor( NULL, IDC_ARROW ); //窗口类的光标句柄。
wndClass.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = _T("WindowsClassForGAIA"); //窗口类的名字。
//注册窗口类
if( !RegisterClassEx( &wndClass ) )
return -1;
//创建窗口
HWND hwnd = CreateWindow( _T("WindowsClassForGAIA"),WINDOW_TITLE,
WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, //WS_POPUP没有标题栏,比较好看
WINDOW_HEIGHT, NULL, NULL, hInstance, NULL );
//Direct3D资源的初始化
if (!(S_OK==Direct3D_Init (hwnd,hInstance)))
{
MessageBox(hwnd, _T("Direct3D资源初始化失败!"), _T("错误信息窗口"), 0);
}
PlaySound(L"GameMedia\\Tracy Bush - Echoes(Exclusive Track).wav", NULL, SND_FILENAME | SND_ASYNC|SND_LOOP); //循环播放背景音乐
if(!g_isFullscreen)
{
MoveWindow(hwnd,30,50,WINDOW_WIDTH,WINDOW_HEIGHT,true); //调整窗口位置
}
ShowWindow( hwnd, nShowCmd ); //ShowWindow函数显示窗口
//进行DirectInput类的初始化
g_pDInput = new Input();
g_pDInput->Init(hwnd,hInstance,DISCL_FOREGROUND | DISCL_NONEXCLUSIVE,DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); //前台,非独占模式
ObjectsFor3D_Init();
UpdateWindow(hwnd); //对窗口进行更新
//消息循环过程
MainMsgLoop(hwnd);
//注销窗口类
UnregisterClass(_T("WindowsClassForGAIA"), wndClass.hInstance);
return 0;
}
//-----------------------------------【MainMsgLoop( )函数】----------------------------------
// 描述:主消息循环函数
//-----------------------------------------------------------------------------------------------
void MainMsgLoop(HWND hwnd)
{
MSG msg = { 0 };
while( msg.message != WM_QUIT )
{
static float fLastTime = (float)::timeGetTime();
static float fCurrTime = (float)::timeGetTime();
static float fTimeDelta = 0.0f;
fCurrTime = (float)::timeGetTime();
fTimeDelta = (fCurrTime - fLastTime) / 1000.0f; //一次循环经历的时间
fLastTime = fCurrTime;
//应该每次循环都进行游戏画面的更新和渲染
{
if( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) ) //查看消息队列,有则发送消息
{
TranslateMessage( &msg ); //将虚拟键消息转换为字符消息
DispatchMessage( &msg ); //发送消息给窗口程序。
}
if(!g_Destroying) //如果窗口已经在销毁中了,就不要更新渲染了
{
Direct3D_Update(hwnd,fTimeDelta); //画面的更新
Direct3D_Render(hwnd,fTimeDelta); //画面的渲染
}
}
}
}
//-----------------------------------【Direct3D_Init( )函数】----------------------------------
// 描述:Direct3D初始化函数
//------------------------------------------------------------------------------------------------
HRESULT Direct3D_Init(HWND hwnd,HINSTANCE hInstance)
{
LPDIRECT3D9 pD3D = NULL; //Direct3D接口对象的创建
if( NULL == ( pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) ) //初始化Direct3D接口对象,并进行DirectX版本协调
return E_FAIL;
//获取硬件设备信息
D3DCAPS9 caps; int vp = 0;
if( FAILED( pD3D->GetDeviceCaps( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps ) ) )
{
return E_FAIL;
}
if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING; //支持硬件顶点运算,就用硬件顶点运算
else
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING; //不支持,用软件顶点运算
//填充D3DPRESENT_PARAMETERS结构体
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.BackBufferWidth = WINDOW_WIDTH;
d3dpp.BackBufferHeight = WINDOW_HEIGHT;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount = 2;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hwnd;
d3dpp.Windowed = !g_isFullscreen;
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.Flags = 0;
d3dpp.FullScreen_RefreshRateInHz = 0;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
//创建Direct3D设备接口
if(FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
hwnd, vp, &d3dpp, &g_pd3dDevice)))
return E_FAIL;
//获取显卡信息到g_strAdapterName中,并在显卡名称之前加上“当前显卡型号:”字符串
wchar_t TempName[60]=L"当前显卡型号:";
D3DADAPTER_IDENTIFIER9 Adapter;
pD3D->GetAdapterIdentifier(0,0,&Adapter);//获取显卡信息
int len = MultiByteToWideChar(CP_ACP,0, Adapter.Description, -1, NULL, 0);
MultiByteToWideChar(CP_ACP, 0, Adapter.Description, -1, g_strAdapterName, len);
wcscat_s(TempName,g_strAdapterName);
wcscpy_s(g_strAdapterName,TempName);
SAFE_RELEASE(pD3D) //LPDIRECT3D9接口对象释放
return S_OK;
}
//-----------------------------------【ObjectsFor3D_Init( )函数】--------------------------------------
// 描述:渲染资源初始化函数
//--------------------------------------------------------------------------------------------------
bool ObjectsFor3D_Init()
{
//创建字体
D3DXCreateFont(g_pd3dDevice, 36, 0, 0, 1000, false, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, _T("Calibri"), &g_pTextFPS);
D3DXCreateFont(g_pd3dDevice, 20, 0, 1000, 0, false, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, L"华文中宋", &g_pTextAdaperName);
D3DXCreateFont(g_pd3dDevice, 40, 0, 1000, 0, false, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, L"微软雅黑", &g_pTextHelper);
D3DXCreateFont(g_pd3dDevice, 26, 0, 1000, 0, false, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, L"黑体", &g_pTextInfor);
//设置纹理采样参数
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_NONE);
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_NONE);
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
//--------------------------------------------------【游戏相关代码】-------------------------------------------------------
//创建 初始化地形
g_pTerrain = new Terrain(g_pd3dDevice);
g_pTerrain->LoadTerrainFromFile(L"GameMedia\\hightMap.raw", L"GameMedia\\贴图.png");//从文件加载高度图和纹理
g_pTerrain->InitTerrain(200, 200, 100.0f, 10.0f, 1.0f,1.0f); //四个值分别是顶点行数,顶点列数,顶点间间距,高度图缩放系数,横,竖用多少张纹理图贴图
// 设置光照
::ZeroMemory(&g_Light, sizeof(g_Light));
g_Light.Type = D3DLIGHT_DIRECTIONAL;
g_Light.Ambient = D3DXCOLOR(0.7f, 0.7f, 0.7f, 1.0f);
g_Light.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
g_Light.Specular = D3DXCOLOR(0.9f, 0.9f, 0.9f, 1.0f);
g_Light.Direction = D3DXVECTOR3(1.0f, 1.0f, 1.0f);
g_pd3dDevice->SetLight(0, &g_Light);
g_pd3dDevice->LightEnable(0, true);
g_pd3dDevice->SetRenderState(D3DRS_NORMALIZENORMALS, true);
g_pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, true);
// 创建并初始化虚拟摄像机
g_pCamera = new Camera(g_pd3dDevice);
g_pCamera->SetCameraPosition(&D3DXVECTOR3(0.0f, 300.0f, -800.0f)); //设置摄像机所在的位置
g_pCamera->SetTargetPosition(&D3DXVECTOR3(0.0f, 400.0f, 0.0f)); //设置目标观察点所在的位置
g_pCamera->SetViewMatrix(); //设置取景变换矩阵
D3DXMATRIX matProj;
D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4.0f, 1.0f, 1.0f, 200000.0f);
g_pCamera->SetProjMatrix(&matProj);
// 创建骨骼动画
g_pCharacter = new Character();
g_pCharacter->InitByName(g_pd3dDevice,g_pDInput,L"GameMedia\\moshou11.X","walk","run" ,"ready" ,"magicAttack",-D3DX_PI / 2.0f , 0.0f , 0.0f ,15.0f);
return true;
}
//-----------------------------------【WndProc( )函数】--------------------------------------
// 描述:窗口过程函数WndProc,对窗口消息进行处理
//------------------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch( message )
{
case WM_KEYUP: //键盘按下消息
if (wParam == VK_ESCAPE) //ESC键
{
DestroyWindow(hwnd); // 销毁窗口, 并发送一条WM_DESTROY消息
g_Destroying = true;
}
break;
case WM_PAINT: //客户区重绘消息
Direct3D_Render(hwnd,0.0f); //Direct3D_Render函数,进行画面的绘制
ValidateRect(hwnd, NULL); //更新客户区的显示
break;
case WM_DESTROY: //窗口销毁消息
Direct3D_CleanUp(); //Direct3D_CleanUp函数,清理COM接口对象
PostQuitMessage( 0 ); //向系统表明有个线程有终止请求。用来响应WM_DESTROY消息
break;
default:
return DefWindowProc( hwnd, message, wParam, lParam ); //其他调用默认
}
return 0;
}
//-----------------------------------【Direct3D_Update( )函数】--------------------------------
// 描述:各种数据的更新
//--------------------------------------------------------------------------------------------------
void Direct3D_Update( HWND hwnd,float fTimeDelta)
{
//使用DirectInput类读取数据
g_pDInput->GetInput();
// 沿摄像机各分量移动视角
if (g_pDInput->IsKeyDown(DIK_A)) g_pCamera->MoveAlongRightVec(-20.0f);
if (g_pDInput->IsKeyDown(DIK_D)) g_pCamera->MoveAlongRightVec( 20.0f);
if (g_pDInput->IsKeyDown(DIK_W)) g_pCamera->MoveAlongLookVec( 20.0f);
if (g_pDInput->IsKeyDown(DIK_S)) g_pCamera->MoveAlongLookVec(-20.0f);
if (g_pDInput->IsKeyDown(DIK_R)) g_pCamera->MoveAlongUpVec( 10.0f);
if (g_pDInput->IsKeyDown(DIK_F)) g_pCamera->MoveAlongUpVec(-10.0f);
//沿摄像机各分量旋转视角
if (g_pDInput->IsKeyDown(DIK_LEFT)) g_pCamera->RotationUpVec(-0.003f);
if (g_pDInput->IsKeyDown(DIK_RIGHT))g_pCamera->RotationUpVec( 0.003f);
if (g_pDInput->IsKeyDown(DIK_UP)) g_pCamera->RotationRightVec(-0.003f);
if (g_pDInput->IsKeyDown(DIK_DOWN)) g_pCamera->RotationRightVec( 0.003f);
if (g_pDInput->IsKeyDown(DIK_Q)) g_pCamera->RotationLookVec(0.001f);
if (g_pDInput->IsKeyDown(DIK_E)) g_pCamera->RotationLookVec( -0.001f);
//鼠标控制右向量和上向量的旋转
g_pCamera->RotationUpVec(g_pDInput->MouseDX()* 0.0003f);
g_pCamera->RotationRightVec(g_pDInput->MouseDY() * 0.0003f);
//鼠标滚轮控制观察点收缩操作
static float fPosZ=0.0f;
fPosZ += g_pDInput->MouseDZ()*0.03f;
//计算并设置取景变换矩阵
D3DXMATRIX matView;
g_pCamera->CalculateViewMatrix(&matView);
g_pd3dDevice->SetTransform(D3DTS_VIEW, &matView);
//把正确的世界变换矩阵存到g_matWorld中
D3DXMatrixTranslation(&g_matWorld, 0.0f, 0.0f, fPosZ);
while( ShowCursor(false) >= 0); //隐藏鼠标光标
srand((unsigned int)timeGetTime());
g_pCharacter->Update(fTimeDelta); //更新骨骼
}
//-----------------------------------【Direct3D_Render( )函数】-------------------------------
// 描述:使用Direct3D进行渲染
//--------------------------------------------------------------------------------------------------
void Direct3D_Render(HWND hwnd,float fTimeDelta)
{
//清屏操作
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL, D3DCOLOR_XRGB(100, 155, 255), 1.0f, 0);
//开始绘制
g_pd3dDevice->BeginScene();
//正式绘制
//-----------------------------【绘制地形】-----------------------------
g_pTerrain->RenderTerrain(&g_matWorld, false); //渲染地形,且第二个参数设为false,表示不渲染出地形的线框
//-----------------------------【绘制骨骼动画】------------------------
g_pCharacter->Draw();
//-----------------------------【绘制文字信息】-----------------------------
HelpText_Render(hwnd);
//结束绘制
g_pd3dDevice->EndScene();
//显示翻转
g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
}
//-----------------------------------【HelpText_Render( )函数】-------------------------------
// 描述:显示帮助信息的函数
//--------------------------------------------------------------------------------------------------
void HelpText_Render(HWND hwnd)
{
//定义一个矩形,用于获取主窗口矩形
RECT formatRect;
GetClientRect(hwnd, &formatRect);
//显示每秒帧数
formatRect.top = 5;
int charCount = swprintf_s(g_strFPS, 20, _T("FPS:%0.3f"), Get_FPS() );
g_pTextFPS->DrawText(NULL, g_strFPS, charCount , &formatRect, DT_TOP | DT_RIGHT, D3DCOLOR_RGBA(0,239,136,255));
//显示显卡类型名
g_pTextAdaperName->DrawText(NULL,g_strAdapterName, -1, &formatRect,
DT_TOP | DT_LEFT, D3DXCOLOR(1.0f, 0.5f, 0.0f, 1.0f));
//显示摄像机信息
formatRect.bottom -= 100;
char info[500];
sprintf(info ,"Q,W,E,R,A,S,D,F\n方向键,鼠标,\n可以控制摄像机的运动\nH,J,K,L控制显示不同的动画");
g_pTextInfor->DrawTextA(NULL,info,-1,&formatRect , DT_BOTTOM|DT_LEFT ,D3DXCOLOR(255.0f,255.0f,255.0,1.0f));
//动画轨道信息
char cTrack[500];
sprintf(cTrack , "run : 0\n\
attack : 1\n\
idle : 2\n\
walk : 3\n\
currentTrack: %d \n\
currentAnim: %d \n",
g_pCharacter->getCurrentTrack(),
g_pCharacter->getCurrentAnim()
);
g_pTextHelper ->DrawTextA(NULL,cTrack,-1,&formatRect , DT_BOTTOM|DT_RIGHT ,D3DXCOLOR(1.0f,0.5f,0.0f,1.0f));
}
//-----------------------------------【Get_FPS( )函数】------------------------------------------
// 描述:获取帧速率
//--------------------------------------------------------------------------------------------------
float Get_FPS()
{
static float fps = 0;
static int frameCount = 0;//帧数
static float currentTime =0.0f;//当前时间
static float lastTime = 0.0f;//上次时间
frameCount++;
currentTime = timeGetTime()*0.001f;
if(currentTime - lastTime > 1.0f) //将时间控制在1秒钟
{
fps = (float)frameCount /(currentTime - lastTime);//计算这1秒钟的FPS值
lastTime = currentTime;
frameCount = 0;
}
return fps;
}
//-----------------------------------【Direct3D_CleanUp( )函数】--------------------------------
// 描述:对Direct3D的资源进行清理,释放COM接口对象
//---------------------------------------------------------------------------------------------------
void Direct3D_CleanUp()
{
//释放COM接口对象
SAFE_RELEASE(g_pd3dDevice);
SAFE_RELEASE(g_pTextFPS)
SAFE_RELEASE(g_pd3dDevice)
}
character.h
#pragma once
#include <d3d9.h>
#include <d3dx9.h>
#include "AllocateHierarchy.h" //骨骼动画的类
#include "Input.h"
#include "Character.h"
#include <vector>
// 地板的顶点结构
struct CUSTOMVERTEX
{
float _x, _y, _z;
float _u, _v ;
CUSTOMVERTEX(float x, float y, float z, float u, float v)
: _x(x), _y(y), _z(z), _u(u), _v(v) {}
};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_TEX1)
class Character
{
private:
LPDIRECT3DDEVICE9 pd3dDevice;
Input * pInput;
float fTimeDelta;
//骨骼动画的
LPD3DXFRAME pFrameRoot;
CAllocateHierarchy* pAllocateHier;
LPD3DXANIMATIONCONTROLLER pAnimController;
D3DXMATRIX modelOrientation;
DWORD walk;
DWORD run;
DWORD idle;
DWORD attack;
DWORD currentAnim;
UINT currentTrack;
D3DXVECTOR3 position;
D3DXVECTOR3 targetPosition;
float facing;
float facingTarget;
float alongXRotation;
float alongYRotation;
float alongZRotation;
float scaling;
float prvTime;
float curTime;
public:
Character();
~Character();
void setScaling(float sca);
int getCurrentTrack();
int getCurrentAnim();
DWORD GetAnimIndex( char sString[] );
void InitByName(LPDIRECT3DDEVICE9 p_d3dDevice, Input * p_Input ,LPCWSTR filename , char * walkAnim ,char * runAnim ,char * idleAnim ,char * attackAnim, float xRotation ,float yRotation , float zRotation ,float sca );
void Update(float f_TimeDelta);
void ChangeTrack(const char *name);
void ChangeTrack(DWORD name);
void Draw();
void Walk();
void Run();
void Idle();
void Attack();
};
character.cpp
#include "Character.h"
#include "Input.h"
#include <vector>
/*
// 地板的顶点结构
struct CUSTOMVERTEX
{
float _x, _y, _z;
float _u, _v ;
CUSTOMVERTEX(float x, float y, float z, float u, float v)
: _x(x), _y(y), _z(z), _u(u), _v(v) {}
};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_TEX1)
*/
Character::Character():
pd3dDevice(NULL),
pInput(NULL),
fTimeDelta(0.0f),
pFrameRoot(NULL),
pAllocateHier(NULL),
pAnimController(NULL),
// modelOrientation
currentAnim(0),
currentTrack(0),
position (D3DXVECTOR3(1000,0,2000)),
targetPosition(D3DXVECTOR3(1000,0,2000)),
facing(0.0f),
scaling(1.0f),
prvTime(0.0f),
curTime(0.0f)
{
D3DXMatrixIdentity(&modelOrientation);
}
Character::~Character()
{
}
void Character::setScaling(float sca)
{
scaling = sca;
D3DXMATRIX mx;
D3DXMatrixScaling( &mx, scaling , scaling, scaling );
modelOrientation = mx;
D3DXMatrixRotationX( &mx, alongXRotation );
D3DXMatrixMultiply( &modelOrientation, &modelOrientation, &mx );
D3DXMatrixRotationY( &mx, alongYRotation);
D3DXMatrixMultiply( &modelOrientation, &modelOrientation, &mx );
D3DXMatrixRotationZ( &mx, alongZRotation);
D3DXMatrixMultiply( &modelOrientation, &modelOrientation, &mx );
}
int Character::getCurrentTrack()
{
return currentTrack;
}
int Character::getCurrentAnim()
{
return currentAnim;
}
void Character::InitByName(LPDIRECT3DDEVICE9 p_d3dDevice, Input * p_Input ,LPCWSTR filename , char * walkAnim ,char * runAnim ,char * idleAnim ,char * attackAnim, float xRotation ,float yRotation , float zRotation ,float sca )
{
pd3dDevice = p_d3dDevice;
pInput = p_Input;
alongXRotation = xRotation;
alongYRotation = yRotation;
alongZRotation = zRotation;
// 创建骨骼动画
pAllocateHier = new CAllocateHierarchy();
D3DXLoadMeshHierarchyFromX(filename, D3DXMESH_MANAGED, pd3dDevice,
pAllocateHier, NULL, &pFrameRoot, &pAnimController);
SetupBoneMatrixPointers(pFrameRoot, pFrameRoot);
walk = GetAnimIndex(walkAnim);
run = GetAnimIndex(runAnim);
idle = GetAnimIndex(idleAnim);
attack = GetAnimIndex(attackAnim);
LPD3DXANIMATIONSET pAnimationSet = NULL;
pAnimController->GetAnimationSet(idle, &pAnimationSet);
pAnimController->SetTrackAnimationSet(currentTrack, pAnimationSet);
pAnimationSet->Release();
pAnimController->UnkeyAllTrackEvents(currentTrack);
pAnimController->SetTrackEnable(currentTrack,TRUE);
pAnimController->KeyTrackSpeed(currentTrack,1.0f,0.01f,0.25f,D3DXTRANSITION_LINEAR);
pAnimController->KeyTrackWeight(currentTrack,1.0f,0.01f,0.25f,D3DXTRANSITION_LINEAR);
currentAnim = idle;
curTime = prvTime = timeGetTime();
setScaling(sca);
}
void Character::Update(float f_TimeDelta)
{
fTimeDelta = f_TimeDelta;
if (pInput->IsKeyDown(DIK_H))
{
Attack();
}
else if (pInput->IsKeyDown(DIK_J))
{
Walk();
}
else if(pInput->IsKeyDown(DIK_K))
{
Run();
}
else if(pInput ->IsKeyDown(DIK_L))
{
Idle();
}
pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE); //关闭光照
// 设置骨骼动画的矩阵
D3DXMATRIX matFinal, mx;
D3DXMatrixIdentity(&matFinal);
//根据位置和朝向计算变换矩阵
D3DXMatrixRotationY( &matFinal, -facing );
D3DXMatrixTranslation( &mx, position.x, position.y, position.z );
D3DXMatrixMultiply( &matFinal, &matFinal, &mx );
D3DXMatrixMultiply( &matFinal, &modelOrientation, &matFinal );
pd3dDevice->SetTransform(D3DTS_WORLD, &matFinal);
// 更新骨骼动画
pAnimController->AdvanceTime(fTimeDelta, NULL); //设置骨骼动画的时间
UpdateFrameMatrices(pFrameRoot, &matFinal); //更新框架中的变换矩阵
pd3dDevice->SetRenderState(D3DRS_LIGHTING, TRUE); //打开光照
//更新时间
prvTime = curTime;
curTime = prvTime + fTimeDelta ;
}
void Character::ChangeTrack(const char * name)
{
DWORD dwNewTrack = ( currentTrack == 0 ? 1 : 0 );
LPD3DXANIMATIONSET pAnimationSet = NULL;
pAnimController->GetAnimationSetByName( name , &pAnimationSet );
pAnimController->SetTrackAnimationSet( dwNewTrack, pAnimationSet );
pAnimationSet->Release();
pAnimController->UnkeyAllTrackEvents( currentTrack );
pAnimController->UnkeyAllTrackEvents( dwNewTrack );
pAnimController->KeyTrackEnable( currentTrack, FALSE, curTime + 0.125f );
pAnimController->KeyTrackSpeed( currentTrack, 0.0f, curTime, 0.125f, D3DXTRANSITION_LINEAR );
pAnimController->KeyTrackWeight( currentTrack, 0.0f, curTime, 0.125f, D3DXTRANSITION_LINEAR );
pAnimController->SetTrackEnable( dwNewTrack, TRUE );
pAnimController->KeyTrackSpeed( dwNewTrack, 1.0f, curTime, 0.125f, D3DXTRANSITION_LINEAR );
pAnimController->KeyTrackWeight( dwNewTrack, 1.0f, curTime, 0.125f, D3DXTRANSITION_LINEAR );
currentTrack = dwNewTrack;
}
void Character::ChangeTrack(DWORD name)
{
if(currentAnim == name )
{
LPD3DXANIMATIONSET pTrack;
pAnimController->GetTrackAnimationSet( currentTrack, &pTrack );
D3DXTRACK_DESC td;
pAnimController->GetTrackDesc( currentTrack, &td );
if( td.Position > pTrack->GetPeriod()/4 ) // come within the change delta of the end
return ;
} //要查看下当前轨道进行的程度,以免在轨道过渡时
DWORD dwNewTrack = ( currentTrack == 0 ? 1 : 0 );
LPD3DXANIMATIONSET pAnimationSet = NULL;
pAnimController->GetAnimationSet( name , &pAnimationSet );
pAnimController->SetTrackAnimationSet( dwNewTrack, pAnimationSet );
if(pAnimationSet)
pAnimationSet->Release();
pAnimController->UnkeyAllTrackEvents( currentTrack );
pAnimController->UnkeyAllTrackEvents( dwNewTrack );
pAnimController->KeyTrackEnable( currentTrack, FALSE, curTime + 0.125f );
pAnimController->KeyTrackSpeed( currentTrack, 0.0f, curTime, 0.125f, D3DXTRANSITION_LINEAR );
pAnimController->KeyTrackWeight( currentTrack, 0.0f, curTime, 0.125f, D3DXTRANSITION_LINEAR );
pAnimController->SetTrackEnable( dwNewTrack, TRUE );
pAnimController->KeyTrackSpeed( dwNewTrack, 1.0f, curTime, 0.125f, D3DXTRANSITION_LINEAR );
pAnimController->KeyTrackWeight( dwNewTrack, 1.0f, curTime, 0.125f, D3DXTRANSITION_LINEAR );
currentAnim = name;
currentTrack = dwNewTrack;
}
void Character::Draw()
{
pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE); //关闭光照
DrawFrame(pd3dDevice, pFrameRoot);
pd3dDevice->SetRenderState(D3DRS_LIGHTING, TRUE); //打开光照
}
DWORD Character::GetAnimIndex( char sString[] )
{
HRESULT hr;
LPD3DXANIMATIONSET pAS;
DWORD dwRet = -1;
for( DWORD i = 0; i < pAnimController->GetNumAnimationSets(); ++i )
{
hr = pAnimController->GetAnimationSet( i, &pAS );
if( FAILED( hr ) )
continue;
if( pAS->GetName() &&
!strncmp( pAS->GetName(), sString, min( strlen( pAS->GetName() ), strlen( sString ) ) ) )
{
dwRet = i;
pAS->Release();
break;
}
pAS->Release();
}
return dwRet;
}
void Character::Walk()
{
ChangeTrack(walk);
}
void Character::Run()
{
ChangeTrack(run);
}
void Character::Idle()
{
ChangeTrack(idle);
}
void Character::Attack()
{
ChangeTrack(attack);
}
代码资源:优快云资源