1. ZIPの構造を知る
カードZIPは、ゲーム名と属性定義・カード情報・画像をまとめたファイルです。人のZIPを使うだけなら入門編の取り込み手順へ進めます。
my-cards/
├── game.json
├── cards/
│ └── cards.json
└── images/
├── DMO-R05.jpg
├── DMO-R12.jpg
└── DMO-R12_p1.jpg2. game.jsonを作る
UTF-8のテキストで保存します。拡張子が .json.txt にならないよう確認してください。format と version は固定、名前と属性は自分のゲームに合わせます。
{
"format": "tcgt-cards",
"version": 1,
"game": {
"name": "デモカードゲーム",
"fields": [
{ "key": "color", "label": "色", "type": "select", "options": ["赤", "青", "緑", "黄"] },
{ "key": "kind", "label": "種類", "type": "select", "options": ["ユニット", "魔法", "フィールド"] },
{ "key": "cost", "label": "コスト", "type": "number" },
{ "key": "power", "label": "パワー", "type": "number" }
]
}
}key は属性の識別子、label は表示名です。select の options には選択肢を入れます。型番とカード名は fields へ追加しません。
3. カードのJSONを作る
cards/cards.json にカードの配列を保存します。code と name は必須です。images の先頭が代表の絵、2枚目以降はパラレルです。
[
{
"code": "DMO-R05",
"name": "炉尾の仔",
"attributes": { "color": "赤", "kind": "ユニット", "cost": 1, "power": 1000 },
"images": ["images/DMO-R05.jpg"]
},
{
"code": "DMO-R12",
"name": "熔冠の獣",
"attributes": { "color": "赤", "kind": "ユニット", "cost": 6, "power": 9000 },
"images": ["images/DMO-R12.jpg", "images/DMO-R12_p1.jpg"]
}
]| 属性の型 | 値の例 |
|---|---|
| text | "説明文" |
| number | 1000 |
| select | "赤" |
| multiselect | ["赤", "青"] |
| boolean | true |
4. 画像のパスを合わせる
- 自分の画像を images/ へ保存します。画像URLを書く方式ではありません。
- ファイル名は半角英数字と - _ . を使うと扱いやすくなります。
- パスはZIP内からの相対パス。先頭の / や ./、上の階層へ戻る .. は使いません。
- 大文字小文字・拡張子を一致させます。
- 用意しないパラレル画像のパスは削除します。
同じ型番は同じカードとして扱われます。絵違いは1件の images にまとめると管理しやすくなります。
5. ZIPに圧縮する
game.json・cards/・images/ を同じフォルダに置き、そのフォルダをZIP形式に圧縮します。外側のフォルダ1階層は取り除いて読めますが、何重にも包まないでください。
Pythonで作る場合
Python 3が使える環境で、my-cards の隣に make_zip.py として保存し、python3 make_zip.pyを実行します。既存ZIPは上書きしません。
from pathlib import Path
import json
import zipfile
source = Path(__file__).resolve().parent / "my-cards"
output = source.parent / "my-cards.zip"
assert (source / "game.json").is_file(), "game.jsonがありません"
assert list((source / "cards").glob("*.json")), "カードJSONがありません"
files = sorted(p for p in source.rglob("*") if p.is_file())
assert len(files) < 65535, "ファイル数が上限を超えています"
for path in [source / "game.json", *sorted((source / "cards").glob("*.json"))]:
json.loads(path.read_text(encoding="utf-8"))
with zipfile.ZipFile(output, "x", compression=zipfile.ZIP_STORED,
allowZip64=False) as archive:
for path in files:
archive.write(path, path.relative_to(source).as_posix())
print(output)6. アプリへ取り込んで確かめる
- ZIPを端末または開けるクラウドへ保存します。
- カード一覧の「+ 追加」→「ZIP を選ぶ」で開きます。Android では、展開したフォルダを「フォルダを選ぶ(展開した ZIP)」から選ぶこともできます(ダウンロードフォルダの直下そのものは選べないので、中のフォルダを選びます)。
- 件数・画像数・警告を確認します。この例ではカード2種類・画像3枚です。
- 下書きを確認して保存し、名前・型番・属性・パラレルを確認します。
最初は新しい確認用ゲームへ入れると、既存カードへの追加を避けて確認できます。新しいゲームとして取り込んだ場合、遊ぶための盤面とデッキ設定は別に用意します。
7. 枚数を増やす・AIを使う
cards/set1.json、cards/set2.json のように複数ファイルへ分けられます。各ファイルをカードの配列にします。
アプリの「AI 用の仕様をコピー」をAIへ渡し、カード情報と実在する画像ファイル名の一覧を添えます。不足情報は推測させず一覧にし、大量の場合は生成用スクリプトと実行手順を依頼します。少数で取り込みを確認してから増やしてください。
登録済みカードからなら、カード一覧の「書き出す」でも同じ形式のZIPを作れます。型番がないカードは採番の確認が入ります。
読めないときに確認するところ
| 症状 | 確認すること |
|---|---|
| game.jsonがない | 階層、ファイル名、拡張子 |
| JSONを読めない | カンマ、引用符、括弧、UTF-8 |
| 画像が見つからない | 実ファイルと相対パス、大文字小文字 |
| 属性が空になる | key、値の型、optionsとの一致 |
| 件数が少ない | 同じ型番にまとめられていないか |
| 再取り込みで増えない | 同じ型番・同じ絵はスキップされます |