
1. はじめに
最近、Webゲームを制作している中で、「素材の保存先」 という壁にぶつかりました。
ローカルストレージ(localStorage)は手軽ですが、容量制限は約5MB。
たとえば 画像素材をまとめたZIPファイル(3〜5MB) を保存しようとすると、すぐに限界に達してしまいます。
ゲーム開発者のリアルな悩み
- キャラクター画像やボイス素材をプレイヤーごとに切り替えたい
- 素材をZIPでまとめて配布したいが、毎回ダウンロードは避けたい
- キャッシュされた素材でオフラインプレイさせたい
こうしたニーズを叶えるには、単なるlocalStorageでは太刀打ちできません。
IndexedDBとは何か?
そこで登場するのが IndexedDB。 これはブラウザ内に存在する、構造化されたローカルデータベースです。
- 最大数百MB以上の保存容量
- 画像(Blob)やファイルを扱える
- データベース的にキーと値を管理可能
一見すると難しそうに見えますが、モダンなラッパーライブラリ idb を使えば驚くほど簡単に扱えます。
このあとは、localStorageとIndexedDBの違いを表で比較しつつ、 実際のゲーム素材保存&読み込み方法までステップを追って紹介していきます。
2. localStorageとの違い
localStorage はWeb開発ではおなじみの保存手段ですが、構造の単純さゆえに限界もあります。
ここでは localStorage と IndexedDB を実際のユースケースに照らして比較してみましょう。
✅ 主な比較表
特徴・仕様 | localStorage |
IndexedDB |
---|---|---|
保存容量 | 約5MB(ブラウザ依存) | 数十〜数百MB(圧倒的に多い) |
保存形式 | 文字列のみ(JSONに変換して保存) | 文字列、数値、オブジェクト、Blob、ArrayBuffer など |
データ構造 | キーと値のみ(シンプル) | オブジェクトストア(テーブル)とキー、インデックス |
非同期対応 | ❌ 同期処理(setItem / getItem ) |
✅ 非同期API(Promise / await )対応 |
速度 | 小規模データでは高速 | 複雑な検索や大量データに最適化済み |
使いやすさ | ◎(手軽だが限界あり) | ◯(慣れれば柔軟だがAPIは複雑) |
ユースケース | スコア保存、テーマ設定など | 画像/音声のキャッシュ、ZIPやアセットの管理 |
🧠 どちらを使うべきか?
- localStorage は 設定値やフラグ、軽量スコアなどの用途に最適。
- 一方で IndexedDB は 素材・アセット・Blob形式の大容量データを保存したいときに真価を発揮します。
🔑 キーワードは「構造化された大容量データの永続化」
🕹 ゲーム開発での具体例
使用場面 | 向いている保存先 |
---|---|
ユーザーの音量設定(数値) | localStorage |
ゲームの進行履歴(JSON) | localStorage |
ZIPファイルで管理する画像セット(3MB超) | IndexedDB |
キャラクター別の音声ファイル(Blob) | IndexedDB |
サムネイル一覧・コレクションギャラリー | IndexedDB(+メタ情報のインデックス) |
このように、それぞれの得意分野を活かして使い分けることが重要です。
特にゲームや画像を扱うWebアプリでは、IndexedDBの導入で表現の幅が大きく広がります。
次は、実際にIndexedDBをどう使っていくか、
「ゲームでの活用シーン」を軽く触れながら、第3章へ進みましょう。
3. ゲームでの活用シーン(軽く触れる)
🎮 「素材を自由に入れ替えたい」——その夢、IndexedDBで叶います。
Webゲーム開発において、以下のような実用的かつクリエイティブなシーンで IndexedDB は活躍します。
✅ 1. ZIP素材の保存(3〜5MBの画像セット)
プレイヤーがアップロードした .zip ファイルの中に、
- カード画像(1.webp〜10.webp)
- キャラボイス(voice_01.ogg など)
- メタ情報(info.json)
といったアセット一式を丸ごと保存して、次回起動時にもそのまま再利用できます。
✅ 2. メタ情報と紐づけた管理
ZIPの中にある info.json に、
{
"title": "森の図書館",
"author": "AI Composer",
"thumbnail": "1.webp"
}
のようなメタ情報を付けておけば、IndexedDBに保存する際に一緒に管理できます。
これにより、ユーザーの画面に以下のようなものが実現可能になります:
- サムネイル一覧からZIPを選択
- キャラ名や説明を表示
- タイトル画面で「前回使ったセット」を自動表示
✅ 3. キャッシュレスなプレイ体験の構築
一度読み込んだZIPを IndexedDB に保存しておけば、2回目以降のプレイは完全オフラインでも可能。
しかも、ファイルはBlobとして保存されるため:
- 通信不要
- 即時ロード
- スマホ・PCでも高速再生
💡 補足:保存はスコアや設定だけじゃない
今までは localStorage に「スコア」「音量」「言語設定」などを保存していたかもしれません。
でも IndexedDBなら、
「ゲームそのもの」=素材や世界観も保存できます。
たとえば、キャラクターを変えたら声も絵柄も変わる
—— そんな「プレイヤーが創造するゲーム体験」が、ついに実現可能なのです。
次はいよいよ「IndexedDBの基本操作」をコード付きで見ていきます!
4. IndexedDBの基本操作
🧠 IndexedDBって難しい? たしかに素のIndexedDB APIは以下のように:
- 非同期コールバック地獄
- トランザクションの管理が煩雑
- ブラウザ依存コードが増えやすい
……など、「挫折ポイント」が多く、慣れないとかなりツライです。
でも、救世主があります。
🦸♂️ idbライブラリ(by Jake Archibald)
Googleの開発者 Jake Archibald 氏が作った idb を使えば、たった数行でIndexedDBの操作が可能になります。
✅ 基本の流れ:データベースを開く
import { openDB } from "./js/idb.js"; // ローカル or CDNから読み込み
const db = await openDB("GameData", 1, {
upgrade(db) {
db.createObjectStore("zips"); // ストア名:zips
}
});
- 第1引数:DB名
- 第2引数:バージョン(スキーマ変更時に番号を上げる)
- upgrade()内で初期化処理(テーブル作成)
✅ データの保存(put)
ZIPファイルやBlobデータをそのまま保存可能:
await db.put("zips", zipBlob, "main.zip");
- 第1引数:ストア名(“zips”)
- 第2引数:保存するデータ(Blobや文字列など)
- 第3引数:キー(“main.zip”)
✅ データの取得(get)
const zipBlob = await db.get("zips", "main.zip");
- 第1引数:ストア名
- 第2引数:キー
✅ データの削除(delete)
await db.delete("zips", "main.zip");
✅ 保存されているキー一覧を取得(getAllKeys)
const keys = await db.getAllKeys("zips");
console.log("保存されたZIP一覧", keys);
🧪 サンプル全体(まとめ)
import { openDB } from "./js/idb.js";
async function saveZipFile(zipBlob) {
const db = await openDB("GameData", 1, {
upgrade(db) {
db.createObjectStore("zips");
}
});
await db.put("zips", zipBlob, "main.zip");
const saved = await db.get("zips", "main.zip");
console.log("保存されたZIPファイル:", saved);
}
このように、awaitを使って直感的に書けるのが idb の魅力。
まるでメモリ変数を扱うかのように、ブラウザ上にファイル保存が可能になります。
5. ラッパーライブラリの紹介(学習コスト軽減)
😵 IndexedDBは「素のまま」だとキツい
もしあなたが idb や Dexie.js を知らずに IndexedDB を触り始めたら、
きっとこんなコードに出くわすでしょう:
const request = indexedDB.open("MyDatabase", 1);
request.onsuccess = function(event) {
const db = event.target.result;
const transaction = db.transaction(["store"], "readwrite");
const store = transaction.objectStore("store");
const putRequest = store.put({ data: "value" }, "key");
};
😱「え、何これ……もうやめたい」
そこで登場するのが、ラッパーライブラリです。
面倒なAPIの手続きをシンプルに隠蔽し、直感的な書き方を可能にします。
✅ 1. idb(軽量・最小・Google公式)
-
作者:Jake Archibald(Google)
-
サイズ:約6KB(最小構成)
-
学習コスト:★☆☆(Promiseベースで直感的)
-
特徴:
- openDB() 一発でDBが開ける
- get/put/delete/getAllKeys が Promiseで使える
- TypeScript対応
-
使い方:CDNまたはESMで import { openDB } from ‘idb’
🏆「これを知ってるだけで、もう一段上のWeb開発者」
✅ 2. Dexie.js(高機能なORM的ラッパー)
-
作者:David Fahlander 氏
-
サイズ:約30KB
-
学習コスト:★★☆(構文は独特だが強力)
-
特徴:
- クエリ操作が可能(where() / filter() など)
- 複数ストアやバージョン管理に強い
- リアクティブ対応(liveQuery)
- TypeScriptの型管理に強い
-
向いている場面:
- 複雑な構造のデータを複数管理したい場合
- アプリの規模が大きく、拡張性が重要な場合
🧠 どう選べばいい?
状況 | おすすめ |
---|---|
とにかく早く使いたい・学習コストを抑えたい | ✅ idb 一択 |
複雑な構造・多機能なWebアプリを構築予定 | ✅ Dexie.js も検討の余地あり |
👤 ゲーム開発における判断基準
ユースケース | ライブラリ選択 |
---|---|
ZIPの保存と取得だけ | idb で十分 |
コレクション・タグ・履歴など複数のストアが必要 | Dexie.js が楽になるかも |
VueやReactなどのフレームワークと併用 | Dexie の liveQuery が便利な場合もある |
🔚 まとめ
らを選んでも IndexedDB の面倒な生APIとは一切おさらばできます。
大切なのは「目的に合わせて道具を選ぶ」という開発者としての姿勢。
さて、次はいよいよ最終章、
「IndexedDBの導入タイミングと未来への可能性」 です。
6. まとめ
IndexedDBの導入タイミングは?初心者でも触る価値はあるのか?
🎯 IndexedDBを導入すべきタイミング
あなたがWeb開発、特にゲームやメディア系アプリを作っているなら、 以下のような要件が出た時こそ、導入のベストタイミングです。
✅ 導入すべきサイン
- 「画像や音声をローカルに保存して、再利用したい」
- 「ZIPファイルで素材を一括管理したい」
- 「オフラインでゲームを続きから遊ばせたい」
- 「ユーザーごとにカスタマイズ素材を保存したい」
- 「プレイ履歴やコレクションをローカルに蓄積したい」
🧠 初心者でも避けずに触る価値あり
「IndexedDBは難しい」と言われることもありますが、それは昔の話です。
今や idb や Dexie.js といった優秀なラッパーライブラリによって、 誰でも手軽に使える技術に変わりました。
💡 保存するのは「スコア」だけじゃない。「世界」だ。
これからのゲームは、単なる点数や設定だけでなく、 素材そのもの・世界観・体験そのものをユーザーと共有できる時代に入っています。
たとえば——
- キャラが変わると声も絵も違う
- ZIPを配ることで、ゲーム全体が着せ替え可能
- 好きなアセットを保存し、いつでも呼び出せる
そんな柔軟な世界を実現するカギが、このIndexedDBにあるのです。
🔚 最後に
「localStorage卒業」という言葉にピンと来たあなたは、 すでに “表現の幅” をもっと広げたい開発者です。
コードを書ける者だけが、次の時代の遊びを作れる。
その第一歩として、ぜひIndexedDBの導入にチャレンジしてみてください。
🎁 次回予告(予告してもいいなら)
- ✅ IndexedDB + JSZip + UI統合で、「ユーザーが素材を自由に選んで遊べるゲームUI」を作る方法
- ✅ IndexedDB × Indexed UI:「ローカルコレクションビューワー」開発日記
関連リンク

【JavaScript応用講座】localStorageでゲーム設定&履歴を保存する
ユーザーのゲーム設定や履歴を保存したい?localStorageを使えば、ブラウザにデータを永続的に保存できます。この記事では、localStorageの基礎から、JSONを使った設定保存、プレイ履歴の管理まで、ゲーム開発に活用できる実用的なテクニックを初心者 …
https://humanxai.info/posts/javascript-localstorage/
💬 コメント