メインシーン

今まで作成したすべてをまとめ、遊べるゲームにするときが来ました。

新しいシーンを作成し、 Mainという名前の Node を追加します。 (Node2D ではなく、Nodeを使用する理由は、これはゲームロジックを扱うノードであり、これ自体に2D機能が不要であるためです。)

インスタンス ボタン(チェーン リンク アイコンで表示)をクリックし、保存した Player.tscnを選択してください。

../../_images/instance_scene.png

次に Main の子供として以下のノードを追加します(値は秒単位です)。

  • Timer( MobTimer という名前) - モブが出現する頻度を制御する

  • Timer ( ScoreTimer という名前) - 一秒ごとに得点を上げる

  • Timer ( StartTimer という名前) - 開始する前に遅延させる

  • Position2D (StartPosition という名前) - プレイヤーの開始位置を示す

Timer ノードの Wait Time プロパティを次のように設定します:

  • MobTimer: 0.5

  • ScoreTimer: 1

  • StartTimer: 2

さらに、 StartTimerOne Shot プロパティを「On」に設定し、 StartPosition ノードの Position(240, 450) に設定します。

モブの生成

メインノードは新しいモブを生成し、画面の端のランダムな場所に表示するようにします。 Main の子として MobPath という名前のPath2Dノードを追加します。 Path2D を選択すると、エディタの上部にいくつかの新しいボタンが表示されます:

../../_images/path2d_buttons.png

中央のアイコン([点を追加])を選択し、表示されているコーナーをクリックしてポイントを追加してパスを描画します。ポイントをグリッドにスナップするには、[グリッドスナップを使う]が選択されていることを確認します。このオプションは、[ロック]ボタンの左側にあり、「交差する線と磁石」のアイコンで表示されています。

../../_images/grid_snap_button.png

重要

時計回りにパスを描画します。そうしないと、モブは内側ではなく外側を向いて発生します!

../../_images/draw_path2d.gif

画像にポイント 4 を配置した後、「カーブを閉じる」ボタンをクリックすると、カーブが完成します。

パスが定義されたので、 MobPath の子としてPathFollow2Dノードを追加し、 MobSpawnLocation という名前を付けます。このノードは自動的に回転し、パスの移動に従うので、パスに沿ってランダムな位置と方向を選択できます。

シーンは次のようになります:

../../_images/main_scene_nodes.png

Mainスクリプト

スクリプトを Main に追加します。 スクリプトの上部で、export(PackedScene) を使用して、インスタンス化するMobシーンを選択できるようにします。

extends Node

export(PackedScene) var mob_scene
var score

また、ここでrandomize()の呼び出しを追加し、ゲームを実行する度に乱数発生器が異なる乱数を生成するようにします。

func _ready():
    randomize()

Mainノードをクリックすると、インスペクタの「Script Variables(スクリプト変数)」の下にMob Sceneプロパティがあります。

このプロパティの値は、ふたつの方法で指定できます:

  • 「ファイルシステム」パネルから Mob.tscn をドラッグし、 Mob Scene プロパティにドロップします。

  • [空] の隣にある下矢印をクリックして「読み込み」を選び、Mob.tscn を選択します。

次に、シーンドックの Player ノードを選択し、サイドバーのノードドックにアクセスします。ノードドックでは、シグナルタブが選択されていることを確認してください。

Player ノードのシグナルのリストが表示されているはずです。リストの中から hit のシグナルを見つけてダブルクリックしてください (または右クリックして "接続..." を選択)。これでシグナルの接続ダイアログが開きます。ゲームが終了したときに必要な処理を行う game_over という名前の新しい関数をこれから作ります。シグナル接続ダイアログの下部にある「受信側メソッド」ボックスに「game_over」と入力し、「接続」をクリックしてください。新しい関数に以下のコードを追加し、さらに、新しいゲームのための設定を行う new_game 関数も追加します:

func game_over():
    $ScoreTimer.stop()
    $MobTimer.stop()

func new_game():
    score = 0
    $Player.start($StartPosition.position)
    $StartTimer.start()

次に、各Timerノード (StartTimerScoreTimer、および MobTimer) の timeout() シグナルをメインスクリプトに接続します。StartTimer は他の2つのタイマーを開始します。ScoreTimer はスコアを1増やします。

func _on_ScoreTimer_timeout():
    score += 1

func _on_StartTimer_timeout():
    $MobTimer.start()
    $ScoreTimer.start()

_on_MobTimer_timeout()では、モブ インスタンスを作成し、Path2Dに沿ってランダムに開始場所を選び、モブを動作させることにしました。PathFollow2Dノードはパスに沿って自動的に回転するので、これを使用して mob の方向とその位置を選択します。モブ を生成するときは、150.0250.0の間でランダムに値を選び、それぞれの モブ がどれくらい速く動くかを決定します(モブがすべて同じ速度で動くと退屈になってしまうでしょう)。

注意点として、新しいインスタンスは add_child() を使ってシーンに追加しなければなりません。

func _on_MobTimer_timeout():
    # Create a new instance of the Mob scene.
    var mob = mob_scene.instance()

    # Choose a random location on Path2D.
    var mob_spawn_location = get_node("MobPath/MobSpawnLocation")
    mob_spawn_location.offset = randi()

    # 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 += rand_range(-PI / 4, PI / 4)
    mob.rotation = direction

    # Choose the velocity for the mob.
    var velocity = Vector2(rand_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)

重要

なぜ PIなのでしょうか?角度を必要とする関数では、Godot は度ではなく、ラジアンを使用します。円周率は、半回転をラジアンで表します。3.1415(TAUもあり、2 * PIと同じです) です。もし、度を扱う方が好きなら、deg2rad()rad2deg()という関数を使って両者を変換しなければならないでしょう。

シーンのテスト

シーンをテストして、すべてが動作していることを確認してみましょう。これを _ready()に追加してください:

func _ready():
    randomize()
    new_game()

また、 Main を「メインシーン」として設定してみましょう - ゲームが起動したときに自動的に実行されるシーンです。「実行」ボタンを押して、プロンプトが表示されたら Main.tscn を選択してください。

ちなみに

すでに他のシーンをメインシーンに設定していた場合は、ファイルシステム("FileSystem") ドックの Main.tscnを右クリックして「メインシーンとして設定」("Set As Main Scene") を選択してください。

プレイヤーを移動でき、モブが発生したり、モブに当たった時にプレイヤーが消えるようになっているはずです。

全て動作していることが確認できたら、 _ready() から new_game() の呼び出しを削除してください。

私たちのゲームには何が足りないのでしょう?それは、ユーザーインターフェイスです。次のレッスンでは、タイトル画面を追加して、プレイヤーのスコアを表示することにします。