除了纯函数的概念之外,我对函数式编程知之甚少.在约翰卡马克2013年的Quakecon演讲中,他提到了一个常常被问及与游戏相关的函数式编程的问题:如果你无法访问状态,你如何开枪并对另一个玩家造成伤害?(转述)在提到一个关于事件系统的事情,我不太明白,因为在我看来事件系统仍然需要状态?
如何用纯函数语言实现这一目标?
重复我最喜欢的一句话
......进入世界状态,回归新世界,保持纯洁.
这是在谈论Clean,Haskell的堂兄,但它仍然是相关的.它的要点是,你是对的,你需要某种状态,但它不一定是可变的.考虑
myFun :: StateOfTheWorld -> a -> (StateOfTheWorld, b)
所以我们不修改状态,我们只是生成一个新状态.这是参考透明的,因为给定相同的世界状态和相同的动作,你将得到同样的回报.
对你来说你可能有类似的东西
killPlayer :: Game -> Event -> Game killPlayer g (Kill x) = g { isDead = x : isDead g }
这只是使用记录的功能更新.这有点笨拙,所以我们可能会做类似的事情
killPlayer :: Game -> Event -> Action killPlayer (PlayerDamaged x amount) = if playerHealth g x <= amount then KillPlayer x else ReduceHealth x amount
所以我们只是回归差异,而不是完整的游戏状态.
这有效,但很难看.所以我们用do
符号和Control.Monad.State来解决这个问题.这听起来很可怕,但它正是我们上面所做的,只是更多的语法抽象.事实上,这也是IO
GHC的内容.我不知道你是否了解过Monads,但State monad通常是激励的例子.
最后回到游戏,我见过的很多游戏框架都是这样的:成堆的东西听取事件然后建议对游戏状态进行一些小的增量更改并返回不同的,最后框架本身会进行适当的openGL调用或者任何实现这些变化的东西.