Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
Godotインターフェース
多くの場合、機能を他のオブジェクトに依存するスクリプトが必要です。このプロセスには2つの部分があります:
機能を持つ可能性のあるオブジェクトへの参照を取得します。
オブジェクトからデータまたはロジックにアクセスします。
このチュートリアルの残りの部分では、これを行うさまざまな方法の概要を説明します。
オブジェクト参照の取得
すべての Object について、それらを参照する最も基本的な方法は、取得した別のインスタンスから既存のオブジェクトへの参照を取得することです。
var obj = node.object # Property access.
var obj = node.get_object() # Method access.
GodotObject obj = node.Object; // Property access.
GodotObject obj = node.GetObject(); // Method access.
同じ原則が RefCounted オブジェクトにも適用されます。ユーザーはこの方法で Node と Resource に頻繁にアクセスしますが、代替手段も利用できます。
プロパティまたはメソッドアクセスの代わりに、ロードアクセスによってリソースを取得できます。
# If you need an "export const var" (which doesn't exist), use a conditional
# setter for a tool script that checks if it's executing in the editor.
# The `@tool` annotation must be placed at the top of the script.
@tool
# Load resource during scene load.
var preres = preload(path)
# Load resource when program reaches statement.
var res = load(path)
# Note that users load scenes and scripts, by convention, with PascalCase
# names (like typenames), often into constants.
const MyScene = preload("my_scene.tscn") # Static load
const MyScript = preload("my_script.gd")
# This type's value varies, i.e. it is a variable, so it uses snake_case.
@export var script_type: Script
# Must configure from the editor, defaults to null.
@export var const_script: Script:
set(value):
if Engine.is_editor_hint():
const_script = value
# Warn users if the value hasn't been set.
func _get_configuration_warnings():
if not const_script:
return ["Must initialize property 'const_script'."]
return []
// Tool script added for the sake of the "const [Export]" example.
[Tool]
public MyType
{
// Property initializations load during Script instancing, i.e. .new().
// No "preload" loads during scene load exists in C#.
// Initialize with a value. Editable at runtime.
public Script MyScript = GD.Load<Script>("res://Path/To/MyScript.cs");
// Initialize with same value. Value cannot be changed.
public readonly Script MyConstScript = GD.Load<Script>("res://Path/To/MyScript.cs");
// Like 'readonly' due to inaccessible setter.
// But, value can be set during constructor, i.e. MyType().
public Script MyNoSetScript { get; } = GD.Load<Script>("res://Path/To/MyScript.cs");
// If need a "const [Export]" (which doesn't exist), use a
// conditional setter for a tool script that checks if it's executing
// in the editor.
private PackedScene _enemyScn;
[Export]
public PackedScene EnemyScn
{
get { return _enemyScn; }
set
{
if (Engine.IsEditorHint())
{
_enemyScn = value;
}
}
};
// Warn users if the value hasn't been set.
public string[] _GetConfigurationWarnings()
{
if (EnemyScn == null)
{
return ["Must initialize property 'EnemyScn'."];
}
return [];
}
}
次の点に注意してください:
言語がそのようなリソースをロードできる方法はたくさんあります。
オブジェクトがデータにアクセスする方法を設計するとき、リソースを参照としても渡すことができることを忘れないでください。
リソースをロードすると、エンジンによって維持されているキャッシュされたリソースインスタンスがフェッチされることに注意してください。新しいオブジェクトを取得するには、既存の参照を duplicate するか、
new()
でゼロからインスタンス化する必要があります。
ノードにも同様に、代替アクセス ポイントがあります: SceneTreeです。
extends Node
# Slow.
func dynamic_lookup_with_dynamic_nodepath():
print(get_node("Child"))
# Faster. GDScript only.
func dynamic_lookup_with_cached_nodepath():
print($Child)
# Fastest. Doesn't break if node moves later.
# Note that `@onready` annotation is GDScript-only.
# Other languages must do...
# var child
# func _ready():
# child = get_node("Child")
@onready var child = $Child
func lookup_and_cache_for_future_access():
print(child)
# Fastest. Doesn't break if node is moved in the Scene tree dock.
# Node must be selected in the inspector as it's an exported property.
@export var child: Node
func lookup_and_cache_for_future_access():
print(child)
# Delegate reference assignment to an external source.
# Con: need to perform a validation check.
# Pro: node makes no requirements of its external structure.
# 'prop' can come from anywhere.
var prop
func call_me_after_prop_is_initialized_by_parent():
# Validate prop in one of three ways.
# Fail with no notification.
if not prop:
return
# Fail with an error message.
if not prop:
printerr("'prop' wasn't initialized")
return
# Fail and terminate.
# NOTE: Scripts run from a release export template don't run `assert`s.
assert(prop, "'prop' wasn't initialized")
# Use an autoload.
# Dangerous for typical nodes, but useful for true singleton nodes
# that manage their own data and don't interfere with other objects.
func reference_a_global_autoloaded_variable():
print(globals)
print(globals.prop)
print(globals.my_getter())
using Godot;
using System;
using System.Diagnostics;
public class MyNode : Node
{
// Slow
public void DynamicLookupWithDynamicNodePath()
{
GD.Print(GetNode("Child"));
}
// Fastest. Lookup node and cache for future access.
// Doesn't break if node moves later.
private Node _child;
public void _Ready()
{
_child = GetNode("Child");
}
public void LookupAndCacheForFutureAccess()
{
GD.Print(_child);
}
// Delegate reference assignment to an external source.
// Con: need to perform a validation check.
// Pro: node makes no requirements of its external structure.
// 'prop' can come from anywhere.
public object Prop { get; set; }
public void CallMeAfterPropIsInitializedByParent()
{
// Validate prop in one of three ways.
// Fail with no notification.
if (prop == null)
{
return;
}
// Fail with an error message.
if (prop == null)
{
GD.PrintErr("'Prop' wasn't initialized");
return;
}
// Fail with an exception.
if (prop == null)
{
throw new InvalidOperationException("'Prop' wasn't initialized.");
}
// Fail and terminate.
// Note: Scripts run from a release export template don't run `Debug.Assert`s.
Debug.Assert(Prop, "'Prop' wasn't initialized");
}
// Use an autoload.
// Dangerous for typical nodes, but useful for true singleton nodes
// that manage their own data and don't interfere with other objects.
public void ReferenceAGlobalAutoloadedVariable()
{
MyNode globals = GetNode<MyNode>("/root/Globals");
GD.Print(globals);
GD.Print(globals.Prop);
GD.Print(globals.MyGetter());
}
};
オブジェクトからのデータまたはロジックへのアクセス
GodotのスクリプトAPIはダック・タイプです。つまり、スクリプトが操作を実行する場合、Godotは 型(type) による操作をサポートしているかどうかを検証しません。代わりに、オブジェクトが個々のメソッドを 実装 していることをチェックします。
たとえば、CanvasItem クラスには visible
プロパティがあります。スクリプトAPIに公開されるすべてのプロパティは、実際には名前にバインドされたセッターとゲッターのペアです。CanvasItem.visible にアクセスしようとすると、Godot は次のチェックを順番に実行します:
オブジェクトにスクリプトがアタッチされている場合、まずスクリプトを介してプロパティを設定しようとします。このプロパティのセッターメソッドをスクリプトでオーバーライドする手段によって、基本オブジェクトで定義されたプロパティをスクリプトから変更することができます。
スクリプトにプロパティがない場合は、CanvasItemクラスとその継承されたすべての型に対して、"visible"プロパティの ClassDBでハッシュマップルックアップが実行されます。見つかった場合は、バインドされたセッターまたはゲッターを呼び出します。ハッシュマップの詳細については、データ設定 ドキュメントを参照してください。
見つからない場合は、ユーザーが"script"プロパティまたは"meta"プロパティにアクセスするかどうかを明示的に確認します。
そうでない場合は、CanvasItemおよびその継承されたタイプで(アクセスのタイプに応じて)
_set
/_get
の実装をチェックします。これらのメソッドは、オブジェクトにプロパティがあることを示すロジックを実行できます。これは_get_property_list
メソッドでも同様です。注意: これは、数字で始まったりスラッシュを含んだりする名前のような、不正なシンボル名に対しても発生します。
その結果、このダック・タイプのシステムは、スクリプト、オブジェクトのクラス、またはオブジェクトが継承する任意のクラスのいずれかでプロパティを見つけることができますが、これは Object を拡張するものについてのみです。
Godotは、これらのアクセスでランタイムチェックを実行するためのさまざまなオプションを提供します:
ダック・タイプのプロパティアクセス。これらはプロパティチェックを行います(上記を参照)。操作がオブジェクトによってサポートされていない場合、実行が停止します。
# All Objects have duck-typed get, set, and call wrapper methods. get_parent().set("visible", false) # Using a symbol accessor, rather than a string in the method call, # will implicitly call the `set` method which, in turn, calls the # setter method bound to the property through the property lookup # sequence. get_parent().visible = false # Note that if one defines a _set and _get that describe a property's # existence, but the property isn't recognized in any _get_property_list # method, then the set() and get() methods will work, but the symbol # access will claim it can't find the property.
// All Objects have duck-typed Get, Set, and Call wrapper methods. GetParent().Set("visible", false); // C# is a static language, so it has no dynamic symbol access, e.g. // `GetParent().Visible = false` won't work.
メソッドチェック。CanvasItem.visible の場合、他のメソッドと同様に
set_visible
とis_visible
のメソッドにアクセスできます。var child = get_child(0) # Dynamic lookup. child.call("set_visible", false) # Symbol-based dynamic lookup. # GDScript aliases this into a 'call' method behind the scenes. child.set_visible(false) # Dynamic lookup, checks for method existence first. if child.has_method("set_visible"): child.set_visible(false) # Cast check, followed by dynamic lookup. # Useful when you make multiple "safe" calls knowing that the class # implements them all. No need for repeated checks. # Tricky if one executes a cast check for a user-defined type as it # forces more dependencies. if child is CanvasItem: child.set_visible(false) child.show_on_top = true # If one does not wish to fail these checks without notifying users, # one can use an assert instead. These will trigger runtime errors # immediately if not true. assert(child.has_method("set_visible")) assert(child.is_in_group("offer")) assert(child is CanvasItem) # Can also use object labels to imply an interface, i.e. assume it # implements certain methods. # There are two types, both of which only exist for Nodes: Names and # Groups. # Assuming... # A "Quest" object exists and 1) that it can "complete" or "fail" and # that it will have text available before and after each state... # 1. Use a name. var quest = $Quest print(quest.text) quest.complete() # or quest.fail() print(quest.text) # implied new text content # 2. Use a group. for a_child in get_children(): if a_child.is_in_group("quest"): print(quest.text) quest.complete() # or quest.fail() print(quest.text) # implied new text content # Note that these interfaces are project-specific conventions the team # defines (which means documentation! But maybe worth it?). # Any script that conforms to the documented "interface" of the name or # group can fill in for it.
Node child = GetChild(0); // Dynamic lookup. child.Call("SetVisible", false); // Dynamic lookup, checks for method existence first. if (child.HasMethod("SetVisible")) { child.Call("SetVisible", false); } // Use a group as if it were an "interface", i.e. assume it implements // certain methods. // Requires good documentation for the project to keep it reliable // (unless you make editor tools to enforce it at editor time). // Note, this is generally not as good as using an actual interface in // C#, but you can't set C# interfaces from the editor since they are // language-level features. if (child.IsInGroup("Offer")) { child.Call("Accept"); child.Call("Reject"); } // Cast check, followed by static lookup. CanvasItem ci = GetParent() as CanvasItem; if (ci != null) { ci.SetVisible(false); // useful when you need to make multiple safe calls to the class ci.ShowOnTop = true; } // If one does not wish to fail these checks without notifying users, // one can use an assert instead. These will trigger runtime errors // immediately if not true. Debug.Assert(child.HasMethod("set_visible")); Debug.Assert(child.IsInGroup("offer")); Debug.Assert(CanvasItem.InstanceHas(child)); // Can also use object labels to imply an interface, i.e. assume it // implements certain methods. // There are two types, both of which only exist for Nodes: Names and // Groups. // Assuming... // A "Quest" object exists and 1) that it can "Complete" or "Fail" and // that it will have Text available before and after each state... // 1. Use a name. Node quest = GetNode("Quest"); GD.Print(quest.Get("Text")); quest.Call("Complete"); // or "Fail". GD.Print(quest.Get("Text")); // Implied new text content. // 2. Use a group. foreach (Node AChild in GetChildren()) { if (AChild.IsInGroup("quest")) { GD.Print(quest.Get("Text")); quest.Call("Complete"); // or "Fail". GD.Print(quest.Get("Text")); // Implied new text content. } } // Note that these interfaces are project-specific conventions the team // defines (which means documentation! But maybe worth it?). // Any script that conforms to the documented "interface" of the // name or group can fill in for it. Also note that in C#, these methods // will be slower than static accesses with traditional interfaces.
Callable へのアクセスを外部委託します。これらは、依存関係から最大限の自由度が必要な場合に役立ちます。この場合、メソッドの設定は外部コンテキストに依存します。
# child.gd
extends Node
var fn = null
func my_method():
if fn:
fn.call()
# parent.gd
extends Node
@onready var child = $Child
func _ready():
child.fn = print_me
child.my_method()
func print_me():
print(name)
// Child.cs
using Godot;
public partial class Child : Node
{
public Callable? Callable { get; set; }
public void MyMethod()
{
Callable?.Call();
}
}
// Parent.cs
using Godot;
public partial class Parent : Node
{
private Child _child;
public void _Ready()
{
_child = GetNode<Child>("Child");
_child.Callable = Callable.From(PrintMe);
_child.MyMethod();
}
public void PrintMe()
{
GD.Print(Name);
}
}
これらの戦略は、Godotの柔軟なデザインに貢献します。それらの間から、ユーザーは特定のニーズを満たすための幅広いツールを手にできます。