2013年1月9日 星期三

自訂UnrealScript休眠函式

UnrealScript的休眠函式(latent function)提供開發者一個簡便的寫法等待某個條件完成。可以在Actor.uc裡找到其中兩個內建的休眠函式:
// Latent functions.
native(256) final latent function Sleep( float Seconds );
native(261) final latent function FinishAnim( AnimNodeSequence SeqNode, optional bool bFinishOnBlendOut );
休眠函式只能在類別的狀態(state)中呼叫,它會暫停目前狀態內的程式執行,直到指定的條件達成。下例中的GotoState()會等Sleep(1)完成後才執行:
class MyPawn extends GamePawn;

state Idle
{
    event BeginState(Name PreviousStateName)
    {
        Sleep(1);
        GotoState('');
    }
}
開發者也可自訂休眠函式,宣告休眠函式時要加上latent關鍵字。實作休眠函式需要寫另一個輪詢函式檢查是否要中止暫停繼續執行,以及選擇一個小於4096的整數做為這個休眠函式的索引值。休眠函式必須將索引值填入該物件的休眠代碼以暫停狀態執行,而輪詢函式必須在繼續執行時重設休眠代碼為零。而且輪詢函式必須以該索引值註冊。

索引值需要跟其他休眠函式錯開,也必須跟UnrealScript的所有指令代碼錯開才行,因為它們都註冊在GNatives函式指標陣列中。為了確保索引值不重覆,可以直接啟動C++除錯查看GNatives陣列裡未被使用的空位。

範例


以下程式碼示範如何自訂一個會等待音效播完的休眠函式:
class MyLatentFunction extends Actor
    native;
    
var AudioComponent LatentAudioComp;

native latent function FinishSound( AudioComponent AudioComp );

cpptext
{
    DECLARE_FUNCTION(execPollFinishSound);
}
FinishSound() 宣告為休眠函式,而execPollFinishSound()註冊為它的輪詢函式:
enum
{
    EPOLL_FinishSound = EPOLL_FinishAnim + 1,
};

void AMyLatentFunction::FinishSound( UAudioComponent* AudioComp )
{
    GetStateFrame()->LatentAction = EPOLL_FinishSound;
    LatentAudioComp = AudioComp;
}

void AMyLatentFunction::execPollFinishSound( FFrame& Stack, RESULT_DECL )
{
    if( !LatentAudioComp || !LatentAudioComp->IsPlaying() )
    {
        GetStateFrame()->LatentAction = 0;
        LatentAudioComp = NULL;        
    }
}
IMPLEMENT_FUNCTION( AMyLatentFunction, EPOLL_FinishSound, execPollFinishSound );
測試碼:
class TestLatentFunction extends MyLatentFunction;

var SoundCue Sound;

var AudioComponent AudioComp;

function Test(SoundCue InSound)
{
    Sound = InSound;
    GotoState("PlayingSound");
}

state PlayingSound
{
Begin:

    AudioComp = CreateAudioComponent(Sound, true);
    FinishSound(AudioComp);
    
    GotoState('');
}
class MyCheatManager extends CheatManager;

exec function TestLatentFunction(SoundCue InSound)
{
    local TestLatentFunction TLF;
    TLF = Pawn.Spawn(class'TestLatentFunction');
    TLF.Test(InSound);
}

沒有留言:

張貼留言