敵のステータスをスクリプトに直書きしていると、敵の種類を増やすたびにコードをコピペし、バランス調整のたびにコードを開いて数値を書き換える——そんな消耗を感じたことはないでしょうか。しかもプランナーやデザイナーは、コードを触れないと数値ひとつ変えられません。
この悩みを解くのが カスタムリソース(Custom Resource) です。Godotの Resource システムを拡張して独自のデータ型を作り、 ゲームのロジック(コード)とデータ(値)を分離 します。Unityの ScriptableObject に相当する、 データ駆動設計 の要です。
この記事でわかること
- データ駆動設計 とは(ロジックとデータの分離)
Resourceを継承した カスタムリソースの定義 とインスペクタ編集- 継承 で派生リソースを作る(
ItemData→WeaponData)duplicate()で 実行時の変更を安全 に行う- JSON / CSV / SQLite との 使い分け
データ駆動設計とは
データ駆動設計とは、 「処理(ロジック)」と「値(データ)」を切り離す 考え方です。1つの汎用的なコードに、差し替え可能なデータを与えて、多彩なバリエーションを作ります。

例えば「敵」を動かすコードは1つ。そこに「スライムのデータ」「ゴブリンのデータ」「ドラゴンのデータ」を差し替えて渡せば、同じコードが別々の敵になります。 データを直書きしない ことで、
- 敵を増やすとき、コードでなく データファイルを増やすだけ で済む
- バランス調整が、コードを開かず インスペクタで数値を触るだけ になる
- プランナーやデザイナーも、コードを知らずにデータを編集できる
——と、開発がぐっと楽になります。この「データ」を担うのがカスタムリソースです。
カスタムリソースを定義して使う
カスタム リソースは、Resource を継承したスクリプトで 型を定義 し、その 値をインスペクタで編集 して、 .tres ファイルに保存 します。

まず、Resource を継承して @export でプロパティを並べます。class_name を付けると、グローバルな型として使えます。
# character_data.gd
class_name CharacterData
extends Resource
@export var character_name: String = "New Character"
@export var max_health: int = 100
@export var attack_power: float = 15.0
enum Job { WARRIOR, MAGE, ROGUE }
@export var job: Job = Job.WARRIOR # enumはインスペクタで選択式になる
# データに紐づくロジックをメソッドで持たせることもできる
func get_description() -> String:
return "%s / HP:%d / ATK:%.1f / %s" % [
character_name, max_health, attack_power, Job.find_key(job)]
保存したら、FileSystemドックで右クリック →「新規作成」→「リソース」→ CharacterData を選び、player_data.tres などの名前で保存します。あとは、ノード側で 型として直接 受け取れます。
extends CharacterBody2D
@export var data: CharacterData # インスペクタで.tresをドラッグして割り当てる
func _ready() -> void:
if data:
print(data.get_description()) # データに応じた振る舞い
@export var data: CharacterData のように 型を明示 できるので、インスペクタには CharacterData の .tres しかドロップできず、型安全です。
実践:継承でアイテムデータベースを作る
カスタムリソースの強みが最も出るのが、 アイテムや敵のデータベース です。RPGの装備品、ローグライクの消費アイテム、カードゲームのカード——「共通の土台+種類ごとの違い」を、 継承 できれいに表現できます。

