UDN
Search public documentation:
UnrealScriptStatesCH
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 状态
概述
- 好处: 状态提供了一个用于来书写针对状态的函数的简单方法,所以你可以根据actor的行为以不同的方式来处理同一个函数。
- 好处: 使用状态,您可以使用完整的规范的UnrealScript命令和几个以"latent functions"著称的专用函数来书写专用的"state code(状态代码)"。一个latent函数的执行是比较慢的(也就是非阻塞的),并且可能要在一定的游戏时间过后才能返回。这可以使您进行基于时间的编程 – 这个主要的好处是无论是C, C++, 还是Java都没有提供的。也就是,你可以按照您想的方式来书写代码;比如,你书写一个脚本来表达"打开这个门; 暂停2s中; 播放这个音效;打开那个门;发放一个怪物来攻击玩家"。你可以通过使用简单的线性的代码来完成它,并且虚幻引擎会负责管理基于时间的代码执行的细节。
- 复杂性: 现在您可以多个状态及子类中重载函数(像 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 { ... }
状态标签和Latent函数
auto state MyState { Begin: `log( "MyState has just begun!" ); Sleep( 2.0 ); `log( "MyState has finished sleeping" ); goto('Begin'); }
"MyState has just begun!"
,接着它停止了2秒钟,然后它输出了信息 "MyState has finished sleeping"
。这个例子中的一个有趣的事情便是调用latent函数"Sleep": 这个函数的调用并不是立即返回,而是在一定量的游戏时间过去后才返回。Latent函数仅能在状态代码中并且不能从函数中调用。Latent函数可以帮助您管理包括一段时间的经过在内的一系列复杂的事件。
所有的状态代码都是以标签定义开始;在上面的例子中标签命名为"Begin"。标签提供了一个进入状态代码的方便的入口点。你可以在状态代码中使用任何标签名称,但是"Begin"标签是专用的: 它是那个状态的默认入口点。
所有的actor都有三个主要的latent函数可以使用:
- Sleep( float Seconds )使状态的执行暂停一段时间,然后再继续执行。
- FinishAnim()等待直到当前你正在播放的动画序列播放完成,然后继续执行。这个函数使编写由动画驱动的脚本(也就是执行是由网格物体动画控制的脚本)变得容易。比如,大多数AI脚本都是由动画驱动的(相对于有时间驱动的脚本),因为平滑过度的动画是AI系统的主要目标。
- FinishInterpolation()等待当前的InterpolationPoint移动完成然后继续。
- "Goto('标签名')"函数(和C/C++/Basic中的goto类似),该函数使状态代码在指定的标签处继续执行。
- 特殊的"Stop"命令,它会导致状态代码停止执行。状态代码在您到达一个新的状态或者到达当前状态中的一个新的标签之前将不会继续执行。
- "GotoState"函数会使actor跳转到一个新的状态,然后在指定的标签处继续执行(如果您没有指定一个标签,默认则是"Begin"标签)。你可以在状态代码中调用GotoState函数,它将会立刻跳转到目标状态。你也可以在actor中的任何函数中调用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" ); }
- 如果对象在一个状态中,并且函数的实现存在于那个状态的某处(不管是在actor类中还是在某个父类中),则调用最子类的状态函数版本。
- 否则,调用最底层派生函数的非状态版本。
高级的状态编程
// 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 时,它是作为latent函数的,所以和您在函数中调用 PushState 的代码执行行为是不同的。 从函数中调用 PushState 将不会中断代码的执行(就像在一个函数中使用GotoState一样),然而当从状态代码中调用它时将会暂停代码的执行,直到子状态被弹出为止(同样也和在状态代码中调用GotoState类似)。 一个状态只能被放到栈中一次,尝试将同一个状态压入堆栈两次将会失败。 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。