はじめてのGodot 第3回: 画面の外に出ないようにしよう — 関数とclamp


前回で宇宙船が動くようになりましたが、画面の外まで飛んで行けてしまいます。今回はこれを直しながら、自分で関数を作ることを学びます。

今回のゴール

宇宙船が画面の端で止まり、外に出られない様子

  • 宇宙船が画面の端で止まる
  • おまけ: 移動方向に機体が傾く

その前に: Godotの座標系

ここで一度、座標の話をします。この連載で一番大事なコラムです。

数学のグラフではyは上に行くほど増えますが、Godot(およびほとんどの2Dゲームエンジン)では逆です。

  • 画面の左上が原点 (0, 0)
  • xは右に行くほど増える(これは直感どおり)
  • yは下に行くほど増える

前回、上キーで (0, -1) になると書いたのはこのためです。「上=マイナス、下=プラス」。今後何度も出てくるので、ここで体に入れておいてください。

画面内に閉じ込める

player.gd をこう書き換えます。

extends Sprite2D

var speed = 400

func _process(delta):
	var direction = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
	position += direction * speed * delta
	keep_inside_screen()

func keep_inside_screen():
	var screen_size = get_viewport_rect().size
	position.x = clamp(position.x, 0, screen_size.x)
	position.y = clamp(position.y, 0, screen_size.y)

実行すると、宇宙船が画面の端で止まるようになります。

何をしたのか

自分の関数を定義する

func keep_inside_screen():_process と同じ func で、自分の関数を作りました。_process はGodotが呼んでくれる特別な関数でしたが、自分で作った関数は自分で呼びます。それが _process の中の keep_inside_screen() という行です。

なぜ関数に分けるのか? _process の中に全部書いても動きますが、コードが伸びると読めなくなります。「画面内に収める」というひとまとまりの仕事に名前を付けて取り出すと、_process を読むだけで「移動して、画面内に収めている」と日本語のように読めるようになります。コードが伸びてきたら関数に分ける — この習慣を今日から始めましょう。

clamp() — 値を範囲内に収める

clamp(値, 最小, 最大) は「値が範囲からはみ出していたら、端に押し戻す」関数です。

  • clamp(500, 0, 480)480(はみ出したので最大値に)
  • clamp(240, 0, 480)240(範囲内なのでそのまま)

これをx座標とy座標それぞれにかけることで、画面の外に出られなくしています。get_viewport_rect().size は画面のサイズ(このゲームでは 480 × 720)を返します。

おまけ: 移動方向に傾ける

見た目が一気にゲームらしくなる小技です。_process の最後に1行足してください。

	rotation = direction.x * 0.3

右に動くと右に、左に動くと左に機体が傾きます。rotation はノードの回転角で、単位はラジアンです(0.3ラジアン ≒ 17度)。度で書きたい場合は rotation_degrees = direction.x * 17 でも同じことができます。

つまずきポイント

  • Function "keep_inside_screen()" not found: 関数の定義(func keep_inside_screen():)が _process中に入ってしまっていませんか? func 同士は同じ字下げレベル(行頭)に並べます
  • 機体の半分が画面外にはみ出る: position は画像の中心なので、端では半分はみ出します。気になる人は clamp(position.x, 30, screen_size.x - 30) のように余白を付けてみてください(30 は画像の半分の幅)。こういう微調整も立派なゲーム開発です

今回学んだこと

  • Godotの座標は左上が原点で、yは下向きに増える
  • func 名前(): で自分の関数を定義し、名前() で呼び出す
  • ひとまとまりの仕事は関数に分けると読みやすくなる
  • clamp(値, 最小, 最大) で値を範囲内に収める
  • rotation の単位はラジアン

次回予告

操作まわりはこれで完成です。第4回ではいよいよ敵 — 降ってくる隕石を作ります。「シーンを部品として作る」という、Godotの設計思想の核心に触れる回です。

第4回: 隕石を作ろう — シーンを部品として作る