Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

プレイヤーのコーディング

このパートでは、playerの動きやアニメーション、衝突判定を設定します。

そのために、組み込みノードからは得られない機能を追加する必要があるので、スクリプトを追加します。 Player ノードをクリックし、「スクリプトをアタッチ」ボタンをクリックします:

../../_images/add_script_button.webp

スクリプト設定ウィンドウ内の設定はそのままで構いません。「作成」をクリックしてください:

注釈

C#スクリプトまたはその他の言語を作成する場合は、作成を実行する前に [言語] ドロップダウン メニューから言語を選択します。

../../_images/attach_node_window.webp

注釈

はじめてGDScriptを扱う場合は、 スクリプト言語 を読んでから先に進んでください。

まず、このオブジェクトに必要なメンバー変数を宣言します:

extends Area2D

@export var speed = 400 # How fast the player will move (pixels/sec).
var screen_size # Size of the game window.

最初の変数 speedexport キーワードを使用すると、インスペクタでその値を設定できるようになります。これは、値をノードの組み込みプロパティのように調整できるようにする場合に便利です。 Player ノードをクリックすると、インスペクタの "Script Variables" セクションにプロパティが表示されます。ここで値を変更すると、スクリプトに記述された値よりも優先されることに注意してください。

警告

If you're using C#, you need to (re)build the project assemblies whenever you want to see new export variables or signals. This build can be manually triggered by clicking the Build button at the top right of the editor.

../../_images/build_dotnet.webp
../../_images/export_variable.webp

Your player.gd script should already contain a _ready() and a _process() function. If you didn't select the default template shown above, create these functions while following the lesson.

_ready() 関数は、ノードがシーンツリーに入ると呼び出されます。これは、ゲームウィンドウのサイズを調べる良いタイミングです:

func _ready():
    screen_size = get_viewport_rect().size

これで _process() 関数を使用して、プレイヤーが何をするかを定義できます。 _process() はフレームごとに呼び出されるため、これを使用してゲームの要素を更新しますが、これは頻繁に変更されることが予想されます。プレイヤーの場合、次のことを行う必要があります:

  • 入力をチェックします。

  • 指定した方向に移動します。

  • 適切なアニメーションを再生します。

まず、入力をチェックする必要があります - プレイヤーはキーを押しているでしょうか?このゲームでは、4方向の入力チェックをする必要があります。入力アクションは、プロジェクト設定の「インプットマップ」で定義されます。ここで、カスタムイベントを定義し、異なるキー、マウスイベント、またはその他の入力を割り当てることができます。このデモでは、キーボードの矢印キーを4方向に割り当てます。

「プロジェクト」→「プロジェクト設定」の順にクリックしてプロジェクト設定を開き、上部の「インプットマップ」タブをクリックします。一番上のバーに"move_right"と入力し、「追加」をクリックして move_right アクションを追加します。

../../_images/input-mapping-add-action.webp

このアクションにキーを割り当てる必要があります。右側の "+"アイコンをクリックして、イベントの設定を開きます。

../../_images/input-mapping-add-key.webp

「入力を確認しています...」というフィールドが自動的に選択されるはずです。キーボードの "→" キーを押すと、メニューがこのように表示されます。

../../_images/input-mapping-event-configuration.webp

"OK" ボタンをクリックします。これで "→" キーが move_right アクションに関連付けられました。

以上の手順を残り3方向分設定します。

  1. move_left を左矢印キーに設定します。

  2. move_up を上矢印キーに設定します。

  3. そして move_down を下矢印キーに設定します。

インプットマップは次のようになります:

../../_images/input-mapping-completed.webp

「閉じる」ボタンを押してプロジェクト設定を終了します。

注釈

今回は一つのキーのみを各アクションに設定しましたが、複数のキーやジョイスティックボタン、マウスボタンを同じアクションに設定することができます。

キーが押されているかどうかを Input.is_action_pressed() を使用して検出できます。これは、押された場合は true 、押されていない場合は false を返します。

func _process(delta):
    var velocity = Vector2.ZERO # The player's movement vector.
    if Input.is_action_pressed("move_right"):
        velocity.x += 1
    if Input.is_action_pressed("move_left"):
        velocity.x -= 1
    if Input.is_action_pressed("move_down"):
        velocity.y += 1
    if Input.is_action_pressed("move_up"):
        velocity.y -= 1

    if velocity.length() > 0:
        velocity = velocity.normalized() * speed
        $AnimatedSprite2D.play()
    else:
        $AnimatedSprite2D.stop()

まず velocity(0, 0) に設定することから始めます - デフォルトでは、プレイヤーは動いてはいけません。次に、各入力をチェックし、 velocity から加算/減算して全体の方向を取得します。たとえば、 を同時に押した場合、結果の velocity ベクトルは (1, 1) になります。この場合、水平方向と垂直方向の動きを追加しているため、プレイヤーは水平方向に移動した場合よりも、斜め方向に速く移動します。

加速度を正規化すれば、これを防ぐことができます。つまり、速度の長さ1 に設定し、それから希望の速度を乗算します。これは、これ以上速い対角移動がないことを意味します。

ちなみに

以前にベクトル演算を使用したことがない場合、あるいは忘れてしまった場合は、ベクトル演算でGodotのベクトル使用の説明をみることができます。これは知っておくと良いですが、このチュートリアルの残りの部分では必要ないでしょう。

また、AnimatedSprite2Dの play() または stop() を呼び出せるようにするため、プレイヤーが移動中かどうかも確認します。

ちなみに

$get_node() の省略形です。したがって、上記のコードでは、$AnimatedSprite2D.play()get_node("AnimatedSprite2D").play() と同じです。

