Up to date
This page is up to date for Godot 4.2
.
If you still find outdated information, please open an issue.
シグナルの使用¶
このレッスンでは、シグナルを見ていきます。これらは、ボタンが押された、など特定のことが起こったときにノードが発信するメッセージです。他のノードはシグナルに接続し、イベントが発生したときに関数を呼び出すことができます。
シグナルはGodotに組み込まれた委任メカニズムで、あるゲームオブジェクトが別のゲームオブジェクトの変更に反応する際に、それらを相互参照させることなく反応できるようにするものです。シグナルを使うと、 結合度 を制限し、コードの柔軟性を保つことができます。
For example, you might have a life bar on the screen that represents the player's health. When the player takes damage or uses a healing potion, you want the bar to reflect the change. To do so, in Godot, you would use signals.
注釈
概要で述べたように、シグナルはGodotバージョンのobserverパターンです。詳しくは 次を参照ください: https://gameprogrammingpatterns.com/observer.html
今度はシグナルを使って、前パート ( プレイヤーの入力を聞く ) で作ったGodotのアイコンがボタンを押すことで動いたり止まったりするようにします。
シーンの設定¶
To add a button to our game, we will create a new main scene which will include
both a Button and the sprite_2d.tscn
scene we created in
the 初めてのスクリプト作成 lesson.
メニューの「シーン -> 新規シーン」で、新しいシーンを作成します。
In the Scene dock, click the 2D Scene button. This will add a Node2D as our root.
In the FileSystem dock, click and drag the sprite_2d.tscn
file you saved
previously onto the Node2D to instantiate it.
We want to add another node as a sibling of the Sprite2D. To do so, right-click on Node2D and select Add Child Node.
Search for the Button node and add it.
デフォルトではノードは小さく作成されます。ハンドルの右下をクリック&ドラッグし、サイズを変更します。
ハンドルが表示されない場合は、ツールバー上で選択ツールが選択されていることを確認してください。
ボタンをクリック&ドラッグし、Spriteの近くへ動かします。
You can also write a label on the Button by editing its Text property in the
Inspector. Enter Toggle motion
.
シーンツリーとビューポートは次のようになります。
Save your newly created scene as node_2d.tscn
, if you haven't already.
You can then run it with F6 (Cmd + R on macOS).
At the moment, the button will be visible, but nothing will happen if you
press it.
エディタ内でシグナルを接続する¶
Here, we want to connect the Button's "pressed" signal to our Sprite2D, and we want to call a new function that will toggle its motion on and off. We need to have a script attached to the Sprite2D node, which we do from the previous lesson.
ノードドック内でシグナルを接続することができます。Buttonノードを選択し、インスペクターの横にあるノードをクリックします。
選択したノードで利用可能なシグナルが表示されます。
"pressed"シグナルをダブルクリックし、ノード接続ウィンドウを開きます。
There, you can connect the signal to the Sprite2D node. The node needs a receiver method, a function that Godot will call when the Button emits the signal. The editor generates one for you. By convention, we name these callback methods "_on_node_name_signal_name". Here, it'll be "_on_button_pressed".
注釈
ノードドックよりシグナルを接続する場合、簡易モードと高度な設定を利用できます。簡易モードではスクリプトが付随しているノードにのみ接続でき、そのノードに新しいコールバック関数を作成します。
高度な設定("Advanced")では、任意のノードと任意のビルトイン関数に接続し、コールバックに引数を追加し、オプションを設定することができます。ウィンドウの右下にある"Advanced"ボタンをクリックすることで、モードを切り替えることができます。
接続ボタン("Connect")をクリックすると、シグナルの接続が完了し、スクリプトのワークスペースにジャンプします。左側のマージンに接続アイコンのある新しいメソッドが表示されるはずです。
このアイコンをクリックすると、ウィンドウがポップアップし、接続に関する情報が表示されます。この機能は、エディターでノードを接続する場合のみ有効です。
pass
キーワードの行を、ノードの動きを切り替えるコードに置き換えましょう。
Our Sprite2D moves thanks to code in the _process()
function. Godot provides
a method to toggle processing on and off: Node.set_process(). Another method of the Node class,
is_processing()
, returns true
if idle processing is active. We can use
the not
keyword to invert the value.
func _on_button_pressed():
set_process(not is_processing())
private void OnButtonPressed()
{
SetProcess(!IsProcessing());
}
この関数はボタンを押したときに、処理を切り替え、アイコンの動作のON/OFFを切り替えます。
ゲームを試す前に、 _process()
関数を単純化して、ユーザー入力を待たずにノードを自動的に移動させる必要があります。次のコードに置き換えます (これは 2 つ前のレッスンで見ています)。
func _process(delta):
rotation += angular_speed * delta
var velocity = Vector2.UP.rotated(rotation) * speed
position += velocity * delta
public override void _Process(double delta)
{
Rotation += _angularSpeed * (float)delta;
var velocity = Vector2.Up.Rotated(Rotation) * _speed;
Position += velocity * (float)delta;
}
Your complete sprite_2d.gd
code should look like the following.
extends Sprite2D
var speed = 400
var angular_speed = PI
func _process(delta):
rotation += angular_speed * delta
var velocity = Vector2.UP.rotated(rotation) * speed
position += velocity * delta
func _on_button_pressed():
set_process(not is_processing())
using Godot;
public partial class MySprite2D : Sprite2D
{
private float _speed = 400;
private float _angularSpeed = Mathf.Pi;
public override void _Process(double delta)
{
Rotation += _angularSpeed * (float)delta;
var velocity = Vector2.Up.Rotated(Rotation) * _speed;
Position += velocity * (float)delta;
}
private void OnButtonPressed()
{
SetProcess(!IsProcessing());
}
}
すぐにシーンを実行し、ボタンをクリックして、スプライトの開始と停止を確認します。
コード経由でシグナルを接続する¶
エディタを使用する代わりに、コードを介してシグナルを接続することができます。これは、スクリプトの中でノードを作成したり、シーンをインスタンス化するときに必要です。
ここで、別のノードを使ってみましよう。Godot には Timer ノードがあり、スキルのクールダウン時間や武器のリロードなどを実装するのに便利です。
Head back to the 2D workspace. You can either click the "2D" text at the top of the window or press Ctrl + F1 (Ctrl + Cmd + 1 on macOS).
In the Scene dock, right-click on the Sprite2D node and add a new child node. Search for Timer and add the corresponding node. Your scene should now look like this.
With the Timer node selected, go to the Inspector and enable the Autostart property.
Click the script icon next to Sprite2D to jump back to the scripting workspace.
ノードをコードで接続するには、2つの操作が必要です。
Get a reference to the Timer from the Sprite2D.
Call the
connect()
method on the Timer's "timeout" signal.
注釈
To connect to a signal via code, you need to call the connect()
method of the signal you want to listen to. In this case, we want to
listen to the Timer's "timeout" signal.
We want to connect the signal when the scene is instantiated, and we can do that using the Node._ready() built-in function, which is called automatically by the engine when a node is fully instantiated.
現在のノードに関連するノードの参照を取得するには、 Node.get_node() というメソッドを使用します。この参照は変数に格納することができます。
func _ready():
var timer = get_node("Timer")
public override void _Ready()
{
var timer = GetNode<Timer>("Timer");
}
The function get_node()
looks at the Sprite2D's children and gets nodes by
their name. For example, if you renamed the Timer node to "BlinkingTimer" in the
editor, you would have to change the call to get_node("BlinkingTimer")
.
We can now connect the Timer to the Sprite2D in the _ready()
function.
func _ready():
var timer = get_node("Timer")
timer.timeout.connect(_on_timer_timeout)
public override void _Ready()
{
var timer = GetNode<Timer>("Timer");
timer.Timeout += OnTimerTimeout;
}
The line reads like so: we connect the Timer's "timeout" signal to the node to
which the script is attached. When the Timer emits timeout
, we want to call
the function _on_timer_timeout()
, that we need to define. Let's add it at the
bottom of our script and use it to toggle our sprite's visibility.
注釈
By convention, we name these callback methods in GDScript as "_on_node_name_signal_name" and in C# as "OnNodeNameSignalName". Here, it'll be "_on_timer_timeout" for GDScript and OnTimerTimeout() for C#.
func _on_timer_timeout():
visible = not visible
private void OnTimerTimeout()
{
Visible = !Visible;
}
visible
のプロパティはブール値で、ノードの可視性を制御します。visible = not visible
の行で値を反転します。visible
が true
なら、false
に、また逆の場合も同様です。
このシーンを今実行すると、スプライトが1秒間隔で点滅するのがわかるでしょう。
完全なスクリプト¶
That's it for our little moving and blinking Godot icon demo!
Here is the complete sprite_2d.gd
file for reference.
extends Sprite2D
var speed = 400
var angular_speed = PI
func _ready():
var timer = get_node("Timer")
timer.timeout.connect(_on_timer_timeout)
func _process(delta):
rotation += angular_speed * delta
var velocity = Vector2.UP.rotated(rotation) * speed
position += velocity * delta
func _on_button_pressed():
set_process(not is_processing())
func _on_timer_timeout():
visible = not visible
using Godot;
public partial class MySprite2D : Sprite2D
{
private float _speed = 400;
private float _angularSpeed = Mathf.Pi;
public override void _Ready()
{
var timer = GetNode<Timer>("Timer");
timer.Timeout += OnTimerTimeout;
}
public override void _Process(double delta)
{
Rotation += _angularSpeed * (float)delta;
var velocity = Vector2.Up.Rotated(Rotation) * _speed;
Position += velocity * (float)delta;
}
private void OnButtonPressed()
{
SetProcess(!IsProcessing());
}
private void OnTimerTimeout()
{
Visible = !Visible;
}
}
カスタムシグナル¶
注釈
このセクションは、独自のシグナルを定義して使用する方法についての参考であり、前のレッスンで作成したプロジェクトを使用するものではありません。
スクリプトでカスタムシグナルを定義することができます。例えば、プレイヤーの体力が0になったときにゲームオーバー画面を表示させたいとします。そのためには、体力が0になったときに、"died" (死亡)や "health_depleted"(体力の枯渇) という名前のシグナルを定義することができます。
extends Node2D
signal health_depleted
var health = 10
using Godot;
public partial class MyNode2D : Node2D
{
[Signal]
public delegate void HealthDepletedEventHandler();
private int _health = 10;
}
注釈
シグナルは発生したばかりのイベントを表現するため、通常、動作を表す過去形の動詞をシグナルの名前に使用します。
作成したシグナルは、組み込まれたシグナルと同じように動作します。シグナルはノード("Node")タブに表示され、他のシグナルと同様に接続することができます。
To emit a signal in your scripts, call emit()
on the signal.
func take_damage(amount):
health -= amount
if health <= 0:
health_depleted.emit()
public void TakeDamage(int amount)
{
_health -= amount;
if (_health <= 0)
{
EmitSignal(SignalName.HealthDepleted);
}
}
シグナルは、オプションで1つ以上の引数を宣言できます。カッコの中に引数の名前を指定します:
extends Node
signal health_changed(old_value, new_value)
var health = 10
using Godot;
public partial class MyNode : Node
{
[Signal]
public delegate void HealthChangedEventHandler(int oldValue, int newValue);
private int _health = 10;
}
注釈
シグナル引数はエディタのノードドックに表示され、Godotはそれらを使用してコールバック関数を生成できます。しかしながら、シグナルを発信するときに、任意の数の引数を発行できます。正しい値を出力するのはあなた次第です。
To emit values along with the signal, add them as extra arguments to the
emit()
function:
func take_damage(amount):
var old_health = health
health -= amount
health_changed.emit(old_health, health)
public void TakeDamage(int amount)
{
int oldHealth = _health;
_health -= amount;
EmitSignal(SignalName.HealthChanged, oldHealth, _health);
}
概要¶
Godot ではどのノードも、ボタンが押されるなど、何か特定のことが起こるとシグナルを発し ます。他のノードは個々のシグナルに接続し、選択されたイベントに反応することができます。
シグナルには多くの用途があります。これらを使用すると、ゲームワールドに出入りするノード、衝突、領域に出入りするキャラクター、サイズが変化するインターフェイスの要素など、多くのことに反応できます。
たとえば、コインの見た目をした Area2D は、プレイヤーの物理ボディが衝突形状(コリジョンシェイプ)に入るたびに body_entered
シグナルを発し、プレイヤーがそれを収集したタイミングを知ることができます。
次のセクション、 最初の2Dゲーム では、完全な2Dゲームを作成し、これまでに学んだことを実践します。