アイテムを一から自作する(ステップ・バイ・ステップ)
チュートリアル 6章 の続きです。
ここでは、items/item_speed.tscn(さわると速くなるアイテム)のような部品を、
まっさらな状態から自分で組み立てる手順を通して説明します。
作るのは1個の独立した部品だけです。player.gd も world.gd も
書き変えません(これがこのゲームの「アドイン」方式です)。
まず「当たり判定(コリジョン)」を知ろう
アイテムは、プレイヤーが近づいたことに気づく必要があります。この 「気づくしくみ」が 当たり判定(コリジョン) です。Godot では2つの設定で 決まります。
- layer(レイヤー)=「自分がいる場所」。 自分が何番の部屋にいるかを表します。
- mask(マスク)=「見はる相手の場所」。 何番の部屋を見張るかを表します。
自分の mask に入れた番号の部屋に、相手の layer があると、はじめて反応します。 番号は1から順に、チェックボックスで選びます。
ℹ️ このゲームでの決まり(ここが大事) このゲームでは、プレイヤーはレイヤー3にいます。だからアイテムは、 自分の layer は「からっぽ」 にして、mask のチェックボックス3だけを オンにします。こうすると「プレイヤーだけを見はる部品」になります。 この「3番」という数字はこのゲーム独自の決まりで、Godot がいつも3番、 というわけではありません。お手本の
item_speed.tscnも同じ設定です。
作る手順
① 新しいシーンを作り、ルートを Area2D にする
- メニューの 「シーン → 新規シーン」 を選びます。
- 「ルートノードを生成」で 「その他のノード」 を押し、
Area2Dを選びます。 - できたルートノードの名前を、分かりやすいもの(例:
SpeedItem)に変えます。
💡 ルートを 必ず
Area2Dにするのがポイントです。Area2Dは「範囲に 入った・出た」を教えてくれるノードで、アイテムの心臓部です。
② 当たり判定の形(CollisionShape2D)を足す
- ルートの
Area2Dを右クリック → 「子ノードを追加」 →CollisionShape2D。 - Inspector の
Shapeを押し、「新規 CircleShape2D」(丸)などを選びます。 四角にしたいときはRectangleShape2Dを選びます。 - キャンバスに出たまるいハンドルをドラッグして、当たり判定の大きさを 決めます。
③ 見た目の絵(Sprite2D)を足す
- もう一度ルートの
Area2Dに、子ノードSprite2Dを足します。 - Inspector の
Textureに、使いたい絵をドラッグします。 絵は Microsoft ペイントなどで描いて、プロジェクトのフォルダに入れておくと、 FileSystem に出てきます。 - 大きすぎ・小さすぎたら、
Sprite2DのScaleで調整します。
④ 当たり判定の相手(layer と mask)を設定する
- ルートの
Area2Dをクリックします。 - Inspector で
Collisionの項目を開きます。 Layerのチェックは全部オフにします(自分の場所は「なし」)。Maskは、チェックボックス3だけをオンにします(プレイヤーを見はる)。
💡 最初は
LayerもMaskも「1」がオンになっています。1のチェックを外す のを忘れないようにしましょう。(上の当たり判定の図も見てください。)
⑤ スクリプト(動きのプログラム)を付ける
- ルートの
Area2Dを右クリック → 「スクリプトをアタッチ」。 - そのまま「作成」を押すと、
extends Area2Dから始まる空のスクリプトが できます。 - 中身は、次の「例」の章のコードを書きます。
⑥ body_entered の合図を関数につなぐ
- ルートの
Area2Dをクリックし、Inspector の右にある 「ノード」 タブ → 「シグナル」 を開きます。 body_enteredをダブルクリックし、「接続」 を押します。- これで、プレイヤーが範囲に入ったときに
_on_body_entered関数が 呼ばれるようになります。
💡 迷ったら、⑤でコードを書く前に先にこの接続をしても大丈夫です。
_on_body_entered関数がまだ無ければ、接続したときに自動で作られます。あとからその中身を書きましょう。
⑦ 保存して、ステージに置く
- Ctrl+S で、
items/フォルダなどに.tscnとして保存します。 - できた
.tscnを、自分のステージのキャンバスにドラッグ&ドロップします。 - F5 で実行して、プレイヤーがさわったときの動きをたしかめましょう。
@export を使うと、置いたあとに調整できる
コードの中で変数の前に @export を付けると、その値が Inspector に出てきます。
@export var SPEED_BONUS = 150.0 # 足す速さ
こうしておくと、同じアイテムを2個置いても、1個ずつ別の値にできます。
たとえば「弱いスピードアップ」と「強いスピードアップ」を、コードを書き直さずに
Inspector の数字を変えるだけで作り分けられます。これが @export の便利な
ところで、このゲームのアイテムがどれも Inspector で調整できるのは、この
しくみのおかげです。
例(やさしい順に3つ)
例1:トラップ(さわるとミス)
一番みじかいアイテムです。さわると died(ミス)の合図をプレイヤーに送ります。
extends Area2D
# さわるとミスになるトラップ
func _on_body_entered(body: Node2D) -> void:
body.died.emit() # プレイヤーに「ミス」の合図を送る
💡
diedはプレイヤーが持つシグナル(合図)なので、body.died()ではなくbody.died.emit()と書きます。ハチやノコギリも中では同じことをしています。
例2:スピードアップ
さわると走る速さが増える、使い切りのアイテムです(お手本の item_speed.gd と
同じ考え方)。
extends Area2D
# さわると速くなるアイテム
@export var SPEED_BONUS = 150.0 # 足す速さ
func _on_body_entered(body: Node2D) -> void:
body.SPEED += SPEED_BONUS # プレイヤーを速くする
queue_free() # アイテムを消す(使い切り)
改造アイデア:body.SPEED を body.JUMP_VELOCITY にするとジャンプ力アップ
(JUMP_VELOCITY はマイナスが上向きなので、引くほど高く跳びます)。
例3(応用):時間つき重力チェンジ(ふうせん)
さわるとしばらくの間だけふわっと軽くなり、少ししたら元にもどるアイテムです。 新しいことを3つ使います。
- グループ(
add_to_group/get_nodes_in_group)… 同じ仲間をまとめて扱う。 awaitとタイマー … 「◯秒待ってから続き」を書く。set_deferred… 当たり判定を安全に切り替える(_on_body_enteredの途中で 当たり判定を直接いじると Godot にしかられるので、これを使います)。
CollisionShape2D の名前が CollisionShape2D(作ったときの標準の名前)で
あることを前提にしています。
extends Area2D
# 応用:さわると少しの間だけ「ふわっと」軽くなるアイテム(ふうせん)。
# しばらくすると元の重さにもどります。
@export var GRAVITY_FACTOR = 0.05 # 重力を何倍にするか(小さいほど軽い)
@export var TIME = 2.0 # 効果がつづく秒数
@onready var collision_shape_2d: CollisionShape2D = $CollisionShape2D
func _ready() -> void:
add_to_group("balloon") # 同じ「ふうせん」グループに入れておく
func _on_body_entered(body: Node2D) -> void:
# 画面にある全部の「ふうせん」を、いったん見えなく・さわれなくする
var balloons = get_tree().get_nodes_in_group("balloon")
for balloon in balloons:
balloon.visible = false
balloon.collision_shape_2d.set_deferred("disabled", true)
body.GRAVITY_SCALE *= GRAVITY_FACTOR # 軽くする
await get_tree().create_timer(TIME).timeout # TIME 秒だけ待つ
body.GRAVITY_SCALE /= GRAVITY_FACTOR # 元の重さにもどす
# ふうせんをまた出す
for balloon in balloons:
balloon.visible = true
balloon.collision_shape_2d.set_deferred("disabled", false)
💡 なぜ全部の「ふうせん」を消すの? 効果が続いている間は、グループにいる ふうせんをすべてさわれなくしています(
disabled = true)。だから「効果中に もう1つのふうせんにさわって重力が二重にかかる」ことは起きません。TIME 秒たつと まとめて元にもどります。これがグループを使う理由です。 (ただし、ふうせん以外に重力を変えるアイテムを同時に使うと、もどし方がずれる ことはあります。)
💡 共通ルール:どの例も
player.gd/world.gdを書き変えていません。 プレイヤーの公開変数(SPEED/JUMP_VELOCITY/GRAVITY_SCALE/scale)と シグナル(died/level_complete)だけを通してはたらいています。