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