ステップ2:キャラクターを動かす(2D)
① 新しいシーンを作成
- 上部メニューの シーン → 新規シーン を選択。
- 2Dシーン をクリック → ルートが Node2D のシーンが作成されます。
- 名前を Main として保存しておきましょう。
② キャラクターを用意する
- シーンドックで Node2D を右クリック → 子ノードを追加。
- Sprite2D(スプライト2D) を追加。
- ノード名は分かりやすく Player に変更。
- インスペクタの テクスチャ に、何か簡単な画像を設定(四角や丸でもOK)。
→ 画像がなければ、右クリック → 新規リソース作成 → ImageTexture で作れますが、練習ならプレースホルダーでも大丈夫。
③ スクリプトをアタッチ
- Player(Sprite2D)を選択。
- 上の スクリプトをアタッチ ボタンを押し、デフォルトのまま 作成。
- できた Player.gd を次のように編集します:
extends Sprite2D
# 移動速度(1秒間に何ピクセル動くか)
@export var speed: float = 200.0
func _process(delta: float) -> void:
var direction := Vector2.ZERO
if Input.is_action_pressed("ui_right"):
direction.x += 1
if Input.is_action_pressed("ui_left"):
direction.x -= 1
if Input.is_action_pressed("ui_down"):
direction.y += 1
if Input.is_action_pressed("ui_up"):
direction.y -= 1
# 方向が決まったら正規化して移動(斜めでも速さ一定)
if direction != Vector2.ZERO:
direction = direction.normalized()
position += direction * speed * delta
✨ 解説
- speed:キャラの移動速度。数値を変えると速さを調整できます。
- Input.is_action_pressed("ui_right") など:Godot に最初から入っている「矢印キー入力」のアクション。
- input_vector.normalized():斜め移動が速くなりすぎないように補正。
- position += ...:キャラの座標を更新して移動。
④ 入力マップを確認
- メニューから プロジェクト → プロジェクト設定 を開く。
- 左の 入力マップ を選択。
- ui_up / ui_down / ui_left / ui_right が登録されているか確認。
- デフォルトで 矢印キー と WASD が割り当て済み。
- もしなければ「アクション追加」から手動で登録できます。
⑤ 実行して確認
- 上部の三角ボタン(▶、または F6)でシーンを実行。
- 矢印キーを押すとキャラクターが移動するはずです 🚶
🔍 スクリプトの流れ(丁寧版)
func _process(delta: float) -> void:
- 毎フレーム呼ばれる関数。
- delta は「前のフレームからの経過時間(秒)」で、移動を滑らかにするために掛け算しています。
direction := Vector2.ZERO
- 2Dの「向きベクトル」を最初は (0,0) で用意。
Input.is_action_pressed("ui_right")
- 「右キーが押されているか?」をチェック。
- 押されていれば direction.x += 1。
direction.normalized()
- ベクトルを長さ1に正規化。
- 斜め移動だと速さが√2倍になってしまうのを防ぐため。
position += direction * speed * delta
- 今の座標(position)に移動量を足す。
- 移動量 = 方向ベクトル × 速度 × 経過時間。
💡 発展練習
- 壁にぶつかって止めたい → Player に CollisionShape2D を付け、ルートを CharacterBody2D にする。
- スプライトを回転させる → rotation = direction.angle() を追加。
- アニメーションを付ける → AnimatedSprite2D に切り替えて、歩きアニメを再生。
👉 これで「キー入力を検知して、ノードを動かす」基本がマスターできます。
画像について
インスペクタのテクスチャで画像設定しようとしたのですが項目が「新規ViewportTexture」などたくさんあります。どれを選べばいいですか?
おお、いいところに気づきました 👍
Godot の インスペクタのテクスチャ欄 にある「新規ViewportTexture」「新規NoiseTexture2D」などは、
いわゆる その場で新しいリソースを作成する候補 なんです。
でも今回は「プレイヤー用の見た目」を設定したいだけなので、基本は次のどちらかになります👇
✅ 画像ファイルを使う場合(おすすめ)
- 手元にある PNG / JPG 画像を Godot の FileSystemドック にドラッグ&ドロップで置きます。
(例:res://assets/player.png のようにプロジェクト内にコピーされます) - インスペクタの Texture 欄右の「空白部分」をクリック → ファイル選択ダイアログが出ます。
- そこから player.png を選択。
→ これで Sprite2D に画像が表示されます 🎉
✅ 画像ファイルがまだない場合(仮でOK)
- インスペクタの Texture 欄 → 「新規PlaceholderTexture2D」を選びます。
→ 色付きの四角い仮画像が出ます。 - または「新規NoiseTexture2D」を選んで、パラメータをいじるとランダム模様の画像が出ます。
🔍 ポイント
- 「ViewportTexture」「NoiseTexture2D」などは特殊用途なので今は使わなくて大丈夫です。
- とりあえず PNG画像を入れる or PlaceholderTexture2D を選ぶ が一番シンプルです。
🚧 衝突判定(Collider)の追加
1. プレイヤーに当たり判定をつける
- Player(Sprite2D) を選択
- 右クリック → 「子ノードを追加」
- 「CollisionShape2D」を選択
→ Sprite2D の下に CollisionShape2D が付きます - インスペクタで「シェイプ」項目 → 「新規長方形シェイプ2D」を選択
- 画面中央の「青い四角」が出るので、キャラの大きさに合わせて調整
2. 壁を作る
- ルート(Node2D)を選択して 子ノードを追加
- 「StaticBody2D」を選択(動かないオブジェクト用)
- その下に「CollisionShape2D」を追加
- シェイプを「新規長方形シェイプ2D」にする
- 位置とサイズを変えて「壁」にする
- 例:画面の端に横長の四角を置く
👉 壁は見た目がまだないので、もし見えるようにしたければ ColorRect や Sprite2D を子ノードにして色や画像をつけてください。
3. 動作確認 - 再生ボタン ▶ を押す
- キャラクターを壁にぶつけると 止まるはず です!
⚠️ 注意
今のコードでは position += ... で直接座標を動かしているため、Collider がめり込む場合があります。
これを解決するには「KinematicBody2D」ではなく CharacterBody2D を使うのが基本ですが、最初の練習なので「止まるだけ」でも十分学びになります 👍
🎨 ColorRect(カラーレクト)とは?
四角形を単色で描画するノード です。
主に UI(ユーザーインターフェース) で使われます。
例えば「背景を黒くする」「赤いバーを表示する」といった用途に便利です。
✅ 特徴
自分で画像を用意しなくても 色付きの四角形 を出せる
サイズや位置を簡単に変更できる
ゲーム画面だけでなく UI のレイアウトにもよく使う
📝 例:壁の見た目に使う
StaticBody2D(壁) の子ノードとして ColorRect を追加
インスペクタで「色」を選ぶ(例:灰色)
「サイズ」で四角形を大きくする
→ これで「見える壁」になります
⚠️ 注意
ColorRect は UIノード(Control系) なので、座標の扱いが Node2D 系と違います。
もし「思った位置に置けない」と感じたら、代わりに Sprite2D で色付き画像(白い四角を塗りつぶすだけでもOK)を使う方がわかりやすいです。
👉 壁の見た目をつけるなら
シンプルにいきたい → Sprite2Dに色付き画像
画像なしで済ませたい → ColorRect
という選び方がおすすめです 👍
🧱 ColorRect で壁を作る手順
1. 壁のノードを作る
- ルート(Node2D)を選択
- 「子ノードを追加」 → StaticBody2D を選択(壁は動かないのでこれを使います)
→ ノード名を「Wall」にしておくと分かりやすいです
2. 当たり判定を追加
- 「Wall」を選択したまま「子ノードを追加」 → CollisionShape2D を選択
- インスペクタの「シェイプ」項目 → 新規長方形シェイプ2D を選択
- 画面上に出る青い四角をドラッグして壁の大きさに調整
3. 見た目を追加(ColorRect)
- 「Wall」を選択したまま「子ノードを追加」 → ColorRect を選択
- インスペクタの「色」を好きな色に変更(例:灰色や黒)
- インスペクタの「サイズ」を調整(CollisionShape2Dと同じくらいにすると分かりやすい)
⚠️ 注意点
ColorRect は「Control 系ノード」なので、座標系が Node2D とちょっと違います。
そのため位置がズレて見えることがあります。
👉 そういう時は
- サイズを調整して大きくしてみる
- もしくは オフセットを手動で動かす
を試してください。
✅ 最終的にできる構造
Node2D(ルート)
├─ Player(Sprite2D + CollisionShape2D)
└─ Wall(StaticBody2D)
├─ CollisionShape2D
└─ ColorRect(見た目)
Playerに設定したColiisionShape2Dが以下の警告を出しました
・CollisionShape2Dは、CollisionObject2D派生ノードに衝突シェイプを提供する役割のみを果たします。
Area2D、StaticBody2D、RigidBody2D、CharacterBody2Dなど形状を与えるための子としてのみ使用してください。
おっ!すごくいい気づきです👏
その警告はつまりこういう意味です:
CollisionShape2D は単独では使えない。必ず Area2D や CharacterBody2D などの「当たり判定を持てるノード」の子として使ってね
✅ 今の状況を整理すると
- Player がただの Sprite2D になっていて、そこに直接 CollisionShape2D を付けている → ⚠️ 警告
- 正しくは、当たり判定を持てるノード(例えば CharacterBody2D)を親にして、その子に Sprite2D と CollisionShape2D を置く 必要があります
🛠 修正手順
- Player の作り直し
- 今の「Player(Sprite2D)」を消すか、残しておいてもいいですが、
新しく CharacterBody2D を追加してください(名前は Player にすると分かりやすい)
- 見た目を設定
- Player(CharacterBody2D)の子に Sprite2D を追加
- インスペクタで画像を設定(前と同じキャラ画像)
- 当たり判定を設定
- Player(CharacterBody2D)の子に CollisionShape2D を追加
- シェイプを「新規長方形シェイプ2D」や「新規円形シェイプ2D」にしてキャラの大きさに合わせる
✅ 構造の正解イメージ
Player(CharacterBody2D)
├─ Sprite2D(見た目)
└─ CollisionShape2D(当たり判定)
これで警告は出なくなって、
さらに「物理エンジン的に正しい Player」になります 🎉
先ほどのSprite2DにCollisionShape2Dをつけただけでは壁にぶつからなかったのですがこれが原因ですか?
はい!まさにそれが原因です 💡
理由
- Sprite2D + CollisionShape2D
→ Sprite2D はただの「絵を表示するだけのノード」なので、物理エンジンに関与しません。
→ CollisionShape2D は「形」だけを定義するノードで、自分では動きません。
→ なので「ぶつかる」処理は発生しないんです。
ぶつかる仕組みの正しい形
Godot では「物理に関与する親ノード」が必ず必要です。
- StaticBody2D → 動かない壁
- CharacterBody2D → プレイヤーや敵など、自分で動かすキャラ
- RigidBody2D → 重力や物理演算に従って勝手に動く物体
- Area2D → 当たり判定だけを検知する(コインやトリガー用)
そして、これらの子に CollisionShape2D をつけて初めて「当たり判定」として働きます。
今回のケース
- プレイヤー → CharacterBody2D にすべき
- 壁(ColorRect) → StaticBody2D + CollisionShape2D にすべき
👉 つまり、
「Sprite2Dに直接CollisionShape2Dをつけた」状態では、お互いが「物理オブジェクト」じゃないので、ぶつかりません。
🟦 ステップA-1: プレイヤーを CharacterBody2D に作り直す
- 左の シーンドック で、今の Player(Sprite2Dのやつ)を右クリック → 削除
- 一旦作り直したほうがスッキリします。
- 左上の「+ ノードを追加」ボタン → 検索欄に
CharacterBody2D と入力して追加- 名前を Player に変更
- Player の子ノードとして
- Sprite2D(キャラの見た目用)
- CollisionShape2D(当たり判定用)
を追加
- Sprite2D の テクスチャ にキャラクター画像を設定
- CollisionShape2D を選んで、インスペクタの「形状」から 新規長方形シェイプ(RectangleShape2D) を追加
- サイズをキャラクターの見た目に合うよう調整
🟨 ステップA-2: 壁を StaticBody2D で作る
- シーンに残っている ColorRect を削除(UI用なので今回は不適切)
- 左上の「+ノードを追加」→ StaticBody2D を追加
- 名前を Wall に変更
- Wall の子に CollisionShape2D を追加
- インスペクタで「形状」を 新規長方形シェイプ に設定
- サイズを壁の大きさに調整
- (任意)壁が見えるようにするために
- Wall の子として Sprite2D を追加して、壁っぽい画像を設定
(なければ ColorRect でもOKですが、StaticBody2D の子に入れてください)
- Wall の子として Sprite2D を追加して、壁っぽい画像を設定
🟩 ステップA-3: スクリプトを修正
Player は CharacterBody2D になったので、スクリプトも少し書き換えます。
例(プレイヤー移動用スクリプト):
extends CharacterBody2D
# プレイヤーの移動速度
@export var speed: float = 200.0
func _physics_process(delta):
var direction = Vector2.ZERO
if Input.is_action_pressed("ui_right"):
direction.x += 1
if Input.is_action_pressed("ui_left"):
direction.x -= 1
if Input.is_action_pressed("ui_down"):
direction.y += 1
if Input.is_action_pressed("ui_up"):
direction.y -= 1
# 移動処理
velocity = direction.normalized() * speed
move_and_slide()
ポイント:
- CharacterBody2D には velocity という変数が最初から用意されている
- move_and_slide() を呼ぶと「壁にぶつかって止まる」挙動をしてくれる
これで プレイヤーが壁にぶつかる ようになります 🚀
🎯 ステップBのゴール
プレイヤーがゴールに触れたら「クリア!」と表示される
これで「目的のあるゲーム」になります
📝 手順
1. ゴールを作る
- シーンツリーで メインシーン(例:Main)を開く
- 「+ノードを追加」 → Area2D を追加(名前を Goal に変更)
- Area2D は「範囲に入ったことを検知できる」ノードです
- Goal の子に CollisionShape2D を追加
- シェイプは 長方形 か 円形 でOK(ゴールの範囲になる部分)
- Goal の子に Sprite2D を追加して見やすくする(例:星の画像など)
- 画像がなければ ColorRect を使ってもOK
2. ゴールのスクリプトを追加
- Goal を選択 → 右クリック → 「スクリプトをアタッチ」
- 名前は Goal.gd
- 以下のコードを書きます:
extends Area2D
# プレイヤーがゴールに触れた時の処理
func _on_body_entered(body):
if body.is_in_group("player"): # プレイヤーかどうかチェック
print("クリア!") # ここでクリア処理
3. プレイヤーを「player」グループに入れる
- プレイヤーノード(Player)を選択
- インスペクタの「ノード」タブ → グループ を開く
- player というグループを追加
- プログラムのと完全一致なので表記ゆれに注意(playerとPlayerなど)
4. シグナルを接続する
- Goal を選択 → 「ノード」タブ
- body_entered シグナルを Goal自身 に接続
- 自動で _on_body_entered が作られます(↑のコードと結合)
✅ ここまででできること
プレイヤーがゴールの範囲に触れると「クリア!」と表示される
🎯 ステップCの目標
- プレイヤーがゴールしたら
画面中央に 「クリア!」 と大きく表示されるようにする
① UIノードを追加する
- シーンドックで ルート(2D)ノード を選択します
- 右クリック → 子ノードを追加
- 検索欄に 「Control」 と入力し、追加します(UIの親)
- 名前を UI に変更
- UI を右クリック → 子ノードを追加
- 検索欄で「Label」を選び、追加します
- 名前を ClearLabel に変更
② Labelを調整する
- ClearLabel を選択し、インスペクタで以下を設定:
- テキスト → 「クリア!」
- テーマのオーバーライド → フォントサイズ を大きめ(例:48)
- レイアウト → 中央に配置 を選択
- これで画面中央に「クリア!」が表示されます。
③ 最初は非表示にする
- ClearLabel を選択し、インスペクタの「表示」チェックを OFF にする(非表示)
- シーンドック側の非表示でも問題はない。聞いたときの回答は以下
表示非表示関連の話
非表示のことなのですがインスペクタ側に見つからなかったためシーンドックの方で非表示にしたのですが問題なかったでしょうか
いいところに気づきましたね!👍
結論から言うと、シーンドック(シーンツリー)側で非表示にしたのも問題ありません。
Godotではノードを非表示にする方法が2つあります👇① インスペクタから非表示にする
- チェックボックスを使う方法です。
- CanvasItem を継承しているノード(Sprite2D や Label など)は
インスペクタに「表示」というチェック項目があります。
- CanvasItem を継承しているノード(Sprite2D や Label など)は
- これを外すと、そのノードはゲーム開始時に非表示になります。
② シーンドック(シーンツリー)から非表示にする
- シーンツリー上のノードを右クリック → 表示/非表示 を切り替える方法です。
- こちらも結果は同じで、チェックが外れると非表示で開始されます。
つまり
- どちらで非表示にしても効果は同じ
- インスペクタのチェックボックスとシーンツリーの目アイコンは 連動 しています
なので、シーンドックで非表示にしたのは正しい使い方ですよ😊
- チェックボックスを使う方法です。
④ ゴール時に表示する
- ゴールのスクリプトに以下を追加します(ゴールノードのスクリプト)。
extends Area2D
func _on_body_entered(body: Node) -> void:
if body.is_in_group("Player"): # プレイヤー判定(グループ化してある場合)
$"/root/Node2D/UI/ClearLabel".show()
※ "/root/Node2D/UI/ClearLabel" のパスは、シーン構成に合わせて変えてくださいね。
(ルートが Node2D じゃなく Main とかならそちらになります)
パスの話
- nodeだとエラーなので記述に注意
スクリプトを入力したら以下のエラーが表示されました
Could not find type "node" in the current scope.
なるほど!👍
そのエラーは 型指定の書き方 が原因です。Godot4 では Node は大文字で始まるクラス名です。
node と小文字で書くと「そんな型はないよ」と怒られてしまいます。
修正前(エラーになる)
func _on_body_entered(body: node) -> void:
修正後(正しい)
func _on_body_entered(body: Node) -> void:
もし プレイヤーしか入らない と分かっているなら CharacterBody2D にしてもOKです。
例:func _on_body_entered(body: CharacterBody2D) -> void:
$"/root/Node2D/UI/ClearLabel".show()
👉 まず Node を大文字に直して試してみてください!
✅ 結果
プレイヤーがゴールに触れると
→ 画面中央に「クリア!」がドーン!と出る