2012年5月26日 星期六

自訂Matinee軌道

UE的Matinee提供開發者在預定時間點變更物件屬性的功能,它是以軌道為基本單位來編排,例如一條軌道代表位置,另一條軌道代表顏色。它可以讓開發者自訂軌道來擴充新的功能。Matinee軌道的基礎類別是InterpTrack,編輯器會尋找所有的InterpTrack類別並且列舉出來。所以如果你自訂一個InterpTrack類別,編譯完就可以在下次開啟Matinee編輯器時看到它。

在Matinee編輯器中,左邊看到軌道名稱是寫在InterpTrack類別的TrackTitle屬性,左邊的圖示則由GetTrackIcon()函式指定。而按右鍵新增軌道時顯示的名稱是寫在當地化組態檔Descriptions.int裡。所以當自訂軌道時,記得要去新增一個名稱設定。

InterpTrack可以指定另外兩個擴充類別:
  • 其中一個是實例類別,用來維護執行狀態,由TrackInstClass屬性指定。
  • 另外一個是輔助類別,用來擴充編輯功能,由GetEdHelperClassName()函式指定。

一般而言,自訂InterpTrack通常也需要自訂實例類別,但輔助類別就不是每個InterpTrack都需要。

InterpTrack是以keyframe的方式記錄在預定時間點的屬性值,不同型別的屬性需要不同型別的記錄資料,所以InterpTrack類別本身並不會定義記錄記錄資料,而讓子類別來決定。InterpTrack會呼叫虛擬函式來通知子類別相關的事件,例如新增、刪除keyframe。所以InterpTrack的子類別可以覆載虛擬函式來擴充功能,以下列出重要的擴充函式:
  • AddKeyframe(Time, TrackInstance, InterpMode):在指定時間點新增一格keyframe。傳入的軌道實例物件型別會根據TrackInstClass屬性決定。
  • RemoveKeyframe(KeyIndex):刪除指定索引的keyframe。
  • UpdateKeyframe(KeyIndex, TrackInstance):更新指定索引的keyframe的值。通常作法是從傳入的軌道實例物件取得目前作用中的Actor,然後取得Actor上相關屬性目前的值,更新到指定索引的keyframe。
  • UpdateTrack(NewPosition, TrackInstance, bJump):更新物件屬性值到指定的時間點。通常作法是利用keyframe記錄資料計算出指定時間的屬性值,然後更新到TrackInstance作用中的Actor身上。

範例


下列程式碼展示如何自訂一個可動態變更DrawScale屬性的軌道。其實使用InterpTrackFloatProp可以達到相同效果,不過它會呼叫Actor類別的ForcedUpdateComponents()函式來暴力更新,而我們可以此呼叫比較有效率的Actor::SetDrawScale()。為了簡化範例,在此繼承自InterpTrackFloatBase,它定義一個型別為InterpCurveFloat的屬性叫FloatTrack來存放keyframe資料。
class MyInterpTrackDrawScale extends InterpTrackFloatBase
    native(Interpolation);

cpptext
{
    // InterpTrack interfaces
    virtual INT AddKeyframe(FLOAT Time, UINterpTrackInst* TrackInst, EInterpCurveMode InitInterpMode)
    {
        INT NewKeyIndex = FloatTrack.AddPoint( Time, 0.f );        
        FloatTrack.Points(NewKeyIndex).InterpMode = InitInterpMode;       

        UpdateKeyframe( NewKeyIndex, TrackInst );       

        FloatTrack.AutoSetTangents(CurveTension);       

        return NewKeyIndex;
    }

    virtual void UpdateKeyframe(INT KeyIndex, UInterpTrackInst* TrackInst)
    {
        AActor* Actor = TrackInst->GetGroupActor();
        if( Actor && FloatTrack.Points.IsValidIndex(KeyIndex) )
        {
            FloatTrack.Points(KeyIndex).OutVal = Actor->DrawScale;
            FloatTrack.AutoSetTangents(CurveTension);
        }  
    }

    virtual void PreviewUpdateTrack(FLOAT NewPosition, UInterpTrackInst* TrackInst)
    {
        UpdateTrack(FLOAT NewPosition, UInterpTrackInst* TrackInst)
    }

    virtual void UpdateTrack(FLOAT NewPosition, UInterpTrackInst* TrackInst, UBOOL bJump)
    {
        AActor* Actor = TrackInst->GetGroupActor();
        if( Actor )
        {
            FLOAT NewFloatValue = FloatTrack.Eval( NewPosition, Actor->DrawScale );
            Actor->SetDrawScale( NewFloatValue );
        }      
    }
}

defaultproperites
{
    TrackInstClass=class'MyGame.MyInterpTrackInstDrawScale'
    TrackTitle="Draw Scale"
}
我們需要自訂對應的實例類別MyInterpTrackInstDrawScale,用來在編輯器預覽時記錄和恢復DrawScale。但不需要使用輔助類別。
class MyInterpTrackInstDrawScale extends InterpTrackInst
    native(Interpolation);

var float SavedDrawScale;

cpptext
{
    virtual void SetActorState(UInterpTrack* Track)
    {
        AActor* Actor = GetGroupActor();
        if( Actor )
        {  
            SavedDrawScale = Actor->DrawScale;
        }
    }

    virtual void RestoreActorState(UInterpTrack* Track)
    {
        AActor* Actor = GetGroupActor();
        if( Actor )
        {  
            Actor->SetDrawScale( SavedDrawScale );
        }  
    }  
}

沒有留言:

張貼留言