如何在工具模式下绘制 Shape2D?

How to draw a Shape2D in toolmode?

我正在使用 Physics2DServer 添加碰撞形状,如下所示:

Physics2DServer.body_add_shape(_body, _shape, Transform2D.IDENTITY, collision_disabled)

基于此

但我看不出是什么形状,
那么有没有办法在工具模式下绘制(并根据body移动它)?

这花了一点时间才弄清楚,但它实际上比我预期的要简单。第一个见解是 Shape2D 已经有一个 draw 方法,所以我们可以这样做:

shape.draw(get_canvas_item(), Color.darkblue)

或使用您喜欢的任何颜色。

这意味着我们可以制定一个通用的解决方案,而不是处理每一种形状。


我们可以利用 _draw。为了使它无效,我们可以在每次更改时调用 update

顺便说一句,Resource 有一个“已更改”信号,所有 build-in 资源(对于自定义资源,您必须手动执行)在它们的状态发生变化时(如果您发现一个不这样做的,请举报)。

所以我们有这个:

tool
extends Node2D

export var shape:Shape2D setget set_shape

func _draw() -> void:
    if not Engine.editor_hint:
        return

    if shape == null:
        return

    shape.draw(get_canvas_item(), Color.darkblue)


func set_shape(new_value:Shape2D) -> void:
    if shape == new_value:
        return

    if shape != null and shape.is_connected("changed", self, "update"):
        shape.disconnect("changed", self, "update")

    shape = new_value
    if shape != null and not shape.is_connected("changed", self, "update"):
        shape.connect("changed", self, "update")

    update()

缺点是我们无法配置它在自定义位置绘制Shape2D(它将在Node2D的局部坐标原点绘制)。 而且,不,我们不能作弊。


但是,我们可以通过 VisualServer 创建一个 canvas 项目来定位它。此设置可能看起来很熟悉:

var canvas_item:RID
var invalid_rid:RID

func _enter_tree() -> void:
    canvas_item = VisualServer.canvas_item_create()
    VisualServer.canvas_item_set_parent(canvas_item, get_canvas_item())


func _exit_tree() -> void:
    VisualServer.canvas_item_clear(canvas_item)
    canvas_item = invalid_rid

func _draw() -> void:
    if not Engine.editor_hint:
        return

    if shape == null:
        return

    shape.draw(canvas_item, Color.darkblue)

要移动它,我们可以设置它的变换,如下所示:

export var offset:Vector2 setget set_offset

func set_offset(new_value:Vector2) -> void:
    if offset == new_value:
        return

    offset = new_value
    VisualServer.canvas_item_set_transform(
        canvas_item,
        Transform2D.IDENTITY.translated(offset)
    )