Up to date
This page is up to date for Godot 4.2
.
If you still find outdated information, please open an issue.
シグナルによるインスタンス化¶
シグナルは、ゲームオブジェクトを分離する方法を提供し、ノードの固定配置を強制することを回避できます。シグナルが必要となる兆候の1つは、get_parent()
を使用して自分自身を見つけたときです。ノードの親を直接参照するということは、そのノードをシーンツリー内の別の場所に簡単に移動できないことを意味します。これは、実行時にオブジェクトをインスタンス化し、実行中のシーンツリーの任意の場所に配置する場合に特に問題になる可能性があります。
以下に、そのような状況の例を考えます: 弾丸を発射します。
発射処理の例¶
マウスに向かって回転して弾を撃つことができるプレイヤーキャラクターを考えてみましょう。マウスボタンがクリックされるたびに、プレイヤーの場所に弾丸のインスタンスが作成されます。詳細については、インスタンスの作成 を参照してください。
弾丸には Area2D
を使用します。これは、指定された速度で直線的に移動します:
extends Area2D
var velocity = Vector2.RIGHT
func _physics_process(delta):
position += velocity * delta
using Godot;
public partial class Bullet : Area2D
{
public Vector2 Velocity { get; set; } = Vector2.Right;
public override void _PhysicsProcess(double delta)
{
Position += Velocity * (float)delta;
}
}
ただし、弾丸がプレイヤーの子として追加された場合、プレイヤーが回転したときに、弾丸も「アタッチ」されたままになります:
代わりに、弾丸はプレイヤーの動きから独立している必要があります。発射されたら、弾丸は直線で移動し続ける必要があり、プレイヤーは弾丸に影響を与えることができなくなります。プレイヤーの子としてシーンツリーに追加する代わりに、弾丸をプレイヤーの親またはツリーのさらに上位にある「メイン」ゲームシーンの子として追加する方が理にかなっています。
これを行うには、弾丸をメインシーンに直接追加します:
var bullet_instance = Bullet.instantiate()
get_parent().add_child(bullet_instance)
Node bulletInstance = Bullet.Instantiate();
GetParent().AddChild(bulletInstance);
ただし、これは別の問題につながります。 「プレイヤー」シーンを個別にテストしようとすると、(弾丸の追加先として)アクセスする親ノードがないため、確認時にクラッシュします。これにより、プレイヤーコードを個別にテストすることが非常に難しくなります。また、メインシーンのノード構造を変更する場合、プレイヤーの親が弾丸を受け取る適切なノードではなくなる可能性があります。
これに対する解決策は、プレイヤーから弾丸を「放出」するシグナルを使用することです。プレイヤーはその後、弾丸に何が起こるかを「知る」必要はありません - シグナルに接続されているノードは、弾丸を「受信」し、弾丸を発生させるために適切なアクションを実行できます。
シグナルを使用して弾丸を発射するプレイヤーのコードは次のとおりです:
extends Sprite2D
signal shoot(bullet, direction, location)
var Bullet = preload("res://bullet.tscn")
func _input(event):
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
shoot.emit(Bullet, rotation, position)
func _process(delta):
look_at(get_global_mouse_position())
using Godot;
public partial class Player : Sprite2D
{
[Signal]
public delegate void ShootEventHandler(PackedScene bullet, float direction, Vector2 location);
private PackedScene _bullet = GD.Load<PackedScene>("res://Bullet.tscn");
public override void _Input(InputEvent @event)
{
if (@event is InputEventMouseButton mouseButton)
{
if (mouseButton.ButtonIndex == MouseButton.Left && mouseButton.Pressed)
{
EmitSignal(SignalName.Shoot, _bullet, Rotation, Position);
}
}
}
public override void _Process(double delta)
{
LookAt(GetGlobalMousePosition());
}
}
In the main scene, we then connect the player's signal (it will appear in the "Node" tab of the Inspector)
func _on_player_shoot(Bullet, direction, location):
var spawned_bullet = Bullet.instantiate()
add_child(spawned_bullet)
spawned_bullet.rotation = direction
spawned_bullet.position = location
spawned_bullet.velocity = spawned_bullet.velocity.rotated(direction)
private void OnPlayerShoot(PackedScene bullet, float direction, Vector2 location)
{
var spawnedBullet = bullet.Instantiate<Bullet>();
AddChild(spawnedBullet);
spawnedBullet.Rotation = direction;
spawnedBullet.Position = location;
spawnedBullet.Velocity = spawnedBullet.Velocity.Rotated(direction);
}
これで、弾丸はプレイヤーの回転に関係なく独自の動きを維持します: