Developer

さくさく理解する Godot 入門(ただし2Dに限る)基礎編 シーズン1【第3回】
2021.11.11
Lv1

さくさく理解する Godot 入門(ただし2Dに限る)基礎編 シーズン1【第3回】

目次

画像表示・上下左右キー移動

■画像表示

画面に画像を表示するには Sprite ノード、 または TextureRect ノードを使用する。
これらの機能は微妙に異なるが、両方とも簡単に画像表示可能なので、どちらを使ったもよい。 が、移動する画像は Sprite、位置が固定された画像は TextureRect がいいのではないかと筆者は個人的に考えている。 表示した画像を次節で上下左右矢印キーにより移動させるので、本稿では、TextureRect ではなく Sprite を使用することにする。

まず、新規にシーンを作り、Node2D をルートノードとする。
次に Ctrl + A を押し(または ルートノードを右ボタンクリックしポップアップメニューから「+子ノードを追加」を選ぶ)、 Node2D の子ノードとして Sprite ノードを作成する(下図参照)。

表示したい画像をプロジェクトと同じディレクトリに置く。 そうすると、下図のように、画面左下ファイルシステムペインの「res://」部分に画像が表示されるはずだ。

Sprite を選んだ状態で、ファイルシステムの画像ファイルをドラッグして、 右側のインスペクタペインの「Texture」という部分にドロップする(下図参照)。

そうすると、下図のように、画像が画面に表示されるはずだ(ここでは皆様御存知「いらすとや」様のイラストを使用させていただいた)。
画像ドラッグ&ドロップではなく、Texture 右の ▼ を押し、表示されるメニューから「読み込み」を選び、画像ファイルを選択してもよい。

画像サイズが大きすぎる場合は、画像そのものをペイントツールアプリを使って縮小するか、 下図のように、インスペクタの「Transform」を展開し、Scale x, y を小さな値に変更する。
そうすると下図のようにいい感じのサイズで表示されるようになるはずだ。

同様に、Transform > Position x, y を修正すると表示位置を変更することもできるし、 Sprite ノードをマウスでドラッグし位置を変更することも可能だ。

■矢印キーによる画像移動

前節で画像を表示する方法を示した。次に表示した画像を上下左右矢印キーで移動できるようにしてみよう。

ユーザがキーを押すと、キーインプットイベントが発生し、_input(event) ハンドラが呼ばれる (詳しくは 公式ドキュメント を参照)。

なので、そのハンドラを実装して画像移動を行ってもいいのだが、 それだと処理間隔がキーリピート間隔に依存してしまい、なんだかぎこちない移動になってしまう。
そこで本稿では、各フレーム(通常は60FPS)処理時にコールされる _process(delta) をオーバライドし、 その中でキーが押されているかどうかをチェックするようにする。 この方が _input() ハンドラを実装するよりも画像をスムーズに移動させることができる。

プロジェクトにはプロジェクト設定というものがあり、画面サイズなどを指定することができる。 そのなかに、「インプットマップ」というものがある。
プロジェクト > プロジェクト設定… メニューを選択し、 表示されるダイアログの上部タブの「インプットマップ」を選択すると下図の様に表示される。

インプットマップとはマウスやキー押下に対して名前を付け、その名前のアクションが発生したかどうかを判定可能にするものだ。

デフォルトでは "ui_left"、"ui_right"、"ui_up", "ui_down" にそれぞれ左右上下矢印キーが割り当てられているが、 それに加えて h も "ui_left"、l も "ui_right" に追加することができる。 このように操作を抽象化することで、キー割り当ての変更を行っても、コードをいっさい修正する必要がなくなるというわけだ。

選択されているノードにスクリプトをアタッチするには、エディタ左上の「+巻物」のようなアイコンを押下する。
そうすると、デフォルトのスクリプトが生成されるので、以下のコードを追加する。

const MOVE_UNIT = 200
func _process(delta):
    var dx = int(Input.is_action_pressed("ui_right")) - int(Input.is_action_pressed("ui_left"))
    var dy = int(Input.is_action_pressed("ui_down")) - int(Input.is_action_pressed("ui_up"))
    if dx != 0 || dy != 0:
        $Sprite.position += Vector2(dx, dy) * MOVE_UNIT*delta

「Input.is_action_pressed("ui_right")」は、"ui_right" として設定されているアクションが発生したかどうかを判定するコードだ。 アクションがあった場合は true を、そうでなければ false を返す。int 型に変換した場合、true は 1、false は 0 なので、 「int(Input…("ui_right")) – int(Input…"ui_left"))」部分は左キーが押されていれば -1 を、右キーが押されていれば +1 を値とする。 なので、それを dx、すなわち x 方向の移動方向としているわけだ。 このコードは若干トリッキーなので、可読性に劣り、あまりよろしくないとも言えるのだが、Godot のサンプルにあったし、 簡潔にコードを記述できるので、筆者はよしとしている。

Sprite には x, y の値を持つ Vector2 型の position というプロパティがあり、それが画像の位置を表す。 なので、コードの様に、position に変位量を加えてやれば、上下左右キーが押されている間だけ画像位置を変更できるという寸法だ。

以上で、画面に表示した画像を上下左右キーを使って移動可能になる。

ただ、このままでは画像が画面外にまで出てしまう。これを防ぎたい場合は、下記のように、position の範囲チェックを行うとよい。

func _process(delta):
    var dx = int(Input.is_action_pressed("ui_right")) - int(Input.is_action_pressed("ui_left"))
    var dy = int(Input.is_action_pressed("ui_down")) - int(Input.is_action_pressed("ui_up"))
    if dx != 0 || dy != 0:
        $Sprite.position += Vector2(dx, dy) * MOVE_UNIT*delta
        $Sprite.position += Vector2(dx, dy) * MOVE_UNIT*delta
        $Sprite.position.x = max(40, $Sprite.position.x)
        $Sprite.position.y = max(40, $Sprite.position.y)
        $Sprite.position.x = min(640, $Sprite.position.x)
        $Sprite.position.y = min(400, $Sprite.position.y)

しかしこれでは、画面サイズや画面レイアウトが変更されたときに、上下左右端位置を書き換えなくてはいけない。 次章で説明するように障害物を置き、それとの衝突判定を行うことで、上下左右端処理を行うこともできる。

■まとめ

・移動する画像を画面に表示したい場合は Sprite を使うといいぞ。
・_process(delta) の中で上下左右キーが押されているかを感知し、Sprite.position を修正することで、画像を移動させることができるぞ。
・Input.is_action_pressed(アクション名) でそのアクションが発生(マウス・キー押下など)しているかを判定できるぞ。
・プロジェクト設定 > インプットマップ で各アクションに対応する(マウス・キー)イベントを設定できるぞ。

TechProjin Godot入門 関連連載リンク

Godotで学ぶゲーム制作
さくさく理解するGodot入門 連載目次

標準C++ライブラリの活用でコーディング力UP!
「競技プログラミング風」標準C++ライブラリ 連載目次