The main game scene

Now it's time to bring everything we did together into a playable game scene.

Create a new scene and add a Node named Main. (The reason we are using Node instead of Node2D is because this node will be a container for handling game logic. It does not require 2D functionality itself.)

Click the Instance button (represented by a chain link icon) and select your saved 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

We also add a call to randomize() here so that the random number generator generates different random numbers each time the game is run:

func _ready():
    randomize()

Click the Main node and you will see the Mob Scene property in the Inspector under "Script Variables".

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

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

  • [空] の隣にある下矢印をクリックして「読み込み」を選び、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()

In _on_MobTimer_timeout(), we will create a mob instance, pick a random starting location along the Path2D, and set the mob in motion. The PathFollow2D node will automatically rotate as it follows the path, so we will use that to select the mob's direction as well as its position. When we spawn a mob, we'll pick a random value between 150.0 and 250.0 for how fast each mob will move (it would be boring if they were all moving at the same speed).

注意点として、新しいインスタンスは 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)

重要

Why PI? In functions requiring angles, Godot uses radians, not degrees. Pi represents a half turn in radians, about 3.1415 (there is also TAU which is equal to 2 * PI). If you're more comfortable working with degrees, you'll need to use the deg2rad() and rad2deg() functions to convert between the two.

シーンのテスト

Let's test the scene to make sure everything is working. Add this new_game call to _ready():

func _ready():
    randomize()
    new_game()

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

ちなみに

If you had already set another scene as the "Main Scene", you can right click Main.tscn in the FileSystem dock and select "Set As Main Scene".

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

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

What's our game lacking? Some user interface. In the next lesson, we'll add a title screen and display the player's score.