首页 > 解决方案 > 在 KinematicBody2D 上调用 get_position 会导致 get_global_transform 错误

问题描述

概括

我正在尝试使用Gut为我player的 in get_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(),但找不到答案。

我也尝试过制作playeran 的孩子,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)

标签: unit-testinggodotgdscript

解决方案


错误告诉你!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.


推荐阅读