mcpField
D
defold-core

defold-core

github.com/gamedev-skills開発5.4k1.2k 回インストール今日更新
リポジトリ

defold-core について

defold-core は、Defold のゲームプロジェクトを開発・検証するためのスキルです。リソース、Lua のライフサイクルやメッセージ、オブジェクト生成とワールド読み込みに加え、参照チェックと Bob によるビルド・実行確認を扱います。

主な機能

  1. 01Defold プロジェクトのリソースとファイルのガイド
  2. 02Lua のライフサイクル、入力、メッセージのパターン
  3. 03実行時のオブジェクト生成とワールド読み込み
  4. 04プロジェクト参照の検証スクリプト
  5. 05Bob によるビルドとヘッドレス実行の確認

活用シーン

  1. 01ゲームオブジェクトやスクリプトの追加・修正
  2. 02不足リソースやビルドエラーの調査
  3. 03入力、メッセージ、オブジェクト生成の実装
  4. 04collection proxy を使ったレベルの読み込み

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/gamedev-skills/awesome-gamedev-agent-skills --skill defold-core

インストール後、Claude Code で/defold-coreを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

agents/
openai.yaml
references/
build-and-run.md
file-formats.md
scripts/
check_defold_project.py

詳細

Defold Core

Defold ゲームの構成、接続、検証を行います。エディターのリソースファイル、Lua スクリプトのライフサイクル、アドレス指定とメッセージ、実行時のスポーンとワールドの読み込み、Bob によるビルドと実行の確認を扱います。 例は Defold 1.14.0 を対象としており、Bob 1.14.0 でビルドし、1.14.0 のヘッドレスエンジンで実行しました。既存のプロジェクトでは、その Defold バージョンが維持されます(バージョンを参照)。

使用する場面

  • Defold プロジェクト(ルートにある game.project、.collection、.go、.script、.gui_script ファイル)で、ゲームオブジェクト、コレクション、スクリプト、入力、メッセージ、スポーン、レベル読み込みを追加または修正するとき、または Bob がリソースの欠落を報告するときに使用します。

使用しない場面: 通常の Lua または LÖVE プロジェクト(love2d-core)、参照資料の説明を超える GUI レイアウト、スプライト、タイルマップ、物理演算の詳細、および以下の関連スキルで扱うエンジンに依存しない設計。

ワークフロー

  1. まず調査します。 game.project([bootstrap] main_collection、[input] game_binding、[project] dependencies)、メインコレクション、および依頼に関連するスクリプトを読みます。プロジェクトのフォルダー構成、id の命名規則、メッセージ名に従い、構成を変更しないでください。CI またはチームで使用している Defold/Bob のバージョンを確認します。
  2. 適切なファイル形式を編集します。 ゲームオブジェクト(.go)にはコンポーネントを格納し、コレクション(.collection)にはゲームオブジェクトや他のコレクションを配置します。ロジックは .script(ゲームオブジェクト)、.gui_script(GUI)、または共有の .lua モジュールに記述します。エディターファイルは protobuf テキストです。構造を保ち、フィールドを推測せずに references/file-formats.md の例を使ってください。
  3. 参照を確認します。 python scripts/check_defold_project.py <project-dir> を実行します(パスはこのスキルフォルダーからの相対パスです。Python 3.10 以降が必要で、Defold のインストールは不要です)。すべての ERROR(存在しない、または大文字・小文字が一致しない /paths、コンパイル後の c サフィックスがない game.project のパス、対応するファイルが存在しない require)を修正します。警告は、まだ使用されていないファイル、未取得のライブラリ依存関係、実行時に読み込まれるファイルを示します。終了コードが 0 になるまで再実行します。
  4. Bob でビルドします。 java -jar bob.jar --root . --variant headless --archive resolve build には JDK 25 と、プロジェクトの Defold バージョンに一致する bob.jar が必要です。終了コードが 1 で ERROR: 行が表示される場合は、参照の破損または Lua の構文エラー(ファイル名と行番号付き)を意味します。生成ファイルを示すエラーの追跡方法は references/file-formats.md を参照してください。
  5. 実行します。 ビルドしただけではゲームが動作することの証明にはなりません。タイムアウトを設定してヘッドレスバンドルを実行し(references/build-and-run.md)、ログを確認します。ERROR:SCRIPT: 行は Lua の実行時エラーを、ERROR:GAMEOBJECT: 行は不正なアドレスまたはソケットの競合を示します。テストが完了時に出力する行を確認してください。終了コードだけでは何も証明できません。ヘッドレスエンジンにはキーボードやマウスがないため、入力の変更はエディターまたはデスクトップビルドで確認し、検証できなかったことを明記してください。

パターン

プロジェクトとリソースの参照

game.project はプロジェクトルートにある INI ファイルです。リソースパスはすべてルート絶対パスです(/main/player.go)。game.project ではコンパイル後のファイルを指定するため、ソースパスの末尾には c が付きます。

[bootstrap]
main_collection = /main/main.collectionc

[input]
game_binding = /input/game.input_bindingc

