在编辑器中运行代码
tool
是什么?
tool
是一个强大的代码行, 当添加到脚本的顶部时, 它会在编辑器中执行. 您还可以决定脚本的哪些部分在编辑器中执行, 哪部分在游戏中执行, 以及哪部分在两者中均执行.
您可以使用它来做很多事情, 它在层次设计中非常有用, 可以直观地呈现难以预测的事物. 以下是一些用例:
如果你有一门发射受物理学(重力)影响的炮弹的大炮, 你可以在编辑器中画出炮弹的轨迹, 使关卡设计容易得多.
如果您有不同跳跃高度的跳线, 您可以绘制游戏角色能跳过的最大跳跃高度, 也可以让关卡设计变得更容易.
如果您的游戏角色不使用精灵, 却使用代码来绘制, 您可以在编辑器中执行该绘图代码以查看您的游戏角色.
危险
tool
脚本在编辑器内运行, 让你访问当前编辑的场景树. 这是一个强大的功能, 但也有一些注意事项, 因为编辑器不包括对 tool
脚本潜在滥用的保护. 在操作场景树时, 尤其是通过 Node.queue_free 时, 要 极其 谨慎, 因为如果你在编辑器运行涉及到节点的逻辑时释放该节点, 可能会导致崩溃.
如何使用它
要把一个脚本变成一个工具, 在你的代码顶部添加关键字 tool
.
要检查您当前是否在编辑器中, 请使用 : Engine.editor_hint
.
例如, 如果你想只在编辑器中执行一些代码, 可以使用:
GDScript
C#
if Engine.editor_hint:
# Code to execute when in editor.
if (Engine.EditorHint)
{
// Code to execute when in editor.
}
另一方面, 如果你想只在游戏中执行代码, 只需否定相同的语句:
GDScript
C#
if not Engine.editor_hint:
# Code to execute when in game.
if (!Engine.EditorHint)
{
// Code to execute when in game.
}
不具备上述两个条件之一的代码片断将在编辑器和游戏中运行.
以下是 _process()
函数的示例:
GDScript
C#
func _process(delta):
if Engine.editor_hint:
# Code to execute in editor.
if not Engine.editor_hint:
# Code to execute in game.
# Code to execute both in editor and in game.
public override void _Process(float delta)
{
if (Engine.EditorHint)
{
// Code to execute in editor.
}
if (!Engine.EditorHint)
{
// Code to execute in game.
}
// Code to execute both in editor and in game.
}
注解
编辑器中的修改是永久性的. 例如, 在下面的情况下, 当我们删除脚本时, 节点将保持其旋转. 要注意避免做不需要的修改.
试试看
在场景中添加一个 Sprite
节点, 并将纹理设置为Godot图标. 添加并打开脚本, 并将其更改为:
GDScript
C#
tool
extends Sprite
func _process(delta):
rotation_degrees += 180 * delta
using Godot;
using System;
[Tool]
public class MySprite : Sprite
{
public override void _Process(float delta)
{
RotationDegrees += 180 * delta;
}
}
保存脚本并返回编辑器. 现在您应该看到您的对象在旋转. 如果您运行游戏, 它也会旋转.
注解
如果您没有看到变化, 请重新加载场景(关闭它并再次打开).
现在让我们选择何时运行代码. 将 _process()
函数修改为:
GDScript
C#
func _process(delta):
if Engine.editor_hint:
rotation_degrees += 180 * delta
else:
rotation_degrees -= 180 * delta
public override void _Process(float delta)
{
if (Engine.EditorHint)
{
RotationDegrees += 180 * delta;
}
else
{
RotationDegrees -= 180 * delta;
}
}
保存脚本. 现在, 对象将在编辑器中顺时针旋转, 但如果您运行游戏, 它将逆时针旋转.
编辑变量
在脚本中添加并导出一个变量速度. 在 “setget” 之后的函数set_speed与你的输入一起执行, 以改变这个变量. 修改 _process()
以包含旋转速度.
GDScript
C#
tool
extends Sprite
export var speed = 1 setget set_speed
# Update speed and reset the rotation.
func set_speed(new_speed):
speed = new_speed
rotation_degrees = 0
func _process(delta):
rotation_degrees += 180 * delta * speed
using Godot;
using System;
[Tool]
public class MySprite : Sprite
{
private float speed = 1;
[Export]
public float Speed {
get => speed;
set => SetSpeed(value);
}
// Update speed and reset the rotation.
private void SetSpeed(float newSpeed)
{
speed = newSpeed;
RotationDegrees = 0;
}
public override void _Process(float delta)
{
RotationDegrees += 180 * delta * speed;
}
}
注解
其他节点的代码不会在编辑器中运行. 您对其他节点的访问权限被限制了. 您可以访问树和节点及其默认属性, 但无法访问用户变量. 如果要这样做, 其他节点也必须在编辑器中运行. AutoLoad节点时无法在编辑器中访问的.
实例化场景
你可以正常实例化打包的场景, 并将它们添加到编辑器中当前打开的场景中. 一定要将场景根节点设置为所有以这种方式创建的节点的所有者, 否则这些节点在编辑器中就不可见.
如果你使用的是 tool
:
GDScript
C#
func _ready():
var node = Spatial.new()
add_child(node) # Parent could be any node in the scene
node.set_owner(get_tree().edited_scene_root)
public override void _Ready()
{
var node = new Spatial();
AddChild(node); // Parent could be any node in the scene
node.Owner = GetTree().EditedSceneRoot;
}
如果你使用 EditorScript :
GDScript
C#
func _run():
var parent = get_scene().find_node("Parent") # Parent could be any node in the scene
var node = Spatial.new()
parent.add_child(node)
node.set_owner(get_scene())
public override void _Run()
{
var parent = GetScene().FindNode("Parent"); // Parent could be any node in the scene
var node = new Spatial();
parent.AddChild(node);
node.Owner = GetScene();
}
警告
不适当地使用 tool
会产生许多错误. 建议首先按照你想要的方式写代码, 然后才在上面添加 tool
关键字. 另外, 要确保把在编辑器中运行的代码和在游戏中运行的代码分开. 这样, 你可以更容易地发现错误.