在编辑器中运行代码

tool 是什么?

tool 是一个强大的代码行,当添加到脚本的顶部时,它会在编辑器中执行. 您还可以决定脚本的哪些部分在编辑器中执行,哪部分在游戏中执行,以及哪部分在两者中均执行.

您可以使用它来做很多事情,它在层次设计中非常有用,可以直观地呈现难以预测的事物. 以下是一些用例:

  • 如果你有一门发射受物理学(重力)影响的炮弹的大炮,你可以在编辑器中画出炮弹的轨迹,使关卡设计容易得多.

  • 如果您有不同跳跃高度的跳线,您可以绘制游戏角色能跳过的最大跳跃高度,也可以让关卡设计变得更容易.

  • 如果您的游戏角色不使用精灵,却使用代码来绘制,您可以在编辑器中执行该绘图代码以查看您的游戏角色.

危险

tool 脚本在编辑器内运行,让你访问当前编辑的场景树.这是一个强大的功能,但也有一些注意事项,因为编辑器不包括对 tool 脚本潜在滥用的保护.在操作场景树时,尤其是通过 Node.queue_free 时,要 极其 谨慎,因为如果你在编辑器运行涉及到节点的逻辑时释放该节点,可能会导致崩溃.

如何使用它

要把一个脚本变成一个工具,在你的代码顶部添加关键字 tool .

要检查您当前是否在编辑器中,请使用 : Engine.editor_hint.

例如,如果你想只在编辑器中执行一些代码,可以使用:

GDScript

C#

  1. if Engine.editor_hint:
  2. # Code to execute when in editor.
  1. if (Engine.EditorHint)
  2. {
  3. // Code to execute when in editor.
  4. }

另一方面,如果你想只在游戏中执行代码,只需否定相同的语句:

GDScript

C#

  1. if not Engine.editor_hint:
  2. # Code to execute when in game.
  1. if (!Engine.EditorHint)
  2. {
  3. // Code to execute when in game.
  4. }

不具备上述两个条件之一的代码片断将在编辑器和游戏中运行.

以下是 _process() 函数的示例:

GDScript

C#

  1. func _process(delta):
  2. if Engine.editor_hint:
  3. # Code to execute in editor.
  4. if not Engine.editor_hint:
  5. # Code to execute in game.
  6. # Code to execute both in editor and in game.
  1. public override void _Process(float delta)
  2. {
  3. if (Engine.EditorHint)
  4. {
  5. // Code to execute in editor.
  6. }
  7. if (!Engine.EditorHint)
  8. {
  9. // Code to execute in game.
  10. }
  11. // Code to execute both in editor and in game.
  12. }

注解

编辑器中的修改是永久性的.例如,在下面的情况下,当我们删除脚本时,节点将保持其旋转.要注意避免做不需要的修改.

试试看

在场景中添加一个 Sprite 节点,并将纹理设置为Godot图标. 添加并打开脚本,并将其更改为:

GDScript

C#

  1. tool
  2. extends Sprite
  3. func _process(delta):
  4. rotation_degrees += 180 * delta
  1. using Godot;
  2. using System;
  3. [Tool]
  4. public class MySprite : Sprite
  5. {
  6. public override void _Process(float delta)
  7. {
  8. RotationDegrees += 180 * delta;
  9. }
  10. }

保存脚本并返回编辑器. 现在您应该看到您的对象在旋转. 如果您运行游戏,它也会旋转.

../../_images/rotating_in_editor.gif

注解

如果您没有看到变化,请重新加载场景(关闭它并再次打开).

现在让我们选择何时运行代码. 将 _process() 函数修改为:

GDScript

C#

  1. func _process(delta):
  2. if Engine.editor_hint:
  3. rotation_degrees += 180 * delta
  4. else:
  5. rotation_degrees -= 180 * delta
  1. public override void _Process(float delta)
  2. {
  3. if (Engine.EditorHint)
  4. {
  5. RotationDegrees += 180 * delta;
  6. }
  7. else
  8. {
  9. RotationDegrees -= 180 * delta;
  10. }
  11. }

保存脚本. 现在,对象将在编辑器中顺时针旋转,但如果您运行游戏,它将逆时针旋转.

编辑变量

在脚本中添加并导出一个变量速度.在 “setget” 之后的函数set_speed与你的输入一起执行,以改变这个变量.修改 _process() 以包含旋转速度.

GDScript

C#

  1. tool
  2. extends Sprite
  3. export var speed = 1 setget set_speed
  4. # Update speed and reset the rotation.
  5. func set_speed(new_speed):
  6. speed = new_speed
  7. rotation_degrees = 0
  8. func _process(delta):
  9. rotation_degrees += 180 * delta * speed
  1. using Godot;
  2. using System;
  3. [Tool]
  4. public class MySprite : Sprite
  5. {
  6. private float speed = 1;
  7. [Export]
  8. public float Speed {
  9. get => speed;
  10. set => SetSpeed(value);
  11. }
  12. // Update speed and reset the rotation.
  13. private void SetSpeed(float newSpeed)
  14. {
  15. speed = newSpeed;
  16. RotationDegrees = 0;
  17. }
  18. public override void _Process(float delta)
  19. {
  20. RotationDegrees += 180 * delta * speed;
  21. }
  22. }

注解

其他节点的代码不会在编辑器中运行. 您对其他节点的访问权限被限制了. 您可以访问树和节点及其默认属性,但无法访问用户变量. 如果要这样做,其他节点也必须在编辑器中运行. AutoLoad节点时无法在编辑器中访问的.

实例化场景

你可以正常实例化打包的场景,并将它们添加到编辑器中当前打开的场景中.一定要将场景根节点设置为所有以这种方式创建的节点的所有者,否则这些节点在编辑器中就不可见.

如果你使用的是 tool :

GDScript

C#

  1. func _ready():
  2. var node = Spatial.new()
  3. add_child(node) # Parent could be any node in the scene
  4. node.set_owner(get_tree().edited_scene_root)
  1. public override void _Ready()
  2. {
  3. var node = new Spatial();
  4. AddChild(node); // Parent could be any node in the scene
  5. node.Owner = GetTree().EditedSceneRoot;
  6. }

如果你使用 EditorScript :

GDScript

C#

  1. func _run():
  2. var parent = get_scene().find_node("Parent") # Parent could be any node in the scene
  3. var node = Spatial.new()
  4. parent.add_child(node)
  5. node.set_owner(get_scene())
  1. public override void _Run()
  2. {
  3. var parent = GetScene().FindNode("Parent"); // Parent could be any node in the scene
  4. var node = new Spatial();
  5. parent.AddChild(node);
  6. node.Owner = GetScene();
  7. }

警告

不适当地使用 tool 会产生许多错误.建议首先按照你想要的方式写代码,然后才在上面添加 tool 关键字.另外,要确保把在编辑器中运行的代码和在游戏中运行的代码分开.这样,你可以更容易地发现错误.