unit-testing - 在 KinematicBody2D 上调用 get_position 会导致 get_global_transform 错误
问题描述
概括
我正在尝试使用Gut为我player
的 in gdscriptget_position()
编写单元测试,但调用player
(a KinematicBody2D)会导致以下错误:
ERROR: get_global_transform: Condition "!is_inside_tree()" is true. Returned: get_transform()
At: scene/2d/canvas_item.cpp:467.
ERROR: body_test_motion: Condition "!body->get_space()" is true. Returned: false
At: servers/physics_2d/physics_2d_server_sw.cpp:1046.
ERROR: get_global_transform: Condition "!is_inside_tree()" is true. Returned: get_transform()
At: scene/2d/canvas_item.cpp:467.
ERROR: body_test_ray_separation: Condition "!body->get_space()" is true. Returned: false
At: servers/physics_2d/physics_2d_server_sw.cpp:1058.
期待
我期待在_physics_process()
我能够获得position
我的更新player
但它返回之后Vector2(0, 0)
。
资源
这是我第一次使用 GDScript,所以我一直在混合使用以下资源来尝试编写第一个测试:
失败的解决方案
我想我可能需要让player
其他东西成为孩子,但我不确定如何在我的测试中做到这一点。
我尝试搜索有关如何在测试中使用的肠道问题add_child()
,但找不到答案。
我也尝试过制作player
an 的孩子,Area2D
但这似乎也不起作用:
var player := Player.new(input)
var area := Area2D.new()
area.add_child(player)
代码
gut
这是从命令行调用时导致错误的代码:
test/unit/actors/test_player.gd
extends "res://addons/gut/test.gd"
func test_can_create_player() -> void:
var input = MockInput.new()
var player := Player.new(input)
assert_not_null(player)
func test_can_move_player_up() -> void:
var input = MockInput.new()
input.press("ui_up")
var player := Player.new(input)
simulate(player, 1, .1)
assert_eq(player.get_position(), Vector2(200, 0))
test/mock_input.gd
class_name MockInput
var _pressed: Dictionary = {}
func press(key: String) -> void:
_pressed[key] = true
func release(key: String) -> void:
_pressed[key] = false
func is_action_pressed(key: String) -> bool:
if _pressed.has(key):
return _pressed.get(key)
return false
entities/actors/player.gd
extends KinematicBody2D
class_name Player
export var speed: int = 200
var _input: Object = Input
var _velocity: Vector2 = Vector2()
func _init(input: Object = Input):
_input = input
func _physics_process(_delta: float) -> void:
_velocity = Vector2()
if _input.is_action_pressed("ui_right"):
_velocity.x += 1
if _input.is_action_pressed("ui_left"):
_velocity.x -= 1
if _input.is_action_pressed("ui_down"):
_velocity.y += 1
if _input.is_action_pressed("ui_up"):
_velocity.y -= 1
_velocity = _velocity.normalized() * speed
_velocity = move_and_slide(_velocity)
解决方案
错误告诉你!is_inside_tree()
。问题不仅在于节点没有父节点。问题是它不在SceneTree
.
您可以创建自己的SceneTree
. 你甚至可以扩展它。例如,这将起作用:
var node := KinematicBody2D.new()
var tree := SceneTree.new()
tree.get_root().add_child(node)
yield(tree, "idle_frame")
print(node.get_global_transform())
现在,关于 Gut……您的测试将在SceneTree
. 因此,您可以将要测试的节点添加为子节点。请记住进行适当的拆卸(删除节点)。因为 Gut 不会为你做这件事,如果子节点从一个测试到另一个测试,那么它们就不再是单元了。
附录:您可以使用add_child_autofree
添加一个孩子,也可以在测试结束后将其排队等待释放。
剩下的答案是我回顾 Gut 如何运行测试以确认它们在 SceneTree 中运行。
该文件gut_cmdln.gd
实际上是一个扩展的SceneTree
. 它将加载gut.gd
(此处)并将其作为节点添加到自身(此处)。
反过来,gut.gd
负责运行测试,由_test_the_scripts
. 我想让你看的是这个:
var test_script = the_script.get_new()
var script_result = null
_setup_script(test_script)
有the_script
一个TestScript
对象。该get_new
调用将返回一个实例。还有_setup_script
……</p>
func _setup_script(test_script):
test_script.gut = self
test_script.set_logger(_lgr)
add_child(test_script)
_test_script_objects.append(test_script)
将其添加为子项(的gud.gd
)。
之后_test_the_scripts
将进入一个循环(这里)并调用_run_test
或_run_parameterized_test
(调用_run_test
)来实际运行测试。并将在实例上_run_test
使用call
来运行测试方法(带有额外的步骤)。
胡扎!您的测试将在自定义的SceneTree
.
推荐阅读
- python - 当我单击一个按钮时,kivy recycleview 中的不同按钮会闪烁
- django - Django将字段错误添加到非模型表单字段
- java - 通过方法调用传递 Graphics g
- node.js - 如何让 Lambda 函数等待异步操作完成?
- javascript - 浏览器中的前端原始 TCP/UDP 套接字,在 2021 年有什么办法吗?
- azure - keyVaultClient - 获取秘密
- python - 在numpy中简明扼要地写向量表达式?
- python - 如何为列表中的每个项目创建 SQLite 记录
- list - (wx)Maxima:如何在列表的每个成员上迭代一个动作?
- java - “'Mapper' 中的 map(From)' 与 'CursorToMessageImpl' 中的 'map(Object)' 冲突;两种方法具有相同的擦除,但都不会覆盖另一个