Bob は game.project から参照できるものだけをビルドします。/builtins/... はエンジンに付属しています。

コレクション、ゲームオブジェクト、コンポーネント

コレクションにはインスタンスを配置し、インスタンスごとにスクリプトプロパティを上書きできます。ゲームオブジェクトにはファイルコンポーネントと、埋め込みコンポーネント(エスケープされた data: 文字列)を記述します。検証済みの完全なファイルは references/file-formats.md にあります。

# main.collection (excerpt): place player.go and override its script's speed
instances {
  id: "player"
  prototype: "/main/player.go"
  component_properties {
    id: "player"
    properties { id: "speed" value: "250.0" type: PROPERTY_TYPE_NUMBER }
  }
}
スクリプトのライフサイクル、self、プロパティ
go.property("speed", 200)                   -- top level only, literal default; editable per instance

local LEFT = hash("left")                   -- hash ids once, not every frame
local RIGHT = hash("right")
local FIRE = hash("fire")

function init(self)
	msg.post(".", "acquire_input_focus")    -- no focus, no on_input calls
	self.held = {}                          -- per-instance state lives on self
end

function update(self, dt)
	local dir = (self.held[RIGHT] and 1 or 0) - (self.held[LEFT] and 1 or 0)
	if dir ~= 0 then
		local pos = go.get_position()
		pos.x = pos.x + dir * self.speed * dt    -- dt-scaled: same speed at any frame rate
		go.set_position(pos)
	end
end

function on_input(self, action_id, action)
	if action_id == LEFT or action_id == RIGHT then
		if action.pressed then self.held[action_id] = true
		elseif action.released then self.held[action_id] = nil end
		return true                         -- consumed: listeners lower on the stack skip it
	elseif action_id == FIRE and action.pressed then
		factory.create("#bulletfactory", go.get_position(), nil,
			{ velocity = vmath.vector3(0, 600, 0) })
		return true
	end
end

function final(self)
	msg.post(".", "release_input_focus")
end

コールバック:init、final、fixed_update、update、late_update(各 update の後、描画前)、on_message、on_input、on_reload。ゲームオブジェクト間の更新順序は定義されていません。fixed_update はフレームごとに [engine] fixed_update_frequency の設定に応じて0~N回実行されます。物理演算のステップも同じ頻度にするには [physics] use_fixed_timestep = 1 も設定し、物理演算に依存するコードはそこに記述してください。self はユーザーデータです。フィールドを格納できますが、pairs(self) と pprint(self) は機能しません。プロパティの型:数値、ブール値、ハッシュ、msg.url、vmath.vector3/vmath.vector4、vmath.quat、resource.atlas("/main/main.atlas") などのリソース、および(1.13.2以降)文字列。

入力バインディングと入力スタック

.input_binding はデバイスをアクション名にマッピングします(key_trigger、mouse_trigger、さらにゲームパッド、タッチ、テキストのトリガー)。フォーカスを取得した各コンポーネントは入力スタックに追加されます。最後に取得したコンポーネントがスタックの一番上にあり、最初に入力を受け取ります。on_input から true を返すと入力がそこで止まるため、ポーズメニューでゲームプレイの入力をブロックできます。キーアクションは pressed と released を通知します。押されているキーは前述のように自分で追跡してください。

アドレス指定とメッセージ

