Zenn
Open26

Godot入門

morit4ryomorit4ryo

環境構築

VSCodeとの連携:
https://www.youtube.com/watch?v=-urLt9bvteQ&ab_channel=Queble
あと拡張機能でgodot-tools入れる
これをやっておくと便利ではあるが、Godot上のエディタも引き続き使う(debuggerなど)ので、設定した上でチェックボックスは外しておくのがよさそう

VSCode側に出るエラーの潰し方:
https://lef237.hatenablog.com/entry/2024/05/03/163855

ビルド・デバッグまでVSCodeで完結する場合
https://docs.godotengine.org/ja/4.x/contributing/development/configuring_an_ide/visual_studio_code.html

Cursorの場合:
https://docs.godotengine.org/en/stable/ をドキュメントとして登録しておくと良いかも

morit4ryomorit4ryo

クラスを作りたい時は:

  • ファイル名を他のクラス(例:ColorRect)に揃えて、パスカルケースにしておくと良い
  • class_nameをファイル冒頭・extendsの後にでも記載しておく
WallBase.gd
extends ColorRect
class_name WallBase

superで親クラスの関数拡張(override)が可能

func add_trim(value: int) -> void:
    super.add_trim(value)
    size.y = get_grid() * get_edge_pos()
    return
morit4ryomorit4ryo

クリックの当たり判定を取れるようにするには:

  • クリックしたいもの(例えば敵)をArea2Dで作成
  • 子ノードにCollisionShape2Dを追加
    • インスペクタのShapeで敵の形状に適したShapeを選択する
  • 敵(Area2D)を開き、インスペクタのノードでCollisionObject2D > input_event()を選ぶ
  • gdscriptにfunc _on_***_input_event()が追加されるので、クリックした時の処理を書く
    • 例えばクリックしたら消えるようにするなら、if文を書いてqueue_free()する

https://2dgames.jp/godot2d-click-game2/
https://2dgames.jp/godot2d-click-game3/

morit4ryomorit4ryo

メモ:Controlを入れ子で使うことで、片方をカメラ的に使うことができる(2Dゲームにおいて)
Subviewportを試したが、Subviewportではマウスクリック座標がずれたり、クリックを渡すこと自体が難しかったり、トラブルが多く解決できなかった

morit4ryomorit4ryo

ENUMの書き方:
ゲームの状態を管理するStateを作る

state.gd
extends Node

enum State {PRE_GAME, PLAYING, PAUSED, GAME_OVER, GAME_CLEAR}
var _current_state:int = State.PRE_GAME

func current_state() -> int:
	return _current_state

func game_over() -> void:
	_current_state = State.GAME_OVER
	print("game over")
	return

func game_clear() -> void:
	_current_state = State.GAME_CLEAR
	print("game clear")
	return
morit4ryomorit4ryo

上記のStateのように、プロジェクト全体で共有したい値はグローバル変数として設定できる
https://igarashisant.com/2023/02/15/godot_grobal_variable/

上記のファイルを「State」としてグローバル変数に設定した場合、他ファイルで以下のように呼ぶことができる

main.gd
func _on_input_event(viewport: Node, event: InputEvent, shape_idx: int) -> void:
	if State.current_state() == State.State.GAME_OVER or \
	   State.current_state() == State.State.GAME_CLEAR:
		return
morit4ryomorit4ryo

いわゆるポーズ画面などはDialogを使うと良さそう
https://2dgames.jp/godot-popup/
※だが、サンプルコードが古く、そのままだとGodot 4.3で動かなかった
Dialogに載せたColorRectに透過度を指定して、それを描画に反映させるときは、DialogのTransparentをOnにする

morit4ryomorit4ryo

https://www.reddit.com/r/godot/comments/13pm5o5/instantiating_a_scene_with_constructor_parameters/?rdt=49943

static func()、static varを使うことで、複数呼び出したもの(例えば敵)に共通する状態を持たせることができる
instantiate()は通常そのシーンを呼び出したい.gd側に書くことが多いが(例えば敵.gdをmain.gdで呼び出す)、そのシーン自体でinstantiate()を呼ぶstatic func new_enemy(引数)を作り、本来呼び出したい.gd側でEnemy.new_enemy(引数)することができる
これにより、呼び出す時点で引数を渡すことが可能になる
なお、static func内で使う変数は通常のvarではなくstatic varとなる

instantiate()の発音はインスタンエイト(nationがネーションになるのと同じ法則)
new()とinstantiate()の大きな違いは、instantiate()ではシーンが持つ子ノードまで含めて呼ばれるのに対して、new()ではスクリプトしか呼ばれない(子ノードなどが呼ばれずnullになってしまう)

