non*_*com 3 oop functional-programming scala
我正在尝试在Scala和Processing中编写一个教程游戏,打算尽可能多地使用FP.但是,我得出结论,不可变状态游戏对象在这样的应用程序中是无利可图的.如果一个对象很大,那么在许多这样的对象被不断更新的情况下(因此,每个周期自己复制一次),例如使用copy()func ,它可能导致非常密集的内存消耗.坚决这个的默认方法是什么?我想出的唯一一件事就是将对象切成小块 - 对象,这样只有那些需要更新的对象才会被更新,同时让"大"对象保持不变.
游戏引擎本质上是一种(离散的)事件模拟.通常,这些是通过可变数据结构实现的,例如事件的堆,关于对象的空间查询的quad/oct树和大量的哈希表.
对于这些数据结构中的每一个,可变变体更快.此外,不可变数据结构会产生必须收集的垃圾,因此GC上的压力会更高,并且您的应用程序最终会变慢.在实时关注的情况下,GC暂停可能是有害的(例如,它可能会影响游戏中的帧速率),尤其是在处理能力较低的平台上,例如Android.
至于copy()方法 - 它不必复制整个对象来创建更新版本.如果您的对象以树状方式分层组织(例如,作为案例类的层次结构),则更改对象的一个属性需要仅重写此树中的一个路径 - 您不需要重写所有内容.尽管如此,它还是比具有可变版本和就地更新更昂贵.
例:
case class World(map: Array[Item], players: Vector[Player])
case class Player(health: Int, speed: Int, weapon: Weapon, shield: Shield)
case class Weapon(strength: Int, ammo: Int)
Run Code Online (Sandbox Code Playgroud)
要为武器添加更多弹药,您不必复制整个弹药World:
def setAmmo(playerNum: Int, newAmmo: Int, world: World): World = {
val p = players(playerNum)
world.copy(players = players.updated(playerNum, p.copy(weapon = p.weapon.copy(ammo = newAmmo))))
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中map,其他players和shield修改Player后的内容在内存中保持不变并且不会被急切复制.
我建议使用可变数据结构来表示状态 - 除非你有一个并发游戏引擎(例如)一个模拟游戏状态的编写器,以及一系列呈现输出,处理声音,网络等的读者在这个用例中,不可变数据结构的好处几乎没有.
首先,不要做过早的优化.你测量过代码了吗?也许有一些具体的瓶颈?
由于大多数对象都是由通过数据结构连接的较小对象组成,我认为你可以通过使用持久数据结构来解决这个问题 .
持久数据结构是一种数据结构,它在修改时始终保留自身的先前版本; 这样的数据结构实际上是不可变的,因为它们的操作不会(可见地)就地更新结构,而是始终产生新的更新结构
以下是Daniel Spiewak对其中一些人的精彩演讲.如果您需要更多,请查看Chris Okasaki的Purely Functional Data Structures.