跳转到内容

Godot 游戏引擎优化指南/优化

50% developed
来自维基教科书,开放世界中的开放书籍

游戏运行在拥有有限资源和 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()

[编辑 | 编辑源代码]

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_parent().get_parent(),而不是 get_node('../../')

[编辑 | 编辑源代码]

如果尝试获取节点的父节点(或上级节点),请不要使用 get_node('../../'),因为它比直接使用 get_parent().get_parent() 慢 37%。当然,看起来更乱,但是如果你需要更快的代码,这就是你想要的方式。

使用最新的稳定版本

[编辑 | 编辑源代码]

较新的 Godot 稳定 版本具有更多优化,并且往往比旧版本性能更高。



Godot 游戏引擎指南

入门 [编辑]
安装
什么是节点?
编程
资源和导入
信号和方法
你的第一个游戏
使它工作
调试
输入
物理
保存和加载
多人游戏
使它看起来更好
UI 皮肤
动画
高级帮助
服务器(单例)
平台特定
优化
加密
导出
插件
杂项
有用链接
作者和贡献者
打印版本


<-- 上一页 返回顶部 下一页 -->

华夏公益教科书