Up to date
This page is up to date for Godot 4.3.
If you still find outdated information, please open an issue.
メインシーン
今まで作成したすべてをまとめ、遊べるゲームにするときが来ました。
新しいシーンを作成し、 Node クラスを追加して Main という名前にします。 (Node2D ではなく、Nodeを使用する理由は、これはゲームロジックを扱うノードであり、これ自体に2D機能が不要であるためです)
インスタンス ボタン(チェーンリンクアイコン)をクリックし、保存した player.tscn を選択してください。
次に Main の子ノードとして以下のノードを追加し、名前を変更します:
Timer(
MobTimerという名前) - モブが出現する頻度を制御するTimer (
ScoreTimerという名前) - 一秒ごとに得点を上げるTimer (
StartTimerという名前) - 開始する前に遅延させるMarker2D (
StartPositionという名前) - プレイヤーの開始位置を示す
各 Timer ノードの Wait Time プロパティを次のように設定します (値は秒単位です):
MobTimer:0.5ScoreTimer:1StartTimer:2
さらに、 StartTimer の One Shot プロパティを「On」に設定し、 StartPosition ノードの Position を (240, 450) に設定します。
モブの生成
メインノードは新しいモブを生成し、画面の端のランダムな場所に表示するようにします。 Main の子として MobPath という名前のPath2Dノードを追加します。 Path2D を選択すると、エディタの上部にいくつかの新しいボタンが表示されます:
中央のアイコン([点を空きスペースに追加])を選択し、表示されているコーナーをクリックしてポイントを追加してパスを描画します。ポイントをグリッドにスナップするには、[グリッドスナップを使う]が選択されていることを確認します。このオプションは、[選択Nodeをロック]ボタンの左側にあり、「交差する線と磁石」のアイコンで表示されています。
重要
時計回りにパスを描画します。そうしないと、モブは内側ではなく外側を向いて発生します!
画像にポイント 4 を配置した後、[曲線を閉じる] ボタンをクリックすると、パスが完成します。
パスが定義されたので、 MobPath の子としてPathFollow2Dノードを追加し、 MobSpawnLocation という名前を付けます。このノードは自動的に回転し、パスの移動に従うので、パスに沿ってランダムな位置と方向を選択できます。
シーンは次のようになります:
Mainスクリプト
Main にスクリプトをアタッチします。 スクリプトの上部に @export var mob_scene: PackedScene を追加して、インスタンス化するMobシーンを選択できるようにします。
extends Node
@export var mob_scene: PackedScene
var score
using Godot;
public partial class Main : Node
{
// Don't forget to rebuild the project so the editor knows about the new export variable.
[Export]
public PackedScene MobScene { get; set; }
private int _score;
}
Main ノードをクリックすると、インスペクタの "Main.gd" の下に Mob Scene プロパティが見えるようになっています。
このプロパティの値は、ふたつの方法で指定できます:
「ファイルシステム」パネルから
mob.tscnをドラッグし、 Mob Scene プロパティにドロップします。<空> の隣にある下矢印をクリックして「読み込み」を選び、
mob.tscnを選択します。
次に、シーンドックの Player ノードを選択し、サイドバーのノードドックにアクセスします。ノードドックでは、シグナルタブが選択されていることを確認してください。
Player ノードのシグナルのリストが表示されます。リストの中から hit のシグナルを見つけてダブルクリックしてください (または、右クリックして "接続..." を選択)。これでシグナルの接続ダイアログが開きます。ゲームが終了したときに必要な処理を行う game_over という名前の新しい関数をこれから作ります。シグナル接続ダイアログの下部にある「受信側メソッド」ボックスに「game_over」と入力し、「接続」をクリックしてください。 Player から hit シグナルが発火されたとき、 Main スクリプト側で処理できるようになります。新しい関数に以下のコードを追加し、新しいゲームのセットアップを行う new_game 関数も追加します:
func game_over():
$ScoreTimer.stop()
$MobTimer.stop()
func new_game():
score = 0
$Player.start($StartPosition.position)
$StartTimer.start()
public void GameOver()
{
GetNode<Timer>("MobTimer").Stop();
GetNode<Timer>("ScoreTimer").Stop();
}
public void NewGame()
{
_score = 0;
var player = GetNode<Player>("Player");
var startPosition = GetNode<Marker2D>("StartPosition");
player.Start(startPosition.Position);
GetNode<Timer>("StartTimer").Start();
}
次に、各Timerノード (StartTimer 、 ScoreTimer 、 MobTimer) の timeout() シグナルをMainスクリプトに接続します。 StartTimer は他の2つのタイマーを開始します。 ScoreTimer はスコアを1増やします。
func _on_score_timer_timeout():
score += 1
func _on_start_timer_timeout():
$MobTimer.start()
$ScoreTimer.start()
// We also specified this function name in PascalCase in the editor's connection window.
private void OnScoreTimerTimeout()
{
_score++;
}
// We also specified this function name in PascalCase in the editor's connection window.
private void OnStartTimerTimeout()
{
GetNode<Timer>("MobTimer").Start();
GetNode<Timer>("ScoreTimer").Start();
}
_on_mob_timer_timeout() では、モブのインスタンスを作成し、 Path2D に沿ってランダムに開始位置を選び、モブを動かすようにします。PathFollow2D ノードはパスに沿って自動的に回転するので、これを使ってモブの方向と位置を選択します。移動速度は 150.0 から 250.0 の間でランダムに値を選びます(すべて同じ速度で動くとつまらなくなってしまいます)。
注意点として、新しいインスタンスは add_child() を使ってシーンに追加しなければなりません。
func _on_mob_timer_timeout():
# Create a new instance of the Mob scene.
var mob = mob_scene.instantiate()
# Choose a random location on Path2D.
var mob_spawn_location = $MobPath/MobSpawnLocation
mob_spawn_location.progress_ratio = randf()
# Set the mob's direction perpendicular to the path direction.
var direction = mob_spawn_location.rotation + PI / 2
# Set the mob's position to a random location.
mob.position = mob_spawn_location.position
# Add some randomness to the direction.
direction += randf_range(-PI / 4, PI / 4)
mob.rotation = direction
# Choose the velocity for the mob.
var velocity = Vector2(randf_range(150.0, 250.0), 0.0)
mob.linear_velocity = velocity.rotated(direction)
# Spawn the mob by adding it to the Main scene.
add_child(mob)
// We also specified this function name in PascalCase in the editor's connection window.
private void OnMobTimerTimeout()
{
// Create a new instance of the Mob scene.
Mob mob = MobScene.Instantiate<Mob>();
// Choose a random location on Path2D.
var mobSpawnLocation = GetNode<PathFollow2D>("MobPath/MobSpawnLocation");
mobSpawnLocation.ProgressRatio = GD.Randf();
// Set the mob's direction perpendicular to the path direction.
float direction = mobSpawnLocation.Rotation + Mathf.Pi / 2;
// Set the mob's position to a random location.
mob.Position = mobSpawnLocation.Position;
// Add some randomness to the direction.
direction += (float)GD.RandRange(-Mathf.Pi / 4, Mathf.Pi / 4);
mob.Rotation = direction;
// Choose the velocity.
var velocity = new Vector2((float)GD.RandRange(150.0, 250.0), 0);
mob.LinearVelocity = velocity.Rotated(direction);
// Spawn the mob by adding it to the Main scene.
AddChild(mob);
}
重要
なぜ PI なのでしょうか?角度を必要とする関数では、Godot は度数ではなく、 ラジアン を使用します。円周率はラジアンの半回転を表し、約 3.1415 です ( 2 * PI に等しい TAU もあります) 。もし、度数を扱う方が好きであれば deg_to_rad() と rad_to_deg() という関数を使って両者を変換する必要があります。
シーンのテスト
シーンをテストして、すべてが動作していることを確認してみましょう。new_game 関数の呼び出しを _ready()に追加してください:
func _ready():
new_game()
public override void _Ready()
{
NewGame();
}
また、 Main を「メインシーン」として設定してみましょう。 (ゲームが起動したときに自動的に実行されるシーンです。) 「プロジェクトを実行」ボタンを押して、プロンプトが表示されたら main.tscn を選択してください。
Tip
すでに他のシーンをメインシーンに設定していた場合は、ファイルシステムドックの main.tscn を右クリックして「メインシーンとして設定」を選択してください。
プレイヤーを移動でき、モブが発生したり、モブに当たった時にプレイヤーが消えるようになっているはずです。
全て動作していることが確認できたら、 _ready() から new_game() の呼び出しを削除して、 pass に置き換えてください。
私たちのゲームには何が足りないのでしょう?それは、ユーザーインターフェイスです。次のレッスンでは、タイトル画面を追加して、プレイヤーのスコアを表示することにします。