URL の形式は [socket:][path][#fragment] です:"." はこのゲームオブジェクト、"#" はこのコンポーネント、"#sprite" は兄弟コンポーネント、"enemy#ai" は相対オブジェクト、"/manager#controller" は絶対オブジェクト、"main:/loader#loader" は別のワールド内のオブジェクトです。コレクションは名前解決のスコープを作成するため、文字列の ID は送信元のコレクションを基準に解決されます。事前にハッシュ化された ID は常に絶対指定です。

msg.post("/manager#controller", "enemy_spotted", { id = go.get_id() })

function on_message(self, message_id, message, sender)
	if message_id == hash("enemy_spotted") then
		print("from", sender, "id", message.id)
	end
end

メッセージはキューに格納され、フレームの後半でディスパッチされます。テーブルの上限は2 KBです。無効なアドレスを指定すると、ERROR:GAMEOBJECT: Instance '/x' could not be found when dispatching message というエラーがログに記録されます。

ファクトリーとコレクションファクトリー
-- factory component "#bulletfactory" -> one game object; properties override go.property values
local id = factory.create("#bulletfactory", pos, nil, { velocity = vmath.vector3(0, 600, 0) })

-- collectionfactory component "#wavefactory" -> table of collection ids -> new instance ids
local ids = collectionfactory.create("#wavefactory", vmath.vector3(480, 500, 0))
local leader = ids[hash("/leader")]         -- e.g. hash: [/collection0/leader]
go.delete(ids, true)                        -- later: delete them and their children

位置と回転は、生成元オブジェクトの値がデフォルトになります。go.delete() はフレームの終わりに適用されます。コレクションファクトリーのインスタンスごとのプロパティは ID をキーにします:{ [hash("/leader")] = { hp = 5 } }。

コレクションプロキシ(別のワールドを読み込む)
-- excerpt from the loader script; the collection's "#levelproxy" component is a collectionproxy
function init(self)
	msg.post(".", "acquire_input_focus")        -- else the loaded world gets no input
	msg.post("#levelproxy", "async_load")       -- or "load"
end

function on_message(self, message_id, message, sender)
	if message_id == hash("proxy_loaded") then
		msg.post(sender, "init")
		msg.post(sender, "enable")
	elseif message_id == hash("level_done") then
		msg.post("#levelproxy", "unload")       -- disables and finalizes first
	elseif message_id == hash("proxy_unloaded") then
		-- safe to load the next level here
	end
end

読み込まれたワールドのソケットは、読み込まれたコレクションファイルの name: です。そのワールド内のスクリプトは msg.post("main:/loader#loader", ...) で返信し、独自の URL は level1:/level#level となります。set_time_step { factor = 0, mode = 0 } でプロキシのワールドを一時停止できます。

バージョン

game.project にはエンジンのバージョンキーはありません。プロジェクトのビルドに使用する Defold エディターまたは bob.jar のバージョン(CI ではリリースの sha1 が固定されていることがよくあります)と、プロジェクトがライブラリの場合は library.defold_min_version を使用してください。java -jar bob.jar --version でバージョンと sha1 が表示されます。そのバージョンを維持し、依頼されない限り移行しないでください。

落とし穴

  • Bob:the bootstrap.main_collection '/main/main.collectio' can't be found → 設定にコンパイル後のサフィックスがなく、Bob が最後の文字を削除しています。 /main/main.collectionc と記述してください(input.game_binding も同様に → .input_bindingc)。
  • Bob:ERROR: build/default/_generated_….factory:0: the prototype '/main/x.go' can't be found → いずれかの .go に埋め込まれたコンポーネントが、存在しないファイルを参照しています。生成された名前ではなく、引用符で囲まれたパス(/main/x.go)をソース内で検索するか、チェッカーを実行してください。
  • on_input が一度も呼び出されない → オブジェクトが acquire_input_focus を送信していない、アクション名がバインディングと異なる、input.game_binding の参照先が違う、またはスタック上位のリスナーが true を返しています。
  • プロキシで読み込まれたレベル内で入力が機能しない → コレクションプロキシを保持するゲームオブジェクトが入力フォーカスを取得していません。
  • already a socket with the same name が表示され、プロキシが proxy_loaded を送信しない → 読み込まれたコレクションの name: が、すでに読み込まれているワールドと同じです(多くの場合、両方が "main" または "default" です)。プロキシ経由で読み込むコレクションごとに、固有の名前を付けてください。
  • fixed_update が一度も実行されない → [engine] fixed_update_frequency が 0 になっています(デフォルトは 60 です)。物理演算を使う場合は、マニュアルで両方の設定が必要とされているため、[physics] use_fixed_timestep = 1 も設定してください。
  • Bob の実行は成功するのに、実行時に module 'modules.util' not found が表示される → require でスラッシュを使っています(require "modules/util")。プロジェクトルートからのドット区切りパスを使い、/modules/util.lua には require "modules.util" と指定してください。
  • tostring(id) が hash: [<unknown:…>] を出力する → ハッシュはデバッグビルドでのみ元のテキストを保持します。文字列ではなく、ハッシュを比較してください。
  • 2つ目のエンジンで Failed to initialize Remotery がログに記録される、またはテストが終了しない → デバッグエンジンはエンジンサービス(ポート 8001)、ログサーバー、プロファイラーポートを開き、sys.exit がない場合は無期限に待機します。一度に実行するエンジンは1つだけにし、必ずタイムアウトを設定してください。

参考資料

  • references/file-formats.md — 検証済みの最小構成の game.project、.collection、.go、 .atlas、.input_binding、スクリプトファイル、およびビルドエラーをソースファイルまで追跡する方法を説明しています。エディターファイルを手動で作成する前にお読みください。
  • references/build-and-run.md — JDK 25 と bob.jar、Bob のコマンド、プラットフォームと バリアント、タイムアウトとログ確認を含むヘッドレスのスモークテスト、GUI、 スプライト、タイルマップ、衝突オブジェクトに関する参考情報を説明しています。
  • scripts/check_defold_project.py — 読み取り専用の参考チェッカーです。すべてのチェック項目は --help に記載されています。

関連するスキル

  • input-systems — Defold のバインディングを使った再バインド、ゲームパッド対応、入力バッファリング。
  • game-ui-ux — GUI シーンと .gui_script で構築する HUD とメニューの設計。
  • physics-tuning — 衝突オブジェクトの固定タイムステップと衝突判定の調整。
  • camera-systems — 追従/デッドゾーンのロジック。通常は late_update で適用します。
  • save-systems — セーブ形式とスロット。Defold の sys.save/sys.load と組み合わせてください。
  • game-feel — go.animate とタイマーで作る演出。
  • platformer、level-design — このスキルと連携するジャンルおよびレイアウトのガイダンス。
  • love2d-core — このカタログにあるもう1つの Lua エンジンで、LÖVE プロジェクト向けです。

コメント