4Hえんぴつ|React+TypeScriptでWeb RPGを作る
第0章「この連載について」
第0回:連載の目的と開発ロードマップ
0. はじめに
React+TypeScriptを使って、小さな異世界ファンタジーRPGを個人開発しています。
ゲーム名は仮に、
「冒険に行こう!」
としています。
この連載では、そのゲームを実際に作る中で考えたことや、実装したこと、うまくいかなかったこと、そこからどう直したかを、技術テーマごとに紹介していきます。
もともとの制作記録は、noteの「4Hえんぴつ|ゲームクリエイターへの道」で続けています。
noteでは、ゲームを作ろうと思った背景や世界観、設計を決めるまでの試行錯誤などを中心に書いています。
一方、このQiita連載では、
- React
- TypeScript
- データ設計
- 状態管理
- セーブ
- テスト
- 不具合修正
- Web公開
といった、実際の開発で得られた技術的な内容を中心に扱います。
ただし、
noteを読んでいないとQiitaの記事が分からない
という構成にはしません。
必要な背景やゲーム内の用語は、Qiitaの記事の中でも説明していきます。
今回は第0回として、
そもそも何を作っているのか、この連載で何を伝えたいのか、そして今後どんな順番で記事を書いていくのか
をまとめます。
1. この連載の名前
このQiita連載では、
「4Hえんぴつ|React+TypeScriptでWeb RPGを作る」
という名前を使います。
「4Hえんぴつ」は、ゲーム制作や小説などの創作活動を記録している名前です。
中心に置いているのは、
技術と物語を、一本の線から創る。
という考え方です。
プログラムを書くことと、物語や世界を作ることを完全に別々の活動として扱うのではなく、
技術と創作をつなげながら、一つの作品を作ってみたい。
その実践の一つが、今回のWeb RPGです。
記事の中では、少し短く、
「React+TypeScriptでWeb RPGを作る」シリーズ
と呼ぶこともあります。
2. このシリーズで伝えたいこと
この連載で紹介したいのは、完成したコードだけではありません。
むしろ、
小さく作る
↓
実際に動かす
↓
問題を見つける
↓
設計を見直す
↓
実装する
↓
テストする
↓
もう一度動かす
という過程をできるだけ残したいと考えています。
個人開発では、最初からすべてを正しく設計するのは難しいものです。
今回のRPGでも、
「最初はこれで十分だと思った」
という実装が、町や依頼、イベントを増やしたことで使いにくくなることが何度もありました。
例えば、
- 一つだったイベントを増やしたら管理が難しくなった
- 途中セーブを作ったら保存する情報が増えた
- 失敗した依頼と成功した依頼を同じように扱えなくなった
- HPが0なのに次の行動へ進めてしまった
- 再挑戦したのに前回の状態が残った
といったことです。
この連載では、
「こう作れば正解です」
だけではなく、
「最初はこう作った。でも実際には困ったので、こう変えた」
という部分も扱います。
Web RPGが題材ですが、そこで使う考え方は、ゲーム以外の小さなWebアプリにも応用できるものを意識しています。
3. このシリーズを読んだ先のゴール
この連載のゴールは、
同じRPGをそのまま作れるようになること
ではありません。
目指したいのは、
自分のWebアプリやゲームを、画面・データ・状態・保存・テストなどに分けて考えられるようになること
です。
例えば、シリーズを読み進めることで、
- 最初のプロトタイプをどこまで小さくするか考えられる
- TypeScriptでデータ構造を整理できる
- 変わらないデータと、ゲーム中に変わる状態を分けて考えられる
- Reactの画面とゲーム状態の関係を整理できる
- セーブするときに何を保存すべきか考えられる
- 「画面は動くが、仕様としてはおかしい」という問題に気づける
- 状態の変化をテストできる
- 機能を追加したときの影響範囲を考えられる
といったところまで進められればと思っています。
一言でまとめると、
Web RPGを題材に、個人開発で設計を少しずつ育てていく感覚を共有する
ことが、このシリーズの一つのゴールです。
4. どんな人に読んでもらいたいか
主に、次のような方を想定しています。
- ReactやTypeScriptを勉強している方
- 小さなWebアプリを自分で作ってみたい方
- 個人開発に興味がある方
- ゲームを作ってみたいが、何から始めればよいか迷っている方
- ゲームエンジン以外のゲーム開発にも興味がある方
- データ設計や状態管理を実例から学びたい方
- 技術と創作の両方が好きな方
特に、若手エンジニアや、これから何かを作り始めたい方にも読めるようにしたいと考えています。
そのため、難しい用語を使わないというより、
必要な専門用語は使いながら、初めて出てきたところで意味を説明する
という書き方を基本にします。
ゲーム開発経験がなくても読めるように、RPG固有の用語についても必要に応じて説明します。
5. そもそも、なぜRPGを作ろうと思ったのか
私は、技術だけではなく物語を作ることにも興味があります。
小説では、登場人物や町、国、街道などを文章として作ることができます。
一方、ゲームにすると、
「この町からどこへ行けるのか」
「この出来事に対して何を選べるのか」
「その選択によって何が変わるのか」
を、実際に動く仕組みにする必要があります。
例えば小説なら、
主人公は街道で壊れた荷車を見つけた。
と書けば物語は進みます。
ゲームの場合は、その先に、
助ける
戦う
話を聞く
周囲を調べる
そのまま進む
といった選択肢を用意できます。
そして、選択によって、
HPが減る
ゴールドが増える
評判が変わる
新しい場所へ行けるようになる
依頼の結果が変わる
といった状態変化が発生します。
この、
物語として考えた世界を、データとルールとして動かしてみる
ことに興味を持ったのが、RPG制作を始めた理由の一つです。
6. 作っているのはどんなゲームか
「冒険に行こう!」は、異世界ファンタジーを舞台にした小さなRPGです。
ここでいう「異世界ファンタジー」は、現実とは異なる世界を舞台にした物語を指しています。
プレイヤーは冒険者となり、町で仕事を引き受け、街道を通って目的地へ向かいます。
このゲームでは、ゲーム内の仕事を「依頼」と呼びます。
一般的なRPGでいう「クエスト」に近いものです。
また、町と町、あるいは町と目的地をつなぐ移動ルートを「街道」と呼んでいます。
基本的な流れは、次のような形です。
町
↓
依頼を受ける
↓
街道へ出る
↓
出来事が起きる
↓
どう解決するか選ぶ
↓
結果がゲームへ反映される
↓
町へ戻る
街道では、さまざまな「イベント」が発生します。
ここでいうイベントとは、
移動中などに起きるゲーム内の出来事
です。
例えば、
- 壊れた荷車を見つける
- 困っている人に出会う
- 危険な相手と遭遇する
といったものです。
7. 戦闘だけで解決するRPGにはしない
このゲームで試していることの一つが、
戦闘
交渉
調査
という3種類の解決方法です。
敵らしい相手が現れても、
必ず戦うとは限らない
ゲームにしたいと考えています。
例えば、
- 戦って突破する
- 相手と話して解決する
- 周囲を調べて別の方法を見つける
といった選択ができるようにします。
この仕組みを入れたことで、実装側では、
「戦闘だけ成功・失敗を持てばよい」
という設計では済まなくなりました。
交渉や調査も含めて、
成功
部分成功
失敗
などの結果をどう管理するか考える必要があります。
世界観やゲームデザインの選択が、そのままデータ設計や状態管理へつながっていきます。
このあたりも、Qiitaでは技術テーマとして扱っていきます。
8. このゲームはどんな人に遊んでもらいたいか
現在のWeb版は、スマートフォンで気軽に遊べることを意識しています。
例えば、
- 通勤や休憩などの短い時間でも進められる
- 複雑な操作を覚えなくても遊べる
- 文章を読みながら選択できる
- 戦闘だけではない解決方法を楽しめる
といった方向を考えています。
そのため、Web版ではスマートフォンの縦持ち画面を意識しています。
ゲーム側のこうした方針は、
- ボタンをどう配置するか
- 一画面に何を表示するか
- セーブをいつできるようにするか
- 途中からどう再開するか
といった技術設計にも影響します。
つまり、
ゲームの対象プレイヤーを考えることと、UIやデータを設計することは別々ではない
ということも、実際に作る中で分かってきました。
9. 最初はUnity+C#を考えていた
ゲーム制作を考え始めた当初は、Unity+C#を使う方向で検討していました。
ゲームエンジンを使ってスマートフォン向けに作り、その後PCなどへ広げていく構想です。
ただ、計画を具体化していくうちに、
まだゲームの基本的な遊び方も検証できていない段階で、最初から大きな開発環境へ進む必要があるのか
という疑問が出てきました。
まず確認したいのは、
- 町から旅へ出る流れは面白いか
- 戦闘・交渉・調査という選択は成立するか
- スマートフォンで操作しやすいか
- 町や依頼を増やせる構造になるか
- セーブして続きを遊べるか
といった部分です。
そこで、開発する順番を見直しました。
10. なぜWebアプリから始めることにしたのか
現在のロードマップは、次の順番です。
Webアプリ
↓
PCアプリ
↓
将来の別プラットフォーム
Unity+C#を使わないことにしたわけではありません。
使う順番を後ろへ移しました。
まずWebアプリで、
「このゲームの基本的な仕組みは成立するか」
を確認します。
Web版では、React+TypeScriptを中心に開発しています。
現在使っている主な技術は、
React
TypeScript
Vite
React Router
Vitest
Playwright
Oxlint
IndexedDB
Dexie.js
です。
なぜReactなのか。
なぜTypeScriptなのか。
なぜ最初からゲームエンジンではないのか。
このあたりは、第1回以降で一つずつ取り上げます。
11. 最初に作ったのは、とても小さなRPG
最初のWebプロトタイプでは、
町 1つ
街道 1本
依頼 1つ
イベント 1つ
まで思い切って範囲を小さくしました。
「プロトタイプ」とは、本格的に機能を作り込む前に、アイデアや基本的な仕組みが成立するか確認するための試作品です。
最初から、
- 何十もの町
- 大量の依頼
- 複雑な戦闘システム
- 大規模なセーブデータ
- 完成した世界
を作ることはしませんでした。
まず、
町を出て、出来事に遭遇し、選択し、結果を受け取って、町へ戻れるか。
そこだけを確認しました。
この「小さく始めたこと」が、その後の開発でかなり重要になりました。
12. 現在どこまで作れているのか
最初のWebプロトタイプはすでに完成しています。
その後、Web版をMVPへ広げました。
「MVP(Minimum Viable Product)」とは、実際に使ったり試したりできる、必要最小限の機能を持った製品を指します。
現在は、
- 複数の町
- 複数の依頼
- 複数の街道
- 複数のイベント
- 戦闘・交渉・調査
- 成功・部分成功・失敗
- HP
- ゴールド
- 評判
- 町や街道の解放
- 複数のセーブスロット
- 街道途中からの再開
- 再挑戦
- 宿屋での回復
- 自動テスト
などを持つところまで進んでいます。
つまり、この連載は、
「これからこんなゲームを作りたい」
という構想だけの記事ではありません。
実際に作って、
問題が起きて、
直して、
テストした経験をもとに書いていきます。
13. noteとQiitaでは、少し役割を変える
この開発については、noteでも「4Hえんぴつ|ゲームクリエイターへの道」として記録しています。
ただし、noteの記事をそのままQiitaへ転載するわけではありません。
大まかには、次のように役割を分けます。
note
主に、
- なぜ作ろうと思ったのか
- 世界観
- 制作の過程
- 設計を決めるまでの考え方
- 失敗や迷い
- ゲームクリエイターを目指す過程
を扱います。
Qiita
主に、
- React+TypeScriptでの実装
- データ設計
- 状態管理
- セーブ
- テスト
- 不具合
- 設計変更
- Web公開
などを扱います。
ただし、Qiitaの記事を理解するために必要な背景は、Qiita側でも説明します。
そのため、
noteを読んでいない方でも、途中の記事から読める
ことを基本方針にします。
逆に、技術だけでなく制作背景や世界観にも興味を持っていただけた場合は、noteも読んでいただければと思います。
14. この連載の書き方
このシリーズでは、次の方針で記事を書いていきます。
1記事1テーマ
一つの記事に多くの内容を詰め込みすぎないようにします。
できるだけ短く
第0回は連載全体の説明なので少し長めですが、第1回以降は、通勤や休憩時間にも読めるくらいの長さを基本にします。
用語は必要に応じて説明する
ゲーム固有の言葉や技術用語は、初めて出てくる場所で短く説明します。
完成形だけを書かない
実際に発生した問題や、最初の設計から変更した理由も扱います。
実装済みと予定を分ける
まだ作っていない機能を、すでに実装しているようには書きません。
実コードと説明用コードを分ける
理解しやすくするためにコードを簡略化する場合は、そのことを明記します。
15. 連載ロードマップ
現在は、次の章立てを考えています。
第0章 この連載について
今回の記事です。
連載の背景、目的、ゲーム概要、読者、ロードマップを紹介します。
第1章 小さなWeb RPGを作り始める
- なぜWebから始めたのか
- 最初から全部作らない
- 町1つ、街道1本、依頼1つのプロトタイプ
- Reactで画面とゲーム状態をどう考えるか
第2章 RPGをデータとして設計する
- 町をデータとして持つ
- TownとTownStateを分ける
- Reactコンポーネントを共通化する
- 依頼をTypeScriptの型で表す
- マスターデータとセーブデータを分ける
第3章 街道とイベントを設計する
- 一つだったイベントを増やす
- イベントキュー
- 必須イベント
- 条件付きイベント
- 重複防止
- 再読込後のイベント復元
第4章 戦闘・交渉・調査と状態管理
- 戦闘・交渉・調査を同じ仕組みで扱う
- 成功・部分成功・失敗
- 判定と結果
- 報酬
- 副作用
- 再挑戦
第5章 セーブと再開
- localStorage
- セーブデータ
- セーブスロット
- 現在地
- 街道途中の保存
- イベント途中の保存
- 再読込
- セーブ形式のバージョン
第6章 実際に起きた不具合と改善
- HPが0なのに進めてしまう
- 失敗したのに報酬が入る
- 再挑戦で前回の状態が残る
- 選択済み状態が復活する
- 内部IDが画面に出る
など、実際に開発中に起きた問題を扱います。
第7章 テストと品質管理
- Vitest
- 状態遷移のテスト
- 回帰テスト
- Playwright
- ブラウザ試験
などを扱う予定です。
第8章 Web公開・互換性・永続化
- セーブデータの互換性
- データ移行
- IndexedDB
- 実機試験
- Web公開
- リリース後の確認
など、Webアプリとして公開するための工程を扱う予定です。
このロードマップは固定ではありません。
実際の開発状況や、記事として切り出した方がよいテーマによって、章や記事を追加・変更する場合があります。
この第0回は、今後も連載全体の案内ページとして更新していく予定です。
この記事を最後まで読んでいただき、ありがとうございます。
「いいね」を押していただけるとうれしいです。これからの記事づくりの励みになります。
もし気に入っていただけましたら、フォローもよろしくお願いします。
16. 次回から、実際の開発へ
第0回では、この連載の背景と全体像を紹介しました。
次回から、実際のWeb RPG開発へ入ります。
第1回のテーマは、
「React+TypeScriptでWeb RPGを作っています――なぜWebから始めたのか」
です。
ゲームを作るならUnityなどのゲームエンジンを使う方法もあります。
それでも、なぜ最初の開発対象をWebアプリにしたのか。
実際に検討した順番から整理していきます。
この連載の現在位置
第0章 この連載について
- 第0回 連載の目的と開発ロードマップ ← 今回
次は、
第1章 小さなWeb RPGを作り始める
へ進みます。
次の記事
第1回 React+TypeScriptでWeb RPGを作っています――なぜWebから始めたのか
連載全体のロードマップ
- 第0章 この連載について ← 現在
- 第1章 小さなWeb RPGを作り始める
- 第2章 RPGをデータとして設計する
- 第3章 街道とイベントを設計する
- 第4章 戦闘・交渉・調査と状態管理
- 第5章 セーブと再開
- 第6章 実際に起きた不具合と改善
- 第7章 テストと品質管理
- 第8章 Web公開・互換性・永続化
関連する制作記録
このゲームの制作背景や試行錯誤は、note「4Hえんぴつ」でも記録しています。
4Hえんぴつ:
https://note.com/mild_bonobo5556
Qiitaとnoteでは、記事化する順序や切り口が異なります。
そのため、内容や連載順が完全には一致しない場合があります。