Godot Engine Advent Celendar 2022 2日目
この記事はGodot Engine Advent Celendar 2022 2日目の記事となります。
目次
グラフィックス
矩形 (四角形) を描画したい
画像リソースを用意せずに、ひとまず四角形を表示したい場合、ColorRect
ノードを追加すると四角形を表示できます。
ColorRect ノードを作成します。
白い四角が表示されます。
インスペクタの ColorRect > Color から色を変更できます。
GDScriptから color プロパティを設定すると色が変えられます。
# 緑色に変更する
$ColorRect.color = Color.green
Sprite関連
Sprite
ノードの色は modulate
となります
## スプライトの頂点カラーを緑色にする
$Sprite.modulate = Color.green
Spriteの Animation > Vframes
とAnimation > Hframes
を設定すると Sprite.frame の値を書き換えることでアニメーションを実装できます。または AnimatedSprite ノードを使用します。詳細は以下のページに書きました。
アニメーションそのものを制御する場合、 AnimationPlayerノードを使うこともできます。これについては以下の記事に書いています。
【Godot】AnimationPlayerでのアニメーションを実装する基本CanvasItem > Material > 新規CanvasItemMaterial でMaterialを作成し、Blend Mode
に Add
を指定すると加算ブレンドモードで Sprite を描画できるようになります。
Tween関連 (緩急のある動きを作りたい)
Tweenノード を使うと緩急のある (イージング) アニメーションを作れます。詳細は以下のページに書きました。
【Godot】Tweenの使い方ただ 3.5 以降はもう少し便利な書き方ができたり、4.x以降になると lambda式が使えるので簡潔にコードを書けるようです。以下は 3.5 と 4.0 での Tween を解説されている方の記事となります。
ease()
という関数が用意されていて単純な曲線であればこれで実装できます。
ただ、パラメータの指定が独特なのでこのグラフを見てどの値を指定するのかを検討する必要があります。
# cube in
var d = ease(t, 0.4)
# cube out
var d = ease(t, 4.6)
# expo in
var d = ease(t, 0.2)
# expo out
var d = ease(t, 4.8)
個人的に Tweenノード を使うよりもスクリプトで書いた方がお手軽に使える気がしたので、イージングアニメーションを自作するサンプルコードを以下の記事に書きました。
【Godot】イージング関数のサンプルコード描画順の制御をしたい
z_index
の値で描画順を制御できます。この値を大きくするほど手前に描画されます。
# ピラミッドに追加
for i in range(6):
var card = deck.pop_back()
card.set_next_position(get_pyramid_position(i))
card.z_index = i # 下にあるカードが手前に描画する
card.place = Card.ePlace.Pyramid
card.pos_index = i
CanvasLayerノード を使うことで描画順を階層化して制御ができます。詳細は以下の記事に書いています。
【Godot】2Dゲームの描画順の制御方法YSortノードを使うと、簡単に描画順を制御できます。詳細は以下の記事に書いています。
【Godot】YSortを使った描画順の制御Godot Engineでは、クォータービューの仕組みがすでに用意されているので、これを使うことで簡単に実現できます。実装方法は以下の記事に書きました。
【Godot】クォータービューの基本的な作り方スクロール
スクロールしたい場合は Camera2D ノードをシーンに配置して、Current を オンにして、position の値を動かすとスクロールできます。
カメラを有効にしてスクロールをすると基本的にすべてのオブジェクトがスクロール対象となります。ですが、例えばスコア表示などのUIは、通常であれば位置を固定化したいです。
そういった場合に描画位置をスクリーン座標で固定するには CanvasLayer ノードの下に配置します。
CanvasLayerはデフォルトでカメラに追従する(正確には Viewport に追従しない) 設定となっています。これを無効にする (Viewport に追従する) には “Follow Viewport” を Enable にします。
ParallaxBackground / ParallaxLayer ノードを使用することで多重スクロールが実現できます。
【Godot】多重スクロールの実装方法ポストエフェクト
ViewportContainer / Viewport ノードを使用すると CanvasLayer単位でポストエフェクトを適用することができます。
ポストエフェクトを行いたい CanvasLayer ノードの下に、「ViewportContainer」「Viewport」をぶら下げます。
そして ViewportContainerのインスペクタから Stretchにチェックを入れます。
Viewport のインスペクタから Size をスクリーン(ウィンドウ)のサイズに合わせます(以下は 1024×720)。
この設定をすることで、あとは WorldEnvironmentノードなどでポストエフェクトがかけ放題となります。
WorldEnvironmentノードの簡単な使い方については以下の記事に書きました。
【Godot】ブルームを適用する方法WorldEnvironmentの Background の Mode を Canvas とする場合、”Canvas Max Layer” というパラメータがあります。
これはどの CanvasLayer までポストエフェクトを適用するかという値で、これを適用したいレイヤーの描画順の最大値に設定する必要があります。
なお、CanvasLayer のインスペクタには Layer という値があり、これが描画順となります。
画像リソースの動的読み込み
load() で画像リソースのパスを指定することで、画像を動的に読み込むことができます(※ただし同期ロードです)。
var id = 12
# 画像リソースへのパス "res://assets/cards/012.png" を作成する
var path = "res://assets/cards/c%03d.png"%id
# 子ノードに "Sprite" が存在する前提
$Sprite.texture = load(path)
画像を拡大するとぼやけてしまう
Godot Engine はデフォルトでBilinear補間の描画が有効になっています。なので、これを無効にすると拡大してもピクセル比が固定(ドットバイドット、ピクセルパーフェクト)で描画できます。
手順は以下のとおりです。
- 対象の画像を選ぶ
- 「インポート」タブを選ぶ
- プリセットから「2D Pixel」を選ぶ
- 「再インポート」をクリックする
Godot 4.x 以降の場合はプロジェクト設定から変更するのが便利です。
「一般 > レンダリング > テクスチャ」から「Canvas Textures > Default Texture Filter」の値を「Nearest」にするとピクセルパーフェクトとなります。
ノードを使わずに直接描画したい
_draw() をオーバーライドすると、draw_*() 系の関数を使って直接描画できます。以下、三角形の描画例です。
func _draw():
var points = PoolVector2Array()
var colors = PoolColorArray([Color(0, 1, 0, 0.5)])
points.push_back(Vector2(50, 0))
points.push_back(Vector2(0, 200))
points.push_back(Vector2(200, 200))
draw_polygon(points, colors)
ただ、この描画コマンドはキャッシュされる(開始時に1度しか呼び出されない)ため、位置やサイズなどを変更したい場合は、描画情報が変更されたタイミングでupdate()
(Godot4.xの場合はqueue_redraw()) を呼び出して _draw()
を再び呼び出すようにします。
Spineを使いたい
高度な2Dアニメーションを実装する場合、Spineでデータ作成してそれをGodotでインポートします。spine-godotの簡単な使い方については以下の記事にまとめています。
【Godot】spine-godotの使い方メモデフォルトのクリアカラー (背景色) を変更したい
Godot はデフォルトのクリアカラーが灰色 (#777777) ですが、「プロジェクト設定 > レンダリング > 環境」の “Default Clear Color” から変更できます。
UI (Controlノード)
ゲージUI
Godot Engine には ProgressBar / TextureProgress ノードという便利な機能が用意されているので、それを使うことで簡単に実装できます。詳細は以下の記事に書きました。
【Godot】ゲージUIの作り方TextureProgressノードは円状のゲージにすることも可能です。実装方法は以下の記事に書いています。
【Godot】TextureProgressを使用したクールダウンアイコンの実装方法9Slice(拡大・縮小できるUI)を作りたい
Godotには、NinePatchRectというUIノードがあり、それを使うと9Sliceを実現できます。
【Godot】NinePatchRectでスケーラブルなUIを作る方法Label ノードを使わずにフォントを描画したい
draw_string() を使用すると動的に文字を描画できます。以下、サンプルとなります。
extends Node2D
var font:BitmapFont
func _ready():
# デフォルトフォントを取得
font = Control.new().get_font("font")
func _process(delta):
# 描画情報に変更がある場合は update() を呼び出して更新する必要がある
# 更新しない場合は update() の呼び出しは不要
update()
func _draw():
# デフォルトフォントを使って文字を描画
draw_string(font, Vector2(32, 32), "Hello world.")
より詳しくは以下の記事に書いています。
【Godot】スクリプトだけで文字を描画する方法フォント
日本語を表示したい
日本語フォントを使用するにはテーマファイルの作成が必要となります。詳細は以下の記事に記載しています。
【Godot】日本語フォントの設定方法 (Godot3.4〜3.5)Godot4.xからはデフォルトフォントで日本語を表示できるようになったので、“Label”ノードを使用することで日本語を表示できます。
フォントを差し替えるには、まずフォントファイル(*.ttfなど)をファイルシステムに追加します。
次に “Label” ノードのインスペクタから Label Settings
の <空>
のところをクリックします。
<空> をクリックするとポップアップが表示されるので「新規LabelSettings」を選びます。
そして作成された「LabelSettings」をクリックするとフォントの設定項目が表示されます。
次に「Font > Font」の <空>
をクリックして クイックロード
を選びます。
ダイアログから設定したいフォントを選びます。
あとはフォントサイズやアウトライン(縁取り)などを自由に選びます。
なおこの LabelSettings はリソースとして保存しておくと他の Label
でも使いまわすことができます。
ビットマップフォントを使用したい
例えばダメージ数値など、専用の画像で数字を表示したい場合にはビットマップフォントを使う方法があります。詳細は以下の記事に書きました。
ShoeBoxを使用したビットマップフォントの作成方法とGodot Engineでの設定方法入力制御
入力の定義を追加する
インプットマップを使うことで入力判定を追加できます。
以下、マウスのクリック判定を追加する手順となります。
- メニューから
プロジェクト > プロジェクト設定
を選ぶ。 インプットマップ
タブを選んで、アクションに “ui_click” と入力して、「追加」ボタンをクリック- 追加された “ui_click” の行の右側にある「+」をクリックして
マウスボタン
を選択 - 「左ボタン」を選んで「追加」ボタンをクリック
この設定をすることで、以下のコードでクリック判定ができるようになります。
func _process(delta: float) -> void:
if Input.is_action_just_pressed("ui_click"):
print("クリックしました")
マウスカーソルの座標を取得したい
get_viewport()
を使用することでマウス座標が取得できます。
# マウスのX座標
var mx = get_viewport().get_mouse_position().x
# マウスのY座標
var my = get_viewport().get_mouse_position().y
Area2Dのマウスクリックイベントがうまく動かない場合
*Rect
系ノード (TextureRect
や ColorRect
)を使っていると、そちらにマウスイベントを取られてしまうことがあるので、もし *Rect
系ノードを使っている場合は Mouse > Filter
を Ignore
にします。
物理システム関連
物理システムノードの分類
Godot Engineで使用できる物理システムに関するノードと分類は以下のとおりです。
ノード名 | 概要 | 使用例 |
---|---|---|
Area2D | ・衝突の「検知」「影響」 ・シグナルの衝突検知 ・領域内の重力や速度減衰 | ・衝突検知のみのオブジェクト (2Dシューティングなど) ・重力を変化させる装置 |
StaticBody2D | 衝突しても動かない 静的オブジェクト | ・動かない壁や床 ・動かないベルトコンベア ・動かない障害物 |
RigidBody2D | 物理エンジンで動く 物理オブジェクト | ・投擲オブジェクト ・物理パーティクル |
CharacterBody2D | スクリプトで細かく動きを 制御できるRigidBody2D | ・プレイヤー ・動く床 |
ゲームジャンルごとに向いている物理システムノードの分類は以下のとおりです。
- Shoot ‘em up (2Dシューティングゲーム) :Area2D
- 2D Platformer (プラットフォーマー) :CharacterBody2D, StaticBody2D
- Physics puzzle game (物理パズルゲーム) :RigidBody2D, StaticBody2D
(※あくまで向いている、というだけなのでどのように使うのかは自由です)
RigidBody2D関連
Godotでの物理エンジンの基本となる RigidBody2D ノード の使い方は以下の記事にまとめました。
【Godot】RigidBody2Dの基本的な使い方Joint2Dを使うと複数の物理オブジェクトを組み合わせることができます。詳細は以下の記事に書きました。
【Godot】2D Jointの使い方RigidBody2D の “body_entered” といったシグナルはデフォルトで無効となっています(処理負荷軽減のため…?)。なのでインスペクタから有効にする必要があります。
Contacts Monitor を「オン」にして、Contacts Reported を「10」あたりにします。
- Contacts Monitor: 衝突検知を有効にするかどうか
- Contacts Reported: 衝突検知のログを残す件数
ちなみに Contacts Reported の数は衝突検知の最大数なので、衝突が多くなる場合はもう少し数を増やしておきます。
コリジョン関連
「エディタのメニュー > デバッグ」 から 「コリジョンの形状の表示」にチェックを入れると実行時にもコリジョンの形状が表示されるようになります。
【Godot】コリジョンの形状を実行時にデバッグ表示する方法上からのみ衝突する床を作る場合には、コリジョンの設定から「One Way Collision」の項目にチェックを入れます。
KinematicBody2Dでキャラクターを実装し、一方通行床を作る方法は以下の記事に書きました。
【Godot】KinematicBody2Dの is_on_floor() と One wayコリジョンの使い方一方通行床の設定に変更はないですが、Godot4.xの場合は CharacterBody2Dを使用しますので、Godot4.x用の記事を書きました。
【Godot4.x】CharacterBody2Dの is_on_floor() と One wayコリジョンの使い方オブジェクトには “name” というプロパティがあるので、それを使って判定する方法があります。
func _on_Shot_area_entered(area):
# オブジェクト名に "Enemy" または "Boss" が含まれていたら
if "Enemy" in area.name or "Boss" in area.name:
area.hit(1) # 敵に1ダメージ
queue_free() # 自分も消える
もしくは Godot Engine にはコリジョンレイヤーの仕組みがあるので、それを使用して衝突対象を限定することもできます。
詳細は以下の記事に書いています。
【Godot】コリジョンレイヤーとマスクについて例えば KinematicBody2D.move_and_collide() (Godot4.xの場合はCharacterBody2D) で移動した場合には、戻り値は KinematicCollision2D を返します。そして KinematicCollision2D.collider には CollisionObject2D が含まれるので、そこから collider.collision_layer をビット演算することで判定できます。
# 移動と衝突処理を行う
var collision:KinematicCollision2D = move_and_collide(velocity * delta)
if collision:
# 衝突した
var collider:CollisionObject2D = collision.collider # コライダーを取り出す
if collider.collision_layer & (1 << 1) # layer '2' と衝突した.
collider.do_something() # 衝突した対象との任意の処理を行うことができる
(※ name プロパティで判定する方がお手軽かもしれません )
こちらも詳しくは以下の記事に書いています。
【Godot】コリジョンレイヤーとマスクについて衝突対象を判定するその他の方法は以下のとおりです。
# 名前を使う
func _on_Wall_body_enter(body):
if body.name == "Player": # 対象のオブジェクトが複数存在する場合は "in" で比較する.
print("Collision with player")
# グループを使用する
func _on_Wall_body_enter(body):
if body.is_in_group("Player"):
print("Collision with player")
# クラス名を使用する (これには "class_name" を Playerオブジェクトに追加する必要がある)
func _on_Wall_body_enter(body):
if body is Player:
print("Collision with player")
# methodが存在するかどうかを確認する
func _on_Wall_body_enter(body):
if body.has_method("death"):
print("Collision with player")
Area2D には monitoring と monitorable の2つの衝突フラグを使って有効無効を切り替えられます。
- Area2D.monitoring: 自身が衝突を検出するかどうかを判定するフラグ
- Area2D.monitorable: 他者が衝突を検出できるかどうかを判定するフラグ
RayCast2Dノードを使用した交差判定の方法は以下のページに書きました。
【Godot】RayCast2Dの基本的な使い方スクリプトのみでレイキャストする方法については以下の記事に書いています。
【Godot】スクリプトでレイキャストする方法CollisionShape2D / CollisionPolygon2D には disabled というフラグがあるので、これを true にすることでコリジョンを一時的に無効にできます。
1つの CharacterBody2D などに複数のコリジョンを設定している場合は以下の記述ですべて有効・無効を切り替えられます。(※ただし_process() / _physics_process() も無効となります)
## コリジョンの有効・無効を切り替える.
func _set_collision_enabled(b:bool) -> void:
if b:
# 有効にする
unlock_target.disable_mode = CollisionObject2D.DISABLE_MODE_KEEP_ACTIVE
unlock_target.process_mode = Node.PROCESS_MODE_INHERIT
else:
# 無効にする.
unlock_target.disable_mode = CollisionObject2D.DISABLE_MODE_REMOVE
unlock_target.process_mode = Node.PROCESS_MODE_DISABLED
サウンド制御
サウンドを再生したい
プロジェクトにサウンドファイル (.wav / .mp3 / .ogg) を追加して、再生したいシーンまたはノードに AudioStreamPlayer2D
を追加します。
ノード名を 「AudioDrawCard」とした場合、スクリプトで以下のように記述します。
# 再生
$AudioDrawCard.play()
1つの AudioStreamPlayer2D に対し、1つの再生のみとなります(再生中に play() を呼び出すと再生中のサウンドは停止する)。
再生中には再生したくない場合には playing で判定できます。
if $AudioDrawCard.playing == false:
# 再生していないときのみ再生する
$AudioDrawCard.play()
サウンドを動的に読み込みたい
AudioStreamPlayer2D.stream
にサウンドリソースを指定すると、動的な読み込みができます。
詳細は以下のページにまとめました。
【Godot】サウンドを動的にロードして再生する方法BGMを区間リピート再生したい
たとえば「イントロ→A→B」の曲を「A→B」でリピート再生したい場合には「Loop Offset」を設定します。詳細は以下の記事に書きました
【Godot】サウンドの区間リピート再生をする方法スクロールすると音が小さくなる
AudioStreamPlayer2D はカメラの位置に合わせて、音量が距離減衰します(小さくなる)。音源がカメラの位置に依存しないものにしたい場合は AudioStreamPlayer を使用すると距離減衰が行われなくなります。
ファイル操作
ファイルが存在するかどうかをチェックしたい
var f = File.new()
if f.file_exists("user://savedata.txt"):
# ファイルが存在するときの処理
else:
# ファイルが存在しない
push_error("user://savedata.txt は存在しません")
セーブ周り
Fileオブジェクトを使うことでセーブ・ロードすることができます。詳細は以下の記事に書きました。
【Godot】セーブデータの保存方法Godot4.x用に書き直したセーブデータの保存方法は以下の記事となります。
【Godot4.x】セーブデータの保存方法可読性の高い ConfigFile に保存する方法は以下の記事に書いています。
【Godot】ConfigFileの使い方エディタ周り
ショートカットキーを変更したい
「エディター > エディター設定」の「ショートカット」タブから変更できます。
個人的に「クイックオープン」はとても便利なショートカットなので、「Ctrl+T (Cmd+T)」など押しやすいキーに設定しておくことをおすすめします。
より詳しくは以下の記事に書いています。
【Godot】よく使いそうなショートカットキーの紹介出力ウィンドウの制御
ログやエラーが出力される「出力ウィンドウ」はひとまずここをクリックすれば表示・非表示は切り替えられますが、初期設定ではデバッグ実行時に常に表示されてしまいます。
このウィンドウの表示設定をするには、メニューから エディタ > エディタ設定
を選択します。
一般 > Run > Output
から出力ウィンドウの設定をします。
- Always Open Output On Play: デバッグ起動時に出力ウィンドウを自動で表示する
- Always Close Output On Stop: デバッグ停止時に出力ウィンドウを自動で非表示にする
個人的には出力ウィンドウが常に必要ではなく、必要なときだけ表示したいので、Always Open Output On Play
のチェックは外しています。
エディタ拡張をしてみたい
CSVエディタをエディタ拡張で作る例を以下の記事に書きました。
【Godot】エディタ拡張で簡易CSVエディタを実装する方法その他
リソースのパスを文字列以外の指定にしたい
preload()で読み込むシーンやリソースのパスを文字列以外で指定する方法は以下の記事に書きました。
【Godot4.x】シーン・リソースの指定を文字列以外にする方法スロー再生をしたい
Engine.time_scale に 1.0 以下の値を指定するとゲーム全体がスローになります。詳しくは以下の記事に書いています。
【Godot】スロー再生する方法ヒットストップを実装したい
Nodeには set_process() / set_physics_process() といったオブジェクトの更新の有効・無効を切り替える関数が用意されているので、これを使うとヒットストップが実現できます。詳しくは以下の記事に書きました。
【Godot】オブジェクトを一時停止する方法なお、RigidBody2D はこの方法では停止できないため、apply_impulse() で速度を直接書き換えるしかなさそうなようです。
RigidBody2Dには現在の速度を表すプロパティの “linear_velocity” があります。このベクトルの向きを逆にした値を力に加えることで一時停止できます。
# 一時停止用の保存用速度
var _linear_velocity_tmp = Vector2.ZERO
...
# 現在の移動量を保存しておく.
_linear_velocity_tmp = linear_velocity
# 逆方向に力を加えることで動きを止める.
apply_central_impulse(-linear_velocity)
そして、更新が再開したタイミングで保存した速度で力を加えることで、動きを再開できます。
func _process(delta: float) -> void:
if _linear_velocity_tmp.length() != 0:
# 保存した速度を反映.
apply_central_impulse(_linear_velocity_tmp)
_linear_velocity_tmp = Vector2.ZERO # ゼロにする.
ウィンドウをリサイズしたい
スクリプトから画面サイズを変更するには OS.set_window_size()
を使用します
# ウィンドウを 480x320 に変更する
OS.set_window_size(Vector2(480, 320))
なおウィンドウをリサイズしても表示物はそのままのサイズなので、プロジェクト設定の「表示 > ウィンドウ」から「ストレッチ」の設定を以下のように変更すると、リサイズに合わせて表示物のサイズもストレッチされるようになります。
- モード:2d または viewport
- アスペクト:keep
プロジェクト設定を取得したい
プロジェクト設定の情報は ProjectSettings.get() で取得できます。
以下は 2Dコリジョンのレイヤー名を取得する例です。
var collision_layer:int # コリジョンレイヤー番号
var layer: String = ProjectSettings.get(str("layer_names/2d_physics/layer_", collision_layer + 1))
他の設定を取り出すには公式ドキュメントを参照します。
GDScript
オブジェクト・インスタンス
is_instance_valid() でそのインスタンスが有効化どうかを判定できます (※null かどうかでは有効なインスタンスであるかどうかは必ずしも判定できません)
var obj; # 何らかのインスタンス.
if is_instance_valid(obj) == false:
# objは無効なインスタンス.
print("objは破棄済みです")
なお queue_free() による破棄リクエストが行われたかどうかは is_queued_for_deletion() で判定できます。(※例えば、衝突系のシグナルでお互いを破棄するときに、複数回破棄処理が行われないようにする…といったチェックができます)
## 他の剛体と衝突した.
func _on_body_entered(body: Node) -> void:
if self.is_queued_for_deletion():
return # すでに破棄要求されている.
if body.is_queued_for_deletion():
return # すでに破棄要求されている.
# フルーツとヒットした.
var other = body as Fruit
...
get_instance_id() で自身のユニークなインスタンスIDを取得できます。特定のグループに自分を含むインスタンスが登録されているものの、自分以外のすべてと判定したい場合などに、このIDを使用します。
できればメンバ変数 (プロパティ) を追加したほうがよいですが、とりあえず追加したい場合は get_meta() で文字列をキーとした値を設定できます。取り出しは get_meta() で行います。
「is」キーワードで型比較ができるのでそれで判定します。
if obj is KinematicBody2D:
print("objは KinematicBody2D")
(シーン)オブジェクトはデフォルトでは型情報は定義されません。class_name キーワードを指定することで型情報を明示的に定義する必要があります。
extends KinematicBody2D
class_name Enemy # 型情報を定義.
...
func is_alive() -> bool:
return _state == eState.MAIN
このように定義して型情報を明示的に記述すると、別のスクリプトからでも補完ができるようになっておすすめです。
なお、インスタンスを生成するための preload() で読みんだ(シーン)オブジェクトを格納するための変数は、型ではなくて変数であるので、この名前は異なる名前にしておくと良いです。
extends Node2D
# もとはEnemy型となるので、"EnemyObj" のように別名にしておく
const EnemyObj = preload("res://src/enemy/Enemy.tscn")
オブジェクトのインスタンスを print() で出力しても得られるのはリファレンス番号のみとなります。そこで、_to_string() を実装すると、print() でも情報が出力されるようになります。
class Obj:
var name:String = "勇者"
var hp:int = 100
var mp:int = 20
# 文字列表現を返す
func _to_string() -> String:
return "%s hp:%d mp:%d"%[name, hp, mp]
func _ready() -> void:
var obj = Obj.new()
print(obj)
get_tree().paused でゲーム全体を停止する方法と、特定のインスタンスのみ停止する Object.set_process() を使用する方法があります。
ゲーム全体を停止したい場合は以下の記事が参考になるかもしれません。
【Godot】ゲームを一時停止するポップアップウィンドウの実装方法特定のオブジェクトのみ停止したい場合は以下が参考になると思います。
【Godot】オブジェクトを一時停止する方法_physics_process() 内で処理を行うことで更新タイミングが固定化されます。
_prcess() の呼び出しは可変レートであり、呼び出される間隔は不定となります。それに対して物理システムの更新関数 _physics_prcess() はフレームレート固定で呼び出されるためとなります。余談ですが、Godot 2.x では _fixed_process() という関数があったのですが、Godot 3 に移行したときにこの仕様に置き換えられたようです。
シーンの制御
get_tree().change_scene() で別のシーンを読み込むことができます。
# Main.tscn に遷移する
get_tree().change_scene("res://Main.tscn")
シングルトン(常駐)のスクリプトを定義したい
プロジェクト設定から「自動読み込み」に、スクリプト(.gd) または シーン (.tscn) を設定すると、その名前でどこからでもアクセスできる常駐のスクリプト・シーンとなります。
乱数
乱数は、整数の乱数を得る randi() 、浮動小数点の範囲を指定してその間で乱数を得る rand_range() などがあります。詳細は以下の記事に書きました。
【Godot】乱数の使い方について数学
Godot Engineにおける基本的な(ゲームでよく使う)三角関数は以下のとおりです。
- cos(): コサインの値を得る (引数はラジアン)
- sin(): サインの値を得る (引数はラジアン)
- atan2(): アークタンジェント2
- deg2rad(): 引数に角度を与えるとラジアンに変換する
- rad2deg(): 引数にラジアンを与えると角度に変換する
より詳しくは公式ドキュメント GODOT DOCS > @GDScript にかかれています。
Vector2 のよく使いそうな関数については以下の記事にまとめました。
【Godot】Vector2でよく使いそうな関数まとめ曲線
スクリプトでCurve2D モジュールを使うと、始点と終点、制御点を指定することでベジェ曲線を作ることができます。
詳しくは以下の記事に書きました。
【Godot】Curve2Dを使ったベジェ曲線の作り方Array
Arrayでよく使いそうな関数は以下の記事にまとめました。
【Godot4.x】Arrayのよく使う関数まとめArray.shuffle()
で配列の中身をシャッフルできます。
func _ready() -> void:
# 乱数初期化
randomize()
# 山札作成
var deck = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 山札をシャッフル
deck.shuffle()
print(deck)
Array.sort()
は標準の比較演算子によるソートとなるので、独自のソート処理を行いたい場合には、Array.sort_custom()
を使用します。
# カードを "pos_index" でソートするクラス
class CardSorter:
static func sort_ascending(a:Card, b:Card) -> bool:
# 昇順ソート
if a.pos_index < b.pos_index:
return true
return false
static func sort_descending(a:Card, b:Card) -> bool:
# 降順ソート
if a.pos_index > b.pos_index:
return true
return false
呼び出しは以下のように記述します。
func get_pyramid_list():
# ピラミッドに含まれるカードのリストを返す
var ret = []
for c in cards:
var card:Card = c
if card.place == Card.ePlace.Pyramid:
ret.append(card)
# 昇順ソート
ret.sort_custom(CardSorter, "sort_ascending")
return ret
そのスクリプト内でしか使用しなければ、self
を使っても良いです。
func sort_ascending(a:Card, b:Card) -> bool:
# 昇順ソート
if a.pos_index < b.pos_index:
return true
return false
# 呼び出し
var arr = []
arr.sort_custom(self, "sort_ascending")
ちなみに Godot.4.x 以降では lambda 式がサポートされるようになるので、式が渡せるようになるのかもしれません。
文字列操作
よく使いそうな文字列操作関数を紹介します。
- length(): 文字列の長さを求める
- find(): 指定の文字の位置を返す
- to_int(): intに変換する
- to_float(): floatに変換する
- hex_to_int(): 16進数の文字列表現をintに変換する
- to_upper(): 大文字に変換する
- to_lower(): 小文字に変換する
- split(): 文字列を分割する
- replace(): 指定の文字を別の文字に置き換える
- strip_edges(): 文字の前後の空白文字を削除する
- pad_decimals(): 小数部のゼロ埋め
- pad_zeros(): 整数部のゼロ埋め
使い方の詳細は公式ドキュメント GODOT DOCS > String 参照のこと。
【Godot】文字列操作の便利関数まとめGodot Engine (GDScript) には、”Expression” というモジュールが用意されているのでそれを使うと文字列を式として評価することができます。こういった関数は、自作のスクリプト言語を作るときに便利だったりします。
var expression = Expression.new()
# 評価したい文字列表現を渡す
expression.parse("(1+2) * 5")
# 式として評価する
var result = expression.execute()
# "15" と出力される
print(result)
未使用変数の警告を消したい
関数の引数で未使用変数の警告を消したい場合がたまにあります。例えば _process(delta)
の delta
が未使用である場合です
func _process(delta):
pass
このように未使用変数は警告が出てしまうのですが、引数の変数名の前に「_」をつけると未使用変数として警告を抑制することができます。(_deltaなど)
func _process(_delta):
pass
エクスポート関連
Steam向けに出力したい
GodotSteamからGodotで Steamworks を利用するためのモジュールをダウンロードします (おそらくエンジンビルドが必要)。
まだ試していないですが、GDNativeを使っていると少しビルドがややこしそうな感じです。
- GodotSteam (英語ページ)
Android向けにビルドしたい
少し昔に書いた記事ですがビルド手順をまとめておきました。
ただ色々と不完全な記事なので、今後調べ直して新しく記事を書きたいと思っています…。
Webブラウザ向け (HTML5) に出力したい
HTML5で出力する方法については以下の記事に書きました。
【Godot】HTML5へのエクスポート手順ただ、HTML5は GDNativeが動かなかったり、Webサーバーがないと動作確認できない、などの制限があります。
チュートリアル
2Dクリックゲームチュートリアル
公式のチュートリアル (最初の2Dゲーム – Godot Docs) が最初に作るにはややヘビーな内容と個人的に感じて、かなりシンプルなものに削ぎ落としたチュートリアルです。
【Godot】2Dクリックゲームチュートリアル (1/3)Godot Engine でゲームを作る上で、以下の最低限必要な機能を理解することを目的としました。
- プロジェクトの作成方法
- シーンの仕組み
- 当たり判定を持つオブジェクトの作り方
- オブジェクトを動かす方法
- オブジェクトを消滅させる方法
- シグナルの使い方
- パーティクルの使い方
フラッピーバードを作るチュートリアル
2D Platformer (プラットフォーマー) はゲーム開発者には人気のジャンルですが、個人的に初心者が手を出すには難易度の高いジャンルと思っていて、もう少しシンプルなものを作った方が良いのかな…と思って用意したチュートリアルです。
学べることとしては以下のとおりです。
- 2Dアクションゲームを作るときに便利な KinematicBody2Dの使い方(移動と衝突)
- スプライトのフレーム番号を変更してアニメーションする方法
- ゲームオブジェクトの動的な生成と破棄の方法
- フォントの設定方法
ラン&ジャンプゲームを作るチュートリアル
ゲーム開発者に人気の 2D Platformer (プラットフォーマー) のシンプルなルールである「ラン&ジャンプゲーム」のチュートリアルを書きました。
スクロールや地形の自動生成、一方通行床や2段ジャンプの実装方法について学べる記事となっています。
【Godot】ラン&ジャンプゲームのチュートリアル会話イベントを楽に作れるアドオン「Dialogic」の紹介
Visual novel (ノベルゲーム) は一部に人気のゲームジャンルで、「Godot Engine でノベルゲームを作りたい人は多いのかも…?」と思って、「Dialogic」というアドオンの使い方を解説した記事となります。
【Godot】会話イベントが楽に作れるアドオン「Dialogic」の紹介ただ、Dialogicは日々進化を続けていて、最新のバージョンとは動作が異なる部分があるのかもしれません。
個人的にはノベルゲームエンジンは自作したい派なので、自作するときの基本的な機能の説明については以下の記事に書きました。
こちらの記事に書いたように、スクリプトエンジンとしては字句解析や構文解析を作ってプログラム言語に近いものを自作するのがおすすめですが、吉里吉里のKAGのような「1行1命令」のシンプルな実装もありかもしれない…と思って、吉里吉里のKAGを自作する方法についての記事も書いています。
【Godot】吉里吉里のKAGっぽいスクリプトを自作するヒントクォータービューの基本的な作り方
Godot Engine は標準機能でクォータービューが作れる素敵なゲームエンジンです。クォータービューは Turn-based (ターン制) のストラテジーゲームに向いているので、そういったゲームを作りたい方におすすめの記事となります。
【Godot】クォータービューの基本的な作り方落ち物ゲームの作り方
落ち物ゲームの実装サンプルとして、マッチ3ゲームを作ってみたのでサンプルコードと、そのコードを解説する記事を書いています。
【Godot】マッチ3ゲームの実装サンプルと解説外部リンク
他にもTips(メモ書き)をまとめている方がいらっしゃるので、リンクしておきます。
- Godot Engine / GDScript備忘録 (by @slmnll):Godotでじっくりとゲームを作られており、そこで得られた知見が精査してまとめられています
- Godot Engineの備忘録的Tips (by @alkn203):よく使うけれども忘れやすい機能の使い方がまとまっています
- GodotEngine小技集 (by @Saitos620):よく調べないと見つからないようなニッチな情報がまとめられていて勉強になります
- kidooom’ s Scrapbox (godotで検索) (by @sparklewing925): Godot Engine で 実際にドットの2Dゲームを何本か作って得られた情報のメモが書かれていて参考になります
- Godot 4メモ (by @korinVR): VR関連のお仕事を中心にされている方の Godot についてのTipsです
- Godot Japan User Community: @Saitos620 さんを中心に日本のGodotユーザーコミュニティの公式サイトとなりそのコンテンツの1つに「逆引きリファレンス」があります。
- Godot Game Engine 4.0 勉強メモ