ゲームプログラムのメモ書き

DirectX

一つのスキンメッシュで複数のキャラを制御する

ゲームを制作する上でキャラクタの複数表示は必須です。 それぞれのキャラが独立したアニメーションをしなければいけません。 しかし1オブジェクトごとにファイルを読み込んでいてはメモリがいくらあっても足りません。 そこで、1つのXファイルで複数のオブジェクトを独立してアニメーションさせてみます。

					
//アニメーションメッシュ構造体
struct ANIMATION
{
    LPD3DXFRAME pFrameRoot;
    LPD3DXANIMATIONCONTROLLER pAC;
    LPD3DXANIMATIONSET pAnimSet[10];	//可変長にした方が良いがコード簡略のため固定数。
};

// 物体構造体
struct THING
{   
    D3DXVECTOR3 vecPosition;
    D3DXMATRIX matRotation;
    D3DXMATRIX matWorld;
    LPD3DXANIMATIONCONTROLLER pAC;
};

まずはどれが複数必要で、どれが一つで済むのかをまとめておきます。ANIMATION構造体はXファイル一種類につき、 1つ用意します。読み込むXファイルの種類を増やしたい場合はこれを複数定義すれば良いです。 THING構造体は一つのXファイルで表示させる物体数だけ用意します。





//Xファイルの読み込み
HRESULT LoadXFile(LPDIRECT3DDEVICE9 pDevice,ANIMATION *pAnim, LPSTR szXFileName)
{
    if( FAILED( D3DXLoadMeshHierarchyFromX(
        szXFileName,
        D3DXMESH_MANAGED,
        pDevice, &cHierarchy, 
        NULL,
        &pAnim->pFrameRoot,
        &pAnim->pAC)))
    {
            MessageBox(NULL, "Xファイルの読み込みに失敗しました",szXFileName, MB_OK);
            return E_FAIL;   
    }

    //アニメーショントラックを得る
    for(DWORD i=0;i<pAnim->pAC->GetNumAnimationSets();i++)
    {
        pAnim->pAC->GetAnimationSet(i,&pAnim->pAnimSet[i]);
        pAnim->pAnimSet[i]->Release();
    }

    //ボーン行列の初期化
    AllocateAllBoneMatrices(pAnim,pAnim->pFrameRoot);

    return S_OK;
}

Xファイルの読み込みです。読み込み部分は通常の読み込みと変わりありません。
今回は複数アニメーションの解説のためAllocateAllBoneMatrices()などの解説は省きます。





THING Thing[THING_AMOUNT];	//物体数
ANIMATION Anim;             //アニメーションメッシュ


//Xファイルを読み込む
LoadXFile(pDevice, &Anim, "ファイル名.x");

for(DWORD i = 0 ; i < THING_AMOUNT ; i++)
{
    //アニメーションコントローラのコピーを作る
    Anim.pAC->CloneAnimationController(
        Anim.pAC->GetMaxNumAnimationOutputs(),
        Anim.pAC->GetMaxNumAnimationSets(),
        Anim.pAC->GetMaxNumTracks(),
        Anim.pAC->GetMaxNumEvents(),
        &Thing[i].pAC);
}

CloneAnimationController関数はその名の通りアニメーションコントローラのコピーを作ります。




//物体を描画する
VOID Render(THING* pThing, ANIMATION* pAnim)
{
    //ワールド変換、ビュー変換、射影変換
    //ライトの設定
    //
    //     省略
    //



    //アニメーションの更新
    pThing->pAC->AdvanceTime(0.1, NULL);

    //フレームの更新
    UpdateFrameMatrices(pAnim->pFrameRoot, &matWorld);
    //描画
    DrawFrame(pDevice,pAnim->pFrameRoot);
}

描画部分です。各変換やライトの設定は省略しています。 Render関数内で特に書く順序に気をつけなければいけない部分があります。 AdvanceTime()です。これをフレーム行列の更新より前に書いて下さい。後に書くとアニメーションさせたいオブジェクトでは無いオブジェクトが動き出したりします。アニメーションコントローラとフレーム行列は裏で結ばれているので順序は慎重に決める必要があります。
(筆者はこの問題に衝突し長い間アニメーション部分が停滞中でした。(その間に他のことが実装出来ましたが・・・)