まず全アイテム共通の基底 ItemData を作ります。
# item_data.gd
class_name ItemData
extends Resource
@export var item_id: int = 0
@export var item_name: String = "Unknown Item"
@export_multiline var description: String = ""
@export var icon: Texture2D
@export var stackable: bool = true
武器やポーションには固有のデータが要ります。ItemData を 継承 して、足りない分だけ追加します。
# weapon_data.gd
class_name WeaponData
extends ItemData # ItemDataの全プロパティを引き継ぐ
@export var attack_bonus: float = 5.0 # 武器だけの追加プロパティ
@export var weapon_type: String = "Sword"
こうすると、WeaponData は item_name などの共通項目を 持ったまま、武器固有の項目が増えます。読み込むときは、型で判別できます。
func load_item(path: String) -> ItemData:
var res := ResourceLoader.load(path)
if res is WeaponData:
print("武器: 攻撃+%.1f" % res.attack_bonus)
return res if res is ItemData else null
継承の考え方そのものは OOPデザインパターン の記事も参考になります。 共通は基底に、固有は派生に ——この整理で、アイテムが何種類増えても破綻しません。
duplicate()で実行時の変更を安全にする
1つ注意点があります。 リソースは共有されます 。同じ .tres を10体の敵に割り当てると、10体は 同じデータの実体 を見ています。ここで1体のHPを直接書き換えると——全員のHPが変わってしまいます。

実行時に個体ごとの値を変えたいときは、duplicate() で 複製を作り、その複製を変更 します。
func _ready() -> void:
# 共有の元データではなく、自分専用の複製を持つ
data = data.duplicate()
# これ以降 data をいくら書き換えても、他の個体や元の.tresは無事
data.max_health += 20
「敵ごとにHPを少しばらけさせたい」「拾ったポーションの残量を減らしたい」といった 個体差のある変更 は、必ず duplicate() してから行うのが鉄則です。逆に、全個体で共有したい設定(マスターデータ)は、複製せず共有のまま読むだけにします。
代替手段との使い分け
ゲームデータの持ち方は、カスタムリソース以外にもあります。規模と用途で選びます。

| 方法 | 得意 | 向く用途 |
|---|---|---|
| カスタムリソース | エディタ統合・型安全・再利用 | キャラ・アイテム・スキルなど構造化データ |
| JSON | 人が読み書きしやすい・エンジン非依存 | 設定ファイル・外部ツール連携 |
| CSV | 表計算で編集できる | 大量の単純レコード(セリフ集など) |
| SQLite | 大量データの高速クエリ | 数千件を超えるアイテム・ユーザーデータ |
Godot内で完結する構造化データなら、まずカスタムリソース が第一候補です。外部ツールとやり取りするなら JSON、翻訳や大量のセリフはCSV、数千件規模のクエリが要るならSQLite、と使い分けます。
おまけ:先に知っておくと良いこと
.tresと.res:.tresはテキストで Gitと相性が良く 開発向き。.resはバイナリで ロードが速く軽い のでリリース向き。開発は.tres、出荷時に.resへ、が定番です。- 大量ロードは非同期で :起動時に全リソースを読むと重いので、
ResourceLoader.load_threaded_request()で 非同期読み込み し、応答性を保ちます。 - 変更の通知はシグナルで :リソース内の値が変わったことを他へ伝えたいなら、リソース内に シグナル を定義します。
- セーブデータにも使える :プレイ状況をカスタムリソースに詰めて保存する手もあります。セーブ/ロードシステム で扱います。
まとめ
- カスタムリソース は
Resourceを継承した独自データ型。ロジックとデータを分離する class_name+@exportで型を定義し、値はインスペクタで編集、.tresに保存- 継承 で「共通は基底、固有は派生」に整理し、アイテム図鑑などを拡張しやすくする
duplicate()で複製してから変更すれば、共有データを壊さず個体差を出せる- 規模と用途で JSON / CSV / SQLite と使い分ける
まずはキャラの基本ステータスを CharacterData にして、インスペクタで数値をいじってみてください。「コードを触らずにゲームが変わる」感覚が掴めたら、データ駆動設計の第一歩です。
さらに学ぶために
- GDScriptで使うOOPデザインパターン ——継承・class_nameでリソースを整理する
- セーブ/ロードシステムの実装 ——リソースやデータをファイルに保存する
- Autoloadによるシーンをまたぐデータ管理 ——マスターデータをグローバルに持つ
- シグナルによるノード間の連携 ——データ変更を他へ通知する
- Godot公式ドキュメント:Resources ——リソースの一次情報