UDN
Search public documentation:
UnrealScriptStatesJP
English Translation
中国翻译
한국어
Interested in the Unreal Engine?
Visit the Unreal Technology site.
Looking for jobs and company info?
Check out the Epic games site.
Questions about support via UDN?
Contact the UDN Staff
中国翻译
한국어
Interested in the Unreal Engine?
Visit the Unreal Technology site.
Looking for jobs and company info?
Check out the Epic games site.
Questions about support via UDN?
Contact the UDN Staff
UnrealScript のステート
概要
- 利点 1 : ステートを使用することによって、ステート固有の関数を簡単に書くことができます。そのため、アクタの行なっていることに基づいて、同じ関数を異なるやり方で処理することができます。
- 利点 2 : ステートを使用することによって、特別な「ステートコード」を書くことができます。そのためには、通常の UnrealScript コマンドに加え、「潜在関数」として知られているいくつかの特殊な関数を使用します。潜在関数とは、「ゆっくり」 (すなわちノンブロッキングで) 実行される関数で、一定のゲーム時間 ( game time ) が経過した後に値を返します。これによって、時間ベースのプログラミングを行うことが可能になります。このことは、C、C++、Java にはない大きな利点です。すなわち、考えたとおりにコードを書くことができるのです。たとえば、スクリプトをあたかも次のように書くことができます。「このドアを開ける。2 秒待つ。このサウンドエフェクトを再生する。そのドアを開ける。モンスターをリリースして、プレーヤを攻撃させる」というように。つまり、単純で直線的なコードを書くことができます。時間ベースによるコード実行管理の詳細部分は、UnrealEngine が処理します。
- 問題点: 子クラスの中で行うのと同じように、複数のステートの中で ( Touch のような) 関数をオーバーライドしたため、どの Touch 関数をどのような状況で呼び出すべきかといった問題が多数生じ、それを正確に把握しておかなければなりません。UnrealScript には、このプロセスを明確に定めた規則がありますが、この問題は、クラスとステートの複雑な階層を作成する場合に認識しておくべきものです。
// Trigger turns the light on. state() TriggerTurnsOn { function Trigger( actor Other, pawn EventInstigator ) { Trigger = None; Direction = 1.0; Enable( 'Tick' ); } } // Trigger turns the light off. state() TriggerTurnsOff { function Trigger( actor Other, pawn EventInstigator ) { Trigger = None; Direction = -1.0; Enable( 'Tick' ); } }
state() MyState { ... }
state MyState { ... }
auto state MyState { ... }
ステートラベルと潜在関数
auto state MyState { Begin: `log( "MyState has just begun!" ); Sleep( 2.0 ); `log( "MyState has finished sleeping" ); goto('Begin'); }
”MyState has just begun!”
( MyState が開始しました!) というメッセージを表示し、そこから 2 秒間休止し、さらに、 "MyState has finished sleeping"
( MyState のスリープが終了しました!) というメッセージを表示します。この例で面白いのは、潜在関数 Sleep の呼び出しです。この関数呼び出しは、すぐに値を返さず、一定のゲーム時間が経過した後に値を返しています。潜在関数は、ステートコード内からのみ呼び出すことができ、関数内から呼び出すことはできません。潜在関数を使用すると、時間の経過がかかわる複雑なイベントの連鎖をうまく管理することができます。
すべてのステートコードは、ラベルの定義から始まります。上記の例では、ラベルが「Begin」と名付けられています。ステートコードにおいて、ラベルは便利なエントリポイントとなります。ステートコードではあらゆるラベル名を使用することができますが、Begin ラベルは特別です。この Begin ラベルは、そのステートコードにおけるデフォルトの開始点となります。
すべてのアクタで、次の 3 つの主要な潜在関数を利用することができます。
- Sleep( float Seconds ) は、ステートの実行を一定時間休止した後で再開させます。
- FinishAnim() は、現在再生中のアニメーションシーケンスが終了するのを待ってから再開させます。この関数を使用することによって、アニメーション主導のスクリプト (実行がメッシュアニメーションによって制御されているスクリプト) を簡単に書けるようになります。たとえば、AI スクリプトのほとんどはアニメーション主導です (時間主導ではなく)。これは、なめらかなアニメーションが AI システムの主要な目標であるからです。
- FinishInterpolation() は、現在の InterpolationPoint の動作が終了するのを待ってから再開します。
- ステートコード内の Goto('LabelName') 関数(C/C++/Basic の goto に相等) は、指定されたラベルにおいてステートコードの実行を継続します。
- ステート内の特別な Stop コマンドは、ステートコードの実行を停止します。ステートコードの実行が再開されるのは、新しいステートになるか、現在のステート内で新しいラベルに入った場合です。
- GotoState 関数は、アクタを新しいステートにします。オプションとして、指定されたラベルで実行を継続させます。(ラベルを指定しない場合、デフォルトは Begin ラベルとなります)。ステートコード内から GotoState を呼び出し、直接、目的のステートへ行くことができます。また、アクタ内のどの関数内からでも GotoState を呼び出すことができますが、すぐには有効になりません。実行がステートコードに戻るまでは有効にならないためです。
// This is the automatic state to execute. auto state Idle { // When touched by another actor... function Touch( actor Other ) { `log( "I was touched, so I'm going to Attacking" ); GotoState( 'Attacking' ); `log( "I have gone to the Attacking state" ); } Begin: `log( "I am idle..." ); sleep( 10 ); goto 'Begin'; } // Attacking state. state Attacking { Begin: `log( "I am executing the attacking state code" ); ... }
I am idle... I am idle... I am idle... I was touched, so I'm going to Attacking I have gone to the Attacking state I am executing the attacking state code
ステートの継承とスコープの規則
- 新しいクラスは、その親クラスからすべての変数を継承する。
- 新しいクラスは、その親クラスの非ステート関数をすべて継承する。継承された非ステート関数は、どれもオーバーライドすることができる。また、完全に新しい非ステート関数を追加することができる。
- 新しいクラスは、親クラスのステートをすべて継承する。これには、ステート内の関数とラベルも含まれている。継承されたステート関数は、どれもオーバーライドすることができる。また、継承されたステートラベルは、どれもオーバーライドすることができ、新たなステート関数および新たなステートラベルを追加することができる。
// Here is an example parent class. class MyParentClass extends Actor; // A non-state function. function MyInstanceFunction() { `log( "Executing MyInstanceFunction" ); } // A state. state MyState { // A state function. function MyStateFunction() { `log( "Executing MyStateFunction" ); } // The "Begin" label. Begin: `log("Beginning MyState"); } // Here is an example child class. class MyChildClass extends MyParentClass; // Here I'm overriding a non-state function. function MyInstanceFunction() { `log( "Executing MyInstanceFunction in child class" ); } // Here I'm redeclaring MyState so that I can override MyStateFunction. state MyState { // Here I'm overriding MyStateFunction. function MyStateFunction() { `log( "Executing MyStateFunction" ); } // Here I'm overriding the "Begin" label. Begin: `log( "Beginning MyState in MyChildClass" ); }
- そうでない場合は、最派生の非ステートバージョンの関数が呼び出される。
高度なステートのプログラミング
// Base Attacking state. state Attacking { // Stick base functions here... } // Attacking up-close. state MeleeAttacking extends Attacking { // Stick specialized functions here... } // Attacking from a distance. state RangeAttacking extends Attacking { // Stick specialized functions here... }
ignores
指定子 (オプション) を使用することによって、そのステートにある間は、関数を無視することができます。この場合の構文は次のとおりです。
// Declare a state. state Retreating { // Ignore the following messages... ignores Touch, UnTouch, MyFunction; // Stick functions here... }
ステート スタッキング
通常のステート変更では、あるステートから別のステートへ入ると、既に終了している前回のステートに戻ることはできません。ステート スタッキングを利用すると、これが可能になります。 PushState 関数を呼び出すことによって、新しいステートに変わり、その新しいステートがスタックの最上部に置かれます。現在のステートは、凍結されます。 PopState を呼び出すと、前のステートがリストアされ、 PushState が呼び出された地点から実行が再開されます。 PushState 関数は、可能な場合潜在関数として機能します (ステートコード内部においてのみ)。したがって、 PushState を関数外部から呼び出す場合は、コード実行の動作が異なります。PushState を関数から呼び出してもコードの実行を妨害しません (関数内部から呼び出された GotoState と同様です)。一方、PushState をステートコード内部から呼び出すと、子クラスがポップされるまでコードの実行が休止されます (この点においても関数内部から呼び出さた GotoState と同様です)。 ステートをスタックに置けるのは一度だけです。同じステートを2回スタックに置こうとすると、失敗します。 PushState は、 GotoState と同じように機能し、ステート名とステートのエントリポイントのためのラベル (オプション) を引数に取ります。新しいステートは PushedState イベントを受け取り、現在のステートは PausedState イベントを受け取ります。 PopState の呼び出し後は、現在のステートは PoppedState イベントを受けとり、新たなステート (スタック上で次に位置していたステート) は、 ContinuedState を受けとります。state FirstState { function Myfunction() { doSomething(); PushState('SecondState'); // this will be executed immediately since we're inside of a function (no latent functionality) JustPushedSecondState(); } Begin: doSomething(); PushState('SecondState'); // this will be executed once SecondState is popped since we're inside of a state code block (latent functionality) JustPoppedSecondState(); } state SecondState { event PushState() { // we got pushed, push back PopState(); } }
state BaseState { ... } state ExtendedState extends BaseState { ... }
ExtendedState
である場合、 IsInState('BaseState') が false を返します。もちろん、 BaseState がスタック上にある場合は、 IsInState('BaseState', true) を呼びだすと true が返されます。