2Dゲームを作成しよう!
Godot Engine バージョン4.3
このチュートリアルでは、Godot 4を使用してシンプルな2Dゲームをゼロから作成する方法を学びます。プレイヤーが動くキャラクターを操作し、敵を避けながらスコアを稼ぐ基本的なゲームを目指します。
ステップ1:プロジェクトの準備
Godot 4のインストール
Godotの公式サイトからGodot 4をダウンロードしてインストールします。
新しいプロジェクトを作成
Godotを起動し、「Create」をクリックしてプロジェクトを作成します。適当な名前を付け、2Dゲーム用のフォルダを指定します。
ステップ2:プレイヤーキャラクターを作成
シーンの設定
Area2D
をメインノード(名前をPlayer
)にします。
Area2D
の子コードとしてAnimatedSprite2D
とCollisionShape2D
を追加ます。
下記の画像のように設定してください。
idle
とrun
の二つのアニメーションを追加します。
- 各アニメーションに動かしたいフレームをドラッグ&ドロップしてください。
- 各アニメーションに
FPS
を設定します
下記の画像のように設定してください。
スクリプトを追加
Sprite2DにGDScriptをアタッチし、プレイヤーの移動ロジックを記述します。
extends Area2D
# プレイヤーが敵や障害物に衝突したときに発信されるシグナルsignal hit
# プレイヤーの移動速度@export var move_speed = 400
# 画面サイズを格納する変数var screen_size
# ゲーム開始時の初期化処理func _ready(): # ビューポートのサイズを取得して screen_size に保存 screen_size = get_viewport_rect().size
# フレームごとの処理func _process(delta): # プレイヤーの移動方向を示すベクトル (初期値はゼロ) var velocity = Vector2.ZERO # 入力に応じて移動方向を設定 if Input.is_action_pressed("move_up"): velocity.y -= 1 # 上方向 if Input.is_action_pressed("move_down"): velocity.y += 1 # 下方向 if Input.is_action_pressed("move_left"): velocity.x -= 1 # 左方向 if Input.is_action_pressed("move_right"): velocity.x += 1 # 右方向 # 移動方向が設定されている場合、速度を計算 if velocity.length() > 0: # ベクトルを正規化し、速度を掛けて移動速度を設定 velocity = velocity.normalized() * move_speed # 移動アニメーションを再生 $AnimatedSprite2D.play("run") else: # 移動していない場合、待機アニメーションを再生 $AnimatedSprite2D.play("idle") # 現在の位置に移動方向と速度を掛けた移動量を加算 position += velocity * delta # プレイヤーが画面外に出ないように位置を制限 position = position.clamp(Vector2.ZERO, screen_size) # 移動方向に応じてスプライトを反転 if velocity.x != 0: $AnimatedSprite2D.flip_v = false # 縦方向の反転を無効化 $AnimatedSprite2D.flip_h = velocity.x < 0 # 左に移動する場合スプライトを反転
# プレイヤーを初期状態に戻す処理func start(): show() # プレイヤーを表示 $CollisionShape2D.disabled = false # 衝突判定を有効化
# プレイヤーが別の物体と衝突した際の処理func _on_body_entered(body): hide() # プレイヤーを非表示にする hit.emit() # "hit" シグナルを発信 $CollisionShape2D.set_deferred("disabled", true) # 衝突判定を無効化
_on_body_entered
をシグナルを設定してプレイヤーが別の物体と衝突した際の処理をできるようにします。
入力マッピングの設定
Godotの「Project Settings」で、「Input Map」から
move_up
, move_down
, move_left
, move_right
を確認します。
ステップ3:敵を作成
シーンの設定
Rigibody2D
をメインノード(名前をEnemy
)にします。
Rigibody2D
の子コードとしてAnimatedSprite2D
,CollisionShape2D
とVisibleOnScreenNotifier2D
を追加ます。
下記の画像のように設定してください。
walk
のアニメーションを追加します。
- アニメーションに動かしたいフレームをドラッグ&ドロップしてください。
- アニメーションに
FPS
を設定します
下記の画像のように設定してください。
敵の動きのロジック
敵を制御するスクリプトをアタッチします。
extends RigidBody2D
# ノードが準備完了時に呼び出されるfunc _ready(): # AnimatedSprite2Dノードのアニメーションを再生 $AnimatedSprite2D.play()
# 毎フレーム呼び出されるfunc _process(delta): pass # 現在は特に処理を実行しない
# オブジェクトが画面外に出たときに呼び出されるfunc _on_visible_on_screen_notifier_2d_screen_exited(): # オブジェクトを削除してメモリを解放 queue_free()
# 敵の向きを切り替える関数# flip: Vector2 値で、x方向の向きに基づいてスプライトを反転func flip_enemy(flip): if (flip.x < 0): # x方向の値が負の場合 $AnimatedSprite2D.flip_v = false # 縦方向の反転を無効化 $AnimatedSprite2D.flip_h = true # 横方向の反転を有効化
敵が画面外に出た場合は削除する処理をします
VisibleOnScreenNotifier2D
のシグナルscreen_exited()
をスクリプトの_on_visible_on_screen_notifier_2d_screen_exited
と設定します
ステップ4:タイトル画面やゲームオーバー画面を管理するUI作成
シーンの設定
CanvasLayer
をメインノード(名前をCanvas
)にします。
CanvasLayer
の子コードとしてタイトル用のLabel
, スコア用のLabel
とスタートやリスタートのButton
を追加ます。
- タイトル用の
Label
は画面の中央に設定して好きなタイトルのテキストにしてください。
- スコア用の
Label
は画面の上の方に設定して、初期スコアとして0
にします。
- スタートやリスタートの
Button
はタイトルの下に設定します。
下記の画像のように設定してください。
Canvas
にスクリプトを設定します。extends CanvasLayer
# ゲーム開始を通知するカスタム信号signal start_game
# ノードの初期化時に呼び出されるfunc _ready(): # スコアの表示を隠す $Score.hide()
# 毎フレーム呼び出されるfunc _process(delta): pass # 現在は特に処理を実行しない
# スタートボタンが押されたときに呼び出されるfunc _on_start_button_pressed(): # スコアを表示 $Score.show() # タイトルを隠す $Title.hide() # スタートボタンを隠す $StartButton.hide() # ゲーム開始の信号を送信 start_game.emit()
# スコアを更新する関数# score: 更新するスコアの値func update_score(score): # スコアのテキストを更新 $Score.text = str(score)
# ゲームオーバー画面を表示する関数func game_show_over(): # タイトルを「GAME OVER」に変更して表示 $Title.text = "GAME OVER" $Title.show() # スタートボタンを「RESTART」に変更して表示 $StartButton.text = "RESTART" $StartButton.show()
このスクリプトの使用場面
- タイトル画面やゲームオーバー画面を管理するUIコントローラーとして機能します。
- スタートボタンの動作、スコア表示の更新、ゲームオーバー画面の切り替えをシンプルに実装します。
- プレイヤーのアクションに応じて信号や表示を管理し、ゲーム全体の流れを制御します。
ステップ5:メインシーンの作成
シーンの設定
Node2D
をメインノード(名前をMain
)にします。
Node2D
の子コードとしてColorRect
を追加してBackground
に名前を変更します。名前通りに背景の色になります。好きな色に変更してください。
- プレイヤーを追加します。プレイヤーシーンをドラッグ&ドロップします。
- 次にTimerを二つ追加します。一つは
EnemyTimer
に名前を変更します。敵の生成を管理するタイマーになります。Wait Time
を0.5s
にします。もう一つはスコア用のタイマーになります。名前はScoreTimer
です。一秒づつスコア用のLabel
を更新するためになります。
- Marker2Dを追加します。これはプレイヤーを初期位置に設定するためのものになります。プレイヤーのスタートする好きな位置に配置して名前を
PlayerPosition
にします。
- 次に先ほど作ったタイトル画面やゲームオーバー画面を管理するUIをドラッグ&ドロップします。
- 敵をランダムの場所から生成するために
Path2D
を追加します。名前はEnemyPath
にします。子としてPathFollow2D
を追加します。名前はEnemySpawnLocation
にします。
下記の画像のように設定してください。
敵の生成の作成
敵の生成のために
Path2D
(EnemyPath)を追加したと思います。それを使っていきます。Path2D
を選択すると、エディタの上部にいくつかの新しいボタンが表示されます:
中央のアイコン([点を空きスペースに追加])を選択し、表示されているコーナーをクリックしてポイントを追加してパスを描画します。ポイントをグリッドにスナップするには、[グリッドスナップを使う]が選択されていることを確認します。このオプションは、[選択Nodeをロック]ボタンの左側にあり、「交差する線と磁石」のアイコンで表示されています。
重要:時計回りにパスを描画します。そうしないと、モブは内側ではなく外側を向いて発生します!
画像に
ポイント 4
を配置した後、「カーブを閉じる」ボタンをクリックすると、カーブが完成します。パスが定義されたので、
EnemyPath
の子として追加したPathFollow2D(EnemySpawnLocation)
は自動的に回転し、パスの移動に従うので、パスに沿ってランダムな位置と方向を選択できます。
Main
にスクリプトを設定します。extends Node2D
# 敵キャラクターのシーンを定義@export var enemy_object: PackedScene# 敵の速度を設定@export var enemy_speed = 400
# スコアの初期値var score = 0
# ノードの初期化時に呼び出されるfunc _ready(): # プレイヤーとタイマーを非表示・停止 $Player.hide() $ScoreTimer.stop() $EnemyTimer.stop()
# ゲームオーバー時の処理func game_over(): # スコアと敵生成のタイマーを停止 $ScoreTimer.stop() $EnemyTimer.stop() # GUI にゲームオーバー画面を表示 $GUI.game_show_over() # 敵キャラクターをすべて削除 get_tree().call_group("enemies", "queue_free")
# 新しいゲームを開始する処理func new_game(): # スコアをリセット score = 0 # プレイヤーの初期化 $Player.start() # スコアと敵生成タイマーを開始 $ScoreTimer.start() $EnemyTimer.start() # プレイヤーを初期位置に設定 $Player.position = $PlayerPosition.position # スコアを更新 $GUI.update_score(score)
# スコアタイマーがタイムアウトした際に呼び出される処理func _on_score_timer_timeout(): # スコアを増加 score += 1 # GUI にスコアを更新 $GUI.update_score(score)
# 敵生成タイマーがタイムアウトした際に呼び出される処理func _on_enemy_timer_timeout(): # 敵キャラクターを生成 var enemy = enemy_object.instantiate() # 敵生成位置をランダムに設定 var enemy_spawn_location = get_node("EnemyPath/EnemySpawnLocation") enemy_spawn_location.progress_ratio = randf() # 敵の移動方向をランダム化 var direction = enemy_spawn_location.rotation + PI / 2 enemy.position = enemy_spawn_location.position direction += randf_range(-PI / 4, PI / 4) # 敵の速度を設定し、方向に応じて回転させる var velocity = Vector2(randf_range(150.0, 250.0), 0.0) var linear = velocity.rotated(direction) enemy.linear_velocity = linear enemy.flip_enemy(linear) # 敵の向きを速度に合わせて変更 # 敵をゲームシーンに追加 add_child(enemy)
このスクリプトの使用場面
- ゲームの全体的なロジック管理を担当。
- スコアの管理、敵キャラクターの生成と削除、ゲームオーバーや新しいゲームの開始などを処理します。
- 敵のランダムな挙動とスコアシステムを統合し、ゲームプレイを楽しくします。
ステップ6:ゲームをテストして完成!
最後にゲームを実行して動作を確認します。チュートリアルを通じて、2Dゲームの基本が完成しました!
このチュートリアルをもとに、プレイヤーの強化や新しい敵の追加など、さまざまな機能を拡張してみてください。質問があればぜひQ&Aページで相談してください!
1
100%
最終更新日: 2025/03/27 01:56