作者littleshan (我要加入剑道社!)
看板GameDesign
标题[程式] 使用 Coroutine 改写状态机-续
时间Fri Jun 29 10:29:04 2012
图文版
http://goo.gl/isGmI
这是 coroutine 系列的最後一篇。相较於状态机,coroutine 的优势除了程式
码比较容易理解外,还有可重覆利用的特性。
在这篇文章中,我们会以对话框作为范例,探讨如何让这个游戏中的常见功能变
得容易使用。
我们要制作的对话框看起来非常简单,就像这样:
http://goo.gl/knN7d
这种对话框在游戏中相当常见,我们先试着用状态机来实作看看。
使用状态机的情况
对话框的各个 state 长这样:
A(确定时的下一个 state)
动画结束 点击 ↗
淡入 ---→ 等待 ---→ 淡出
↘
B(取消时的下一个 state)
因此我们需要定义三个 state。由於程式码已经超过 100 行,我贴在 codepad
上,但它还是很重要,请不要因此偷懒不看 XD
http://codepad.org/TwqXUMBY
理论上,不管在任何 state,只要让状态机转移到 DIALOG_ENTER 这个状态,就
相当於呼叫了对话框功能,对话框会开始播放动画,接着移动到 DIALOG_WAIT
状态等待玩家选择。然而在对话框结束後我们却遇到一个困难:既然状态机中的
任意 state 都可以「呼叫」对话框功能,我们怎麽知道对话框结束後要转移到哪
一个 state 呢?总不能让每个对话框都结束游戏吧?
? ?(确定)
↘ 动画结束 点击 ↗
?-→淡入 ---→ 等待 ---→ 淡出 (下一个状态取决於由哪个状态进入)
↗ ↘
? ?(取消)
简单而有效的解法是在进入 DIALOG_ENTER 之前,先在两个全域变数中设定「确定」
与「取消」所对应到的状态,这麽一来在 DIALOG_LEAVE 就知道下一个 state 是什
麽了。
-- 确定和取消所对应到的下一个 state
-- 需要在进入 DIALOG_ENTER 之前的 state 负责设定
ok_state =
"fill next state when player hit OK"
cancel_state =
"fill next state when player hit CANCEL"
state_table[
"DIALOG_LEAVE"] =
{
...,
update =
function()
if system.getTimer() > animation_end
then
if answer
then
gotoState(ok_state)
else
gotoState(cancel_state)
end
end
end
}
总结来说,在状态机内若要呼叫对话框功能,需要以下的操作:
1. 设定全域变数 dialog_text 作为对话框的文字。
2. 设定全域变数 ok_state 及 cancel_state 作为玩家选择後要转移的
目标 state。
3. 把目前 state 转移至 DIALOG_ENTER
Coroutine 的情况
回过头来看看使用 coroutine 的情况。它的实作并不难,就只是个长一点的函式:
http://codepad.org/6gdHmH1e
(虽然说长一点,但才五十多行!真的)
除了流程更加清楚以外,coroutine 还具备以下的优势:
1. 不需要用全域变数来传递参数或取得回传值。
2. 它只是个函式呼叫,我们不需要知道函式被谁呼叫--它在 return 时会
自然回到呼叫端。
结语
状态机并非一无可取。在某些没有结构化流程中,使用 coroutine 改写反而较为
困难,比如下面这个例子:
A → B
↓ ↗ ↓
D → C
然而,使用状态机就像只用 goto 而不使用函式或回圈来写程式,面对更加复杂的
流程就显得难以建构与维护。游戏中需要状态机的场合,大部份都是具有结构化的
流程,因此使用 coroutine 就相当适合。
* * * * * *
断断续续写了快一个月的 coroutine 系列总算告一段落了,文章中程式码所占的
比例也达到恐怖的程度。原本我曾想过,在文章中加入这麽多程式码是否洽当,
但若不把程式码真的写出来,实在很难理解为何 coroutine 可以让流程变得清楚
易懂。
另一方面,使用 coroutine 通常也会搭配大量的 function object 与 closure,
希望各位细细品尝它们的威力。
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 220.135.3.139
1F:推 cowbaying:全系列4篇已收精华4-20 06/29 17:53
※ 编辑: littleshan 来自: 202.39.238.241 (07/08 17:57)
2F:推 wangm4a1:推 07/13 23:52