GDScriptでは、$ は現在のノードからの相対パスにあるノードを返し、ノードが見つからない場合は null を返します。 AnimatedSprite2Dは現在のノードの子であるため、$AnimatedSprite2D を使用できます。

移動方向がわかったので、プレイヤーの位置を更新します。clamp() を使用して、プレイヤーが画面を離れないようにします。Clampingの意味は長さに制限をかける事です。_process 関数の下部に追加して下さい (else までインデントしないように注意):

position += velocity * delta
position = position.clamp(Vector2.ZERO, screen_size)

ちなみに

_process() 関数の delta パラメーターは フレームの長さ - 前のフレームが完了するまでに要した時間を参照します。この値を使うことで、動きの処理はフレームレートの変動の影響を受けなくなります。

「シーンを実行」( F6 、macOSでは Cmd + R )をクリックして、画面上で全方向にプレイヤーを移動できることを確認してください。

警告

「デバッガ」パネルで以下のようなエラーが発生した場合

null インスタンス上の ベース 'null インスタンス' の関数 'play' を呼び出そうとしています。

この場合、AnimatedSprite2Dのノード名のスペルが間違っている可能性があります。ノード名は大文字と小文字を区別するので、$NodeName はシーンツリーに表示されている名前と一致させる必要があります。

アニメーションの選択

プレイヤーを移動できるようになったので、AnimatedSprite2Dが再生するアニメーションを方向に合わせて変更させる必要があります。今あるのは「walk」アニメーションで、プレイヤーは右方向へ歩きます。左への動きには flip_h プロパティを使用して水平に反転させます。また「up」アニメーションもあり、これは flip_v で垂直に反転させれば、下への動きになります。では、このコードを _process() 関数の最後に配置します:

if velocity.x != 0:
    $AnimatedSprite2D.animation = "walk"
    $AnimatedSprite2D.flip_v = false
    # See the note below about boolean assignment.
    $AnimatedSprite2D.flip_h = velocity.x < 0
elif velocity.y != 0:
    $AnimatedSprite2D.animation = "up"
    $AnimatedSprite2D.flip_v = velocity.y > 0

注釈

上記のコードにおけるブール値の代入は、プログラマーがよく使う略式記法です。比較テスト (ブール値) とブール値の代入を行っていますが、両方とも同時に行うことができます。次のコードと、上記の1行でのブール値代入とを比べてみましょう。

if velocity.x < 0:
    $AnimatedSprite2D.flip_h = true
else:
    $AnimatedSprite2D.flip_h = false

もう一度シーンを再生して、それぞれの方向のアニメーションが正しいことを確認してください。

ちなみに

ここでよくある間違いは、アニメーションの名前を間違って入力してしまうことです。SpriteFramesパネルに表示されるアニメーションの名前は、コードの中で入力したものと一致していなければなりません。もしアニメーションの名前を "Walk" とした場合、コード中では大文字の "W" も使わなければなりません。

動きが正しく機能していることを確認したら、次の行を _ready() に追加して、ゲームの開始時にプレイヤーが非表示になるようにします:

hide()

コリジョン(衝突/当り判定)の準備

Player には敵に攻撃されたことを検知してもらいたいのですが、まだ敵を作っていません!Godotのシグナル機能を使って動作させるので、大丈夫です。

スクリプトの先頭に以下のプログラムを追加します。GDScriptを使用している場合は、 extends Area2D の後に追加してください。C#を使用している場合は、 public partial class Player : Area2D の後に追加してください。:

signal hit

これは、プレイヤーが敵と衝突したときにプレイヤーが発信する(送り出す)"hit"と呼ばれるカスタムシグナルを定義します。衝突を検出するために Area2D を使用します。 Player ノードを選択し、インスペクタタブの横にある「ノード」タブをクリックすると、プレイヤーが発信するシグナルのリストが表示されます:

../../_images/player_signals.webp

Notice our custom "hit" signal is there as well! Since our enemies are going to be RigidBody2D nodes, we want the body_entered(body: Node2D) signal. This signal will be emitted when a body contacts the player. Click "Connect.." and the "Connect a Signal" window appears.

Godot will create a function with that exact name directly in script for you. You don't need to change the default settings right now.

警告

If you're using an external text editor (for example, Visual Studio Code), a bug currently prevents Godot from doing so. You'll be sent to your external editor, but the new function won't be there.

In this case, you'll need to write the function yourself into the Player's script file.

../../_images/player_signal_connection.webp

Note the green icon indicating that a signal is connected to this function; this does not mean the function exists, only that the signal will attempt to connect to a function with that name, so double-check that the spelling of the function matches exactly!

Next, add this code to the function:

func _on_body_entered(body):
    hide() # Player disappears after being hit.
    hit.emit()
    # Must be deferred as we can't change physics properties on a physics callback.
    $CollisionShape2D.set_deferred("disabled", true)

敵がプレイヤーに当たるたびに、シグナルが発せられます。プレイヤーの衝突を無効にして、 hit シグナルを複数回トリガーしないようにする必要があります。

注釈

エリアのコリジョン形状を無効にすると、それがエンジンの衝突処理の途中だったときにエラーが発生する可能性があります。 set_deferred() を使用すると、安全にシェイプを無効にできるようになるまでGodotを待機させることができます。

最後のピースとなるのは、新しいゲームの開始時にPlayerをリセットするため、呼び出す関数を追加することです。

func start(pos):
    position = pos
    show()
    $CollisionShape2D.disabled = false

playerが設定できたことを確認したら、次のパートで敵を設定しましょう。