为了改变节奏,我想做一些开发日志。前段时间,我参加了一个游戏果酱,并制作了这款游戏—— 《老鼠和错误的选择》——一款简短的益智游戏,你在迷宫周围放置奶酪来引诱老鼠。这很有趣,但显然存在一些缺点。
主要问题之一是老鼠的行为不直观。玩家们提到,他们希望老鼠会被不喜欢的奶酪击退,而不仅仅是冻结。另外,实施这种机制将允许更丰富的谜题设计。
所以,我认为这是一个在 Godot 中进行自动化测试的好机会。
有一些测试框架可用于 Godot 4,但最吸引我的是Godot Unit Test (GUT) 。 GUT 非常简单:
test_
开头的函数并编写一些断言 - 典型的单元测试结构。
对于这种特殊情况,我希望有一种定义复杂场景的方法,就像我定义游戏级别一样 - 在引擎编辑器中而不是在代码中(这样,测试将更接近现实)。因此,我想做这些事情:
那么,让我们来揭开这个谜底。
让我们定义一个新类“MouseTestCase”。我们希望它继承Node2D
(因为我们希望将其放置在场景中)。并且我们希望它找到其子级(我们将自己放置在场景上):鼠标和其预期的最终位置(作为标记)
extends Node2D class_name MouseTestCase @export var steps_left = 0 # How many steps to simulate @export var done = false @onready var mouse: Mouse = $Mouse @onready var expected_position = SnapUtils.get_tile_map_position($TestMarker.position)
现在,我们可以把它放到场景中了,一切都很好!我们知道老鼠从哪里开始,我们知道它应该在哪里结束,以及需要走多少步。
现在,让我们制作更多的它们,并制作一张地图来测试我们的驱虫行为。
这种行为有些复杂,因此,我们想要涵盖许多略有不同的情况:
上面显示了定义 12 个测试用例来覆盖此行为的结果图(想象一下在代码中对所有这些坐标进行硬编码是多么乏味)。
唯一剩下要做的就是测试运行器功能。该函数需要:
代码非常简单。
func run_level_with_mouse_test_cases(map_path: String): var level = load(map_path) map.load_level(level) var cases = MouseTestCase.cast_all_cases(get_tree().get_nodes_in_group(MouseTestCase.MTC_GROUP_NAME)) while (cases.any(func(case): return not case.done)): map.move_mice() for case in cases: if not case.done: case.steps_left -= 1 if case.steps_left == 0: case.done = true assert_eq(case.get_mouse_position(), case.expected_position, case.get_parent().name+"/"+case.name)
我想这将会发展,但目前的实现已经足够好了。我已经编写了测试,实现了机制,并且测试实际上确认了机制已正确实现!
在这里,我展示了一种在游戏中进行测试的方法。显然,这里还有很多需要改进的地方,我鼓励读者采用代码和框架并根据自己的需求进行调整。
与往常一样,代码可以在 GitHub 上找到:https: //github.com/d-lowl/of-mice-and-bad-choices您还可以查看介绍测试的具体 PR 。对于奖励积分来说,如果有人能让他们在 CI 中工作,那就太好了。干杯。