Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala游戏编程-在OOP和FP之间_Oop_Scala_Functional Programming - Fatal编程技术网

Scala游戏编程-在OOP和FP之间

Scala游戏编程-在OOP和FP之间,oop,scala,functional-programming,Oop,Scala,Functional Programming,我正在尝试用Scala&Processing编写一个教程游戏,希望尽可能多地使用FP。然而,我得出一个结论,不变的状态博弈对象在这样的应用中是无利可图的。如果一个对象很大,则在大量此类对象不断更新的情况下(因此,每个周期都要复制自身),例如,使用copy()func时,可能会导致相当大的内存消耗。解决这一问题的默认方法是什么?我唯一想到的是将对象切成小块对象,这样只有那些需要更新的对象才会更新,而“大”对象保持不变。首先,不要过早地进行优化。你测量过你的代码吗?也许有一些具体的瓶颈 由于大多数对

我正在尝试用Scala&Processing编写一个教程游戏,希望尽可能多地使用FP。然而,我得出一个结论,不变的状态博弈对象在这样的应用中是无利可图的。如果一个对象很大,则在大量此类对象不断更新的情况下(因此,每个周期都要复制自身),例如,使用
copy()
func时,可能会导致相当大的内存消耗。解决这一问题的默认方法是什么?我唯一想到的是将对象切成小块对象,这样只有那些需要更新的对象才会更新,而“大”对象保持不变。

首先,不要过早地进行优化。你测量过你的代码吗?也许有一些具体的瓶颈

由于大多数对象由通过数据结构连接的较小对象组成,我认为可以通过使用持久数据结构来解决这个问题

持久数据结构是一种始终保持 修改时自身的先前版本;此类数据 结构实际上是不可变的,因为它们的操作不可变 (明显地)在适当的位置更新结构,但始终生成 新的更新结构


关于他们中的一些人。如果你想了解更多,请看Chris Okasaki的文章。

游戏引擎本质上是一个(离散)事件模拟。通常,这些都是通过可变的数据结构实现的,例如事件堆、对象空间查询的四叉树/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)
要向武器添加更多弹药,您不必复制整个
世界

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))))
}
在此示例中,
map
、其他
Player
、以及修改后的
Player
shield
在内存中保持不变,不会被急切地复制


我建议使用可变数据结构来表示状态-除非您有一个并发游戏引擎(例如)一个模拟游戏状态的编写器和一系列呈现输出、处理声音、网络等的读卡器,在这个用例中,不可变的数据结构几乎没有任何好处。

只要承认游戏状态本质上是可变的就行了。仅将不可变类用于概念上的值,如位置、速度等。这可能仍然会产生大量垃圾,但在启用escape analysis的情况下运行可能会有所帮助。

可能是重复的,谢谢,Peter!我去过那里,它是相关的,充满了信息,但不采取相同的角度。阅读丹尼尔·斯皮瓦克的演讲,它将澄清你的“抄袭”神话。函数数据结构非常快问题是,对于您的用例来说,是否足够快?@Andreaschen谢谢大家,我发现这些参考非常有趣。我将尝试开发这些信息。
copy()
功能似乎将VAL转换为更昂贵、更安全的VAR变体,因为它允许像可变值(VAR)一样更改VAL。是吗?案例类上的
copy()
方法创建了一个新的案例类实例,其字段值与原始实例中的字段值相等,但您显式写入
=
的字段除外。但它不会进行深度复制-如果某些字段是案例类,则不会通过
copy()
复制该案例类实例,只复制对其的引用。