Godot 游戏引擎优化指南/优化
游戏运行在拥有有限资源和 CPU 能力的机器上。手机或电脑在你的游戏开始卡顿之前只能做这么多。不过,有一些很好的方法可以解决这个问题。
尝试减少运行的代码量。提高游戏 FPS 的最佳方法是停止运行不需要运行的代码。例如,你不需要在每帧计算对象的碰撞,或者如果你根本不会与该对象发生碰撞,就更不需要了。对于经常更新的对象,尝试将更新延迟到下一帧,并使用最近的更新尝试。
当游戏在每帧进行复杂的计算时,游戏就会变得相当卡顿。尝试在使用计算结果之前将其存储在一个变量中。调用 get_node()
也会造成一点延迟,因此也尝试将它们缓存到一个变量中。
避免这种情况
var direction func _process(delta): var turret = $Turret direction = Vector2.UP.rotated(turret.rotation)
首选这种方式
var direction onready var turret = $Turret func _process(delta): direction = Vector2.UP.rotated(turret.rotation)
之后的代码示例比之前快 1%。听起来可能不多,但将这种优化应用到所有代码中就会累积起来。具有许多 get_node()
或 get_parent()
调用的较大函数比事先将它们缓存到变量中会造成更大的延迟。
没有必要进行不必要的数学运算。在循环之前缓存保持不变的计算结果。
这很慢
var alloy_strength = 1.0 var alloy_thickness = 5.0 var alloy_layers = 15.0 for robot in army: robot.armour = pow(alloy_strength * alloy_thickness, alloy_layers) + robot.native_armour
这更快
var alloy_strength = 1.0 var alloy_thickness = 5.0 var alloy_layers = 15.0 # Here, we're calculating the base armour rating of robots outside of the loop var base_armour = pow(alloy_strength * alloy_thickness, alloy_layers) for robot in army: robot.armour = base_armour + robot.native_armour
只访问一次或两次的小数组是可以忽略的。但是对于经常访问的较大数组,性能差异会累积起来。
# 0.115443 seconds for x in 1000: for y in 1000: var element = my_array[y][x] #... # 0.108107 seconds for x in 1000: for y in 1000: var element = my_array[y * 1000 + x] #... # 0.062938 seconds, about 45% faster than the first example for i in 1000000: var element = my_array[i] #...
通过使用 Godot 的原生迭代器而不是自己创建迭代器,你可以获得更大的性能提升
# 0.048952 seconds, almost 60% faster than the first example for x in 1000: for element in my_array[x]: #... # 0.047986 seconds for element in my_array: #...
你可能并不总是能够做到这一点,但值得记住。在使用数组时需要注意的主要事项是
- 一维数组比多维数组更快
- 单循环比嵌套循环更快
- 使用迭代器访问数组元素(例如,
for element in array
)比使用索引(例如,for i in array.size()
)更快。
每当你从数组中移除或添加元素时,都需要重新索引后面的所有元素,这意味着从数组开头添加/移除元素比从数组末尾添加/移除元素需要重新索引更多的元素。
在从数组中移除或添加元素时,优先使用 pop_back()
和 push_back()
或 append()
。避免使用 pop_front()
和 push_front()
。
以下三个经验法则可以帮助你决定应该使用数组还是字典。
print()
函数很慢。在导出游戏时尽量不要使用它。相反,创建自己的日志记录函数并自动加载它。示例
extends Node onready var log = File.new() func _ready(): log.open("res://log.txt", File.WRITE) func _exit_tree(): log.close() func log_message(message, source): var current_time = OS.get_time() log.write_line("%s (%s:%s:%s): %s" % [source, current_time.hour, current_time.minute, current_time.second, message])
使用 Godot 4.x 中的 静态类型 GDScript
[编辑 | 编辑源代码]使用静态类型带来的收益非常高,介于 50% 到 150% 之间。简而言之,原因是 Godot 在确定所有内容的类型以运行正确的逻辑时付出了更少的努力。
如果尝试获取节点的父节点(或上级节点),请不要使用 get_node('../../')
,因为它比直接使用 get_parent().get_parent()
慢 37%。当然,看起来更乱,但是如果你需要更快的代码,这就是你想要的方式。
较新的 Godot 稳定 版本具有更多优化,并且往往比旧版本性能更高。