morit4ryomorit4ryo

ブラウザゲームへのエクスポート:
https://2dgames.jp/godot-html5/
エクスポートされたファイルを全て公開したい場所にアップロードしてしまえば、とりあえずはOK
今回はgithub pagesを使用した
やり方まとめ:

  1. 開発で使用しているレポジトリのrootフォルダにdocsフォルダを作成する
    • と、開発で使用しているファイルと混ざらないので良い
  2. godotでエクスポートする
    • docsフォルダにエクスポートされたものが入るようにフォルダ指定する
    • htmlのファイル名はindex.htmlにしておく(と後々良い)
  3. GitHubのレポジトリの設定ページを開き、以下の感じで設定する
    • わざわざexportsブランチを切るかはお好みで(必要はない)
    • この時にindex.htmlが無いと、ルートページにアクセスした時に404エラーになる
morit4ryomorit4ryo

秒数表示など、桁数が頻繁に変わるとテキスト表示がチラついてしまうものの調整方法

snapped()で浮動小数点数を任意の小数点数に丸める

https://docs.godotengine.org/en/stable/classes/class_@globalscope.html#class-globalscope-method-snapped

Paddingで足りない桁をスペースや0で埋め、任意の桁数に揃える

https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_format_string.html#padding

を組み合わせると、以下のように書ける

_time.text = str("%3.2f" % snapped(elapsed_time() / 1000.0, 0.01)) + "秒"
morit4ryomorit4ryo

UI:Themeの作り方

ボタンなどの見た目をまとめて管理するのに使用する
https://am1.jp/godot/dev/gui-theme/

  • 最初から角丸や影、ちょっと斜めにするなどの見た目が想定されていて、設定のコピペもできるのでhoverなども作りやすい
  • 一々再生しなくても、Theme内のプレビューで軽い動作確認ならできる
morit4ryomorit4ryo

UI: Twitterシェアボタンの作り方

見栄えを整えたいのであれば、LinkButtonではなく、通常のButtonなどを使うとよい
(LinkButtonでは、あらかじめURIがプロパティとして用意されているので、気楽にリンクボタンを作成できるが、通常のボタンと異なり、いわゆるテキストに下線が引かれるだけのスタイリングしかできず、Themeを適用しても見た目が変更されない)
https://docs.godotengine.org/en/stable/classes/class_linkbutton.html

OS.shell_open()を使うことで、LinkButtonと同様の挙動となる
https://docs.godotengine.org/en/stable/classes/class_os.html#class-os-method-shell-open

var twitter_pretext:String = "https://twitter.com/intent/tweet?url=https://sample.com&via=sampleaccount&text="
var twitter_text:String = ""
var twitter_posttext:String = "&hashtags=GodotEngine,indiedev"
twitter_text = twitter_pretext + "Cleared in " + score + "! " + twitter_posttext

func _on_share_button_pressed() -> void:
	OS.shell_open(twitter_text)
	return

情報元:
https://www.reddit.com/r/godot/comments/1d4pylm/link_button_with_image/

morit4ryomorit4ryo

翻訳:CSVでの翻訳ファイルの作成〜適用まで

基本

https://docs.godotengine.org/en/4.0/tutorials/assets_pipeline/importing_translations.html#translation-format

  1. ↑のように、KEY, lang, Stringを設定したCSVファイルを作る。
  2. Project SettingsのLocalizationタブの「Add」から作成したCSVファイルをインポートする。
  3. 以下のように、CSVに記載したKEYをtr()に渡す。
PauseButton.text = tr("PAUSE")

翻訳が正しく機能しているかは、TranslationServer.set_locale(language)で言語を切り替えて確認すると良い。
languageには英語ならen、日本語ならjaが入る。
(動作確認後のコード削除・コメントアウトを忘れずに)

翻訳関連の応用知識

スコア:n点、のように可変するテキストの場合、%sなどのプレースホルダーを使うことができる。

var format_score = "スコア:%s"
score.text = format_score % "10点"

#翻訳時にプレースホルダで値を渡す場合(配列で複数渡すことが可能)
share_text = tr("SCORE_MESSAGE") % [score, time]

プレースホルダーの種類は%s以外にも様々存在する。
https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_format_string.html#placeholder-types

動画での説明は以下を参照した:
https://www.reddit.com/r/godot/comments/1702tfr/localization_in_godot_its_really_easy_and_well/
その他詳細は公式を参照:
https://docs.godotengine.org/ja/4.x/tutorials/i18n/internationalizing_games.html

ログインするとコメントできます