Godot Engineで2Dゲームを制作するための備忘録です。
この記事はGeminiを活用して作成しました。
0. はじめに
Godot Engine 4.6を使用し、落ちてくるフルーツを駕籠(かご)でキャッチするシンプルな2Dアクションゲームを作成しました。
開発時間約1時間で、スプライトシートによるマルチ表示やスマホのタッチ操作にも対応しています。
1. ゲームの基本仕様
- ジャンル: 落ちもの2Dアクションゲーム
- ターゲット端末: Android(縦画面 / 解像度 1080 × 1920)
- 操作方法: 画面タッチ・ドラッグによる左右移動(PCキーボード操作にも対応)
-
ルール:
- 上から落ちてくるフルーツを駕籠でキャッチすると +10点
- 障害物(台所用品)をキャッチすると -10点
- フルーツはスプライトシート画像からランダムで1種が描画される
2. プロジェクト設定
-
画面サイズ: Viewport Width
1080/ Viewport Height1920 -
Stretch: Mode
canvas_items/ Aspectkeep -
Orientation:
Portrait(縦向き)
3. 各シーンのノード構造と設定
① かご(プレイヤー)シーン:basket.tscn
-
ルートノード:
Area2D(ルート名は Basket に変更)-
子ノード1:
Sprite2D(駕籠のイラスト画像を割り当て) -
子ノード2:
CollisionShape2D(Shape:RectangleShape2D)
-
子ノード1:
② フルーツ(ターゲット)シーン:fruit.tscn
-
ルートノード:
Area2D(ルート名は Fruit に変更する)-
グループ設定:
fruitを追加(※ヒット判定に使用) -
子ノード1:
Sprite2D-
Texture: 8種のフルーツが入ったスプライトシート -
Animation->Hframes:8/Vframes:1(画像に合わせて設定)
-
-
子ノード2:
CollisionShape2D(Shape:CircleShape2D)
-
グループ設定:
③ 台所用品(障害物)シーン:kitchen_item.tscn
-
ルートノード:
Area2D(ルート名は KitchenItem に変更する)-
子ノード1:
Sprite2D(台所用品のイラスト画像) -
子ノード2:
CollisionShape2D(Shape:CircleShape2D)
-
子ノード1:
④ メインシーン:main.tscn
-
ルートノード:
Node2D(ルート名は Main に変更する)-
子ノード1: 駕籠シーンのインスタンス (
Basket) (位置: X 540, Y 1700 付近) -
子ノード2:
Timer(SpawnTimer) (Wait Time:0.8/ Autostart:On) -
子ノード3:
CanvasLayer-
子ノード:
Label(ScoreLabel) (Text:Score: 0)
-
子ノード:
-
子ノード1: 駕籠シーンのインスタンス (
4. スクリプト一覧
かごシーンのBasketに添付
# basket.gd
extends Area2D
# --- 変数定義 ---
# キーボード操作時の移動スピード(float型)
@export var speed: float = 800.0
# タッチ操作時の追従スムーズさ(float型)
@export var follow_speed: float = 15.0
# 指で画面をタッチ中かどうかを管理するフラグ(bool型)
var is_touching: bool = false
# タッチされている目標のX座標(float型)
var target_x: float = 0.0
# --- 関数定義 ---
# ゲーム開始時の初期化処理
func _ready() -> void:
target_x = position.x
# 画面へのタッチやドラッグなどの入力イベントを検知する関数
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventScreenTouch:
if event.pressed:
is_touching = true
target_x = event.position.x
else:
is_touching = false
elif event is InputEventScreenDrag:
if is_touching:
target_x = event.position.x
# 毎フレーム実行される移動計算処理
func _process(delta: float) -> void:
if is_touching:
# 【タッチ操作時】指のX位置に向かってスムーズに移動
position.x = lerp(position.x, target_x, follow_speed * delta)
else:
# 【キーボード操作時】従来の矢印キー(左右)入力による移動
var direction: float = Input.get_axis("ui_left", "ui_right")
position.x += direction * speed * delta
# 移動範囲を画面内に制限(左端80px〜右端1000px)
position.x = clamp(position.x, 80.0, 1000.0)
フルーツシーンのFruitに添付
# fruit.gd
extends Area2D
# --- 変数定義 ---
# フルーツの落下スピード(float型)
@export var speed: float = 300.0
# 表示するフルーツのイラスト番号(int型)
# -1 のときはランダムに決定し、0〜7 を直接指定するとそのフルーツを表示します
@export var fruit_number: int = -1
# --- 関数定義 ---
# 初期化関数(スプライトシートから表示するコマを選択)
func _ready() -> void:
# スクリプトから自分自身(Fruitノード)を "fruit" グループに追加する
add_to_group("fruit")
# フルーツ番号が指定されていない(-1)場合、0〜7の中からランダムに番号を選
if fruit_number == -1:
fruit_number = randi_range(0, 7)
$Sprite2D.frame = fruit_number
# 毎フレーム実行される落下処理
func _process(delta: float) -> void:
position.y += speed * delta
# 画面外に落ちたらノードを削除
if position.y > 2000.0:
queue_free()
台所用品シーンのKitchenItemに添付
# kitchen_item.gd
extends Area2D
# --- 変数定義 ---
# 台所用品の落下スピード(float型)
@export var speed: float = 350.0
# 表示する台所用品のイラスト番号(int型:整数型)
# -1 のときはランダムに決定し、0〜7 を直接指定するとその台所用品を表示します
@export var kitchen_item_number: int = -1
# --- 関数定義 ---
# 台所用品が画面に生み出された瞬間に1度だけ実行される初期化関数
func _ready() -> void:
# 台所用品の番号が指定されていない(-1)場合、0〜7の中からランダムに番号を選ぶ
if kitchen_item_number == -1:
kitchen_item_number = randi_range(0, 7)
# 子ノードのSprite2Dの表示フレーム(コマ)を、決定した台所用品の番号に変更する
$Sprite2D.frame = kitchen_item_number
# 毎フレーム実行される落下と削除の判定関数
func _process(delta: float) -> void:
# 下方向(Y軸のプラス方向)へ移動させる
position.y += speed * delta
# 画面の一番下(2000px)を通り過ぎたらノードを削除して消去する
if position.y > 2000.0:
queue_free()
メインシーンのMainに添付
# main.gd
extends Node2D
# --- 変数定義 ---
# 画面に出現させるフルーツのシーン(PackedScene型)
@export var fruit_scene: PackedScene
# 画面に出現させる台所用品のシーン(PackedScene型)
@export var kitchen_scene: PackedScene
# 現在獲得しているスコア(int型)
var score: int = 0
# スコア表示ラベル(Label型)
@onready var score_label: Label = $CanvasLayer/ScoreLabel
# --- 関数定義 ---
# 初期化とシグナル接続
func _ready() -> void:
$Basket.area_entered.connect(_on_basket_area_entered)$SpawnTimer.timeout.connect(_on_spawn_timer_timeout)
# タイマーによるアイテムのランダムスポーン処理
func _on_spawn_timer_timeout() -> void:
var item: Area2D
# 70%の確率でフルーツ、30%の確率で台所用品を生成
if randf() < 0.7:
item = fruit_scene.instantiate()
else:
item = kitchen_scene.instantiate()
# 画面上のランダムな横位置に配置
item.position = Vector2(randf_range(100, 980), -100)
add_child(item)
# かごとの当たり判定およびスコア計算
func _on_basket_area_entered(area: Area2D) -> void:
if area.is_in_group("fruit"):
score += 10
else:
score -= 10
score_label.text = "Score: " + str(score)
area.queue_free()
5. おわりに
Godot 4.6の Area2D や InputEvent 機能を活用することで、初心者でも短時間でタッチ操作対応の2Dゲームを作成できました。
今後は制限時間機能や難易度調整などを追加して、よりゲーム性を高めていきたいと思います!