DirectX游戏开发之3D角色动起(下)

DirectX游戏开发之3D角色动起(下)

直接先上图吧!
动作idle
idle
动作attack
attack
动作walk
walk
动作run
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);
}

代码资源:CSDN资源

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值