RPGの作り方 (マップ・イベント編)

この記事ではRPGの作り方を解説します。

なおRPGすべてを網羅するのは大変なので、この記事ではRPGの核となる「マップとイベント」のシステムについて解説します。

「マップとイベント」のシステムを作る

「マップとイベント」のシステム構築に必要な要素は以下のとおりです。

  1. マップデータの作成、読み込みと配置
  2. マップをキャラクターが移動できるようにする(別のマップへの移動も含む)
  3. オブジェクトを調べられるようにする (またはイベントの発生)
  4. 調べると会話メッセージが表示される
  5. イベントフラグとイベント変数の管理
  6. アイテムの管理(インベントリ)

1. マップデータの作成、読み込みと配置

マップデータの作成は、ゲームエンジンがサポートしているエディタがあればそれを使うのが早いです。Unityの場合はアセットを使う方が効率化できるようです。

もし開発環境にマップエディタがない場合は「Tiled Map Editor」を使うのが良いと思います。

2Dゲームを作るのであれば、このエディタがあればできないことはないと思います。

Tiled Map Editorについては以下の記事で解説しています。

Tiled Map Editorのデータは XML形式で、たいていのプログラム言語のライブラリにはXMLのパーサーが用意されているので読み込みは難しくないです。もしXMLのパーサーが用意されていなくても、Tiled Map Editorには JSONCSVなど様々なテキストフォーマットで出力する機能が用意されています。

マップのデータ構造

RPGに必要なマップのデータ構造は以下の3つです。

マップのデータ構造

 

 

まず地形の見た目となる情報を配置します。次にプレイヤーが移動できる場所「地形コリジョン」を定義します。そしてさらに、会話イベントや調べられるポイントとなる「イベント配置情報」を持ちます。

この3つのデータがRPGに最低限必要なマップ情報となります。

なお、Tiled Map Editorでこのデータ構造を定義するとこのようなレイヤー構造になると思います。

2.マップをキャラクターが移動できるようにする (マップとの当たり判定)

アクションゲームが作れればこのステップは難しくないと思います。

マップとの当たり判定について通常はゲームエンジンがサポートしているのですが、もし自作しなければならない場合には以下のページが参考になると思います。

2Dでの当たり判定は、通常XY軸を分離して衝突応答を行えば、正しく押し返しができるようになります。RPGツクールのようなマス目移動であれば、移動先に障害物があるかどうかを判定すれば実装できます。

3.イベント発生条件の指定(オブジェクトを調べられるようにするなど)

アクションイベントと自動イベント

ここで実装するのは、例えば落ちているアイテムを調べる処理です。

RPGツクールのように、マス目状にマップが区切られている場合は、4方向のどちらから調べられるのか、という情報が必要です。

またはキャラクターに話しかけるイベントです。

なお、この2つは「ユーザーがアクションを起こす (決定ボタンを押す)」にことにより発生するイベントです。

これに対して、プレイヤーが特定のポイントに移動したことで自動的に発生するイベントがあります。これを「自動イベント」と呼びます。

イベントの発生条件には大きく分けてこの2種類があることを知っておくと、イベントの仕組みが作りやすくなります。

  • アクションイベント: プレイヤーが行動を起こすことで発生するイベント (発生方向がある)
  • 自動イベント:プレイヤーが特定のポイントに移動したら自動で発生するイベント (位置で発生)

イベント発生条件

イベントについてもう一つ考える必要があるのが、発生条件です。例えば「棚からものが落ちてくる」というイベントは通常1回のみとなります。これを制御するのが「イベントフラグ」という考え方です。

イベントフラグは「ON」「OFF」の2つの値のみを持ちます。いわゆる「フラグが立つ」というのはイベントフラグが ON になった状態です。

イベントフラグは以下のルールで運用すると、バグの少ないRPGを作ることができます。

  • ゲーム開始時はすべて「OFF」にする
  • 一度「ON」にしたら、基本的には「OFF」にしない(※使いまわし禁止)
  • グローバルフラグとローカルフラグを用意する
  • イベント開始フラグとイベント終了フラグを用意する

まずゲーム開始時にはイベントフラグはすべて「OFF」の状態で開始します。そして、イベントフラグを「ON」にしたら基本的には「OFF」にしない方が良いです。

なぜかというと、いったん「ON」にしたイベントフラグを「OFF」に戻すということは、そのイベントフラグをまたどこかで「ON」にするからです。これはイベントフラグが複数の意味で使用されることとなり、イベントフラグの状態遷移が複雑になるためです。ですので、例えば「棚からものが落ちてきた」というフラグであれば、それ以外の用途としてフラグを使用しない方が良い、ということになります。(※ただし、棚から物が落ちたことで新しいアイテムが手に入るフラグとして使う……など直列的なイベントの発生条件として使用する場合は問題ありません)

次に、「グローバルフラグ」と「ローカルフラグ」を用意することです。

  • グローバルフラグ:ゲーム内のどこからでも参照できるフラグ
  • ローカルフラグ:そのイベント内からのみ参照できるフラグ

例えば、登場人物Aとの会話の進行(話しかけるごとにメッセージが変化するなど)をグローバルフラグで制御すると、そのキャラクターとの会話だけでイベントフラグを消費してしまいます。そのため、そのイベント(キャラクター)のみが参照できるローカルフラグを使えるようにすると、管理がシンプルになります。

またイベントフラグは「ON」「OFF」の2値ですが、イベント変数を用意しておくとさらに幅広い制御が可能となります

  • イベント変数:イベント制御に使える整数値。4byte整数値(-2147483648〜2147483647)が使えれば基本的に問題ない

例えばキャラクターとの会話の進行のようなものは、フラグよりも整数値で管理すれば、状態が把握しやすくなります。

  • 会話進行度0:話しかけても無言
  • 会話進行度1:少しだけ情報をくれる
  • 会話進行度2:相談ごとを持ちかけられる(サブクエストの発生など)
  • 会話進行度3:フレンドリーに会話してくれる

また数値を扱えるようにすることで、謎解きで入力されたダイヤル番号をイベント変数に保存して、別の場所のイベントで正解判定を行うといった応用もやりやすいです。

 

イベント変数も、イベントフラグと同様にそのイベントからのみ参照できる「ローカルイベント変数」、ゲーム全体で扱うことができる「グローバルイベント変数」を用意しておくと良いでしょう。

まとめ:イベントに必要な情報の定義

よって1つのイベントには以下の情報が必要となります。

  • イベントID:発生するイベントID、もしくはイベント名(スクリプトとの紐付けに使う)
  • イベントコリジョンコリジョンの座標とサイズ。RPGツクールのようなマス目の場合は方向
  • 発生条件 > イベント開始フラグ:イベントが開始可能となるフラグ
  • 発生条件 > イベント終了フラグ:イベントが発生しなくなるフラグ
  • 発生種別:「アクションイベントまたは自動イベント」などのイベントが発生する種類

この情報を定義したテーブルの実装例を記載しておきます。

イベントID 種別 座標(X) 座標(Y) 方向 開始フラグ 終了フラグ コメント
NPC_001 会話 10 5 全て なし なし NPCの001に話しかけたときに発生するイベント
TRASURE_001 調べる 8 22 全て なし LF_01 宝箱イベント。開けると “LF_01” がONになる
AUTO_NPC_002 自動 5 7 全て FLG_ITEM_001 LF_01 宝箱を開けて得られるITEM_001がONになると発生するイベント
NPC_003 調べる 21 25 なし LF_01 木の後ろに隠れているNPCとのイベント
イベント発生条件の実装例

"NPC_001" は、開始フラグと終了フラグが指定されていませんが、このイベントはいつでも発生するイベントとなります。それに対して "TRASURE_001" には終了フラグが設定されており、宝箱を開けることでこのイベントは存在しなくなります。正確には宝箱を開けたという見た目の変化に対応する設定が必要となるかもしれませんが今回は省略しています。

"AUTO_NPC_002" は、宝箱を開けたことにより得られたアイテムのフラグが発生条件となります。

なお、Tiled Map Editor で「オブジェクトレイヤー」を使うと、"カスタムプロパティ" で細かくイベントの発生条件を指定できるので、Tiled Map Editorを使う場合はこの機能を使って良いかもしれません。

4.イベントスクリプトの実装

会話メッセージを表示したり、キャラクター画像(立ち絵など)の表示、イベントフラグの制御などには、専用のスクリプトを用意した方が良いです。

とは言え、独自のスクリプト言語を実装するのは大変なので、既存のゲーム用のスクリプト言語を導入するのが良いと思います。

C# が使えれば、Miniscriptというのが評判が良いようです。

上記は英語ページですが、日本語で組み込み方法が紹介されているのでこちらを参考にするのが良いかもしれません。

もしくは「Lua」を組み込んでみても良いかもしれません。

補足として、イベントの呼び出しは「名前(関数名)」指定で呼び出せるようにしておくと、スクリプトの記述がやりやすいと思います。

スクリプト言語を自作する場合

もし、MiniscriptやLuaの組み込みができない場合は、スクリプト言語を自作する必要があります。

自作……となると「すごい大変そう」という印象を受けてしまうかもしれませんが、どこまで作り込むかで実装コストは変わります。

  • "演算子" や "条件分岐"、 "関数呼び出し" などの「制御構造」
  • 定数やイベントフラグ、イベント変数など、ゲームと連動するためのデータの扱い
  • ゲームから指定の関数を呼び出す機能
  • ローカル変数の定義
  • データ構造の利用(配列やリスト、ハッシュなど)
  • データ構造の宣言(クラス宣言など)

MiniscriptやLuaではこれらに相当する機能が実装されており、とても多機能となっています。ただこれをいきなり実装するのは大変です。

そこで自作する場合、まず以下のように仕様を限定すると難しくないと思います。

  • 上から下に実行するだけ(IF文や関数呼び出しなどの制御構造はなし)
  • プログラムに直接テーブルを記述する(外部テキストにすらしない)
  • 使用可能なイベントフラグ (変数) は 0番から100番 までの固定長にする

例えばC++による実装例です。

// コマンドオブジェクト.
struct COMMAND {
  int Code; // 命令コード.
  int Params[8]; // パラメータ。最大8個まで.
};
 
// 命令コード.
enum eCode {
  eCode_Message, // テキストメッセージ表示.
  eCode_Bg,      // 背景表示.
  eCode_BgOff,  // 背景非表示.
  eCode_Wait,    // 一時停止.
  eCode_End,     // 終了.
};
 
// 実行コードテーブル.
static COMMAND_OBJ s_CodeList[] = {
  {eCode_Bg,      {1}},  // 背景画像 "1" を表示する.
  {eCode_Message, {3}},  // テキストID "3" を表示する.
  {eCode_Wait,    {30}}, // 30フレーム待つ.
  {eCode_BgOff,   {}},   // 背景消去.
  {eCode_End,     {}},   // 終了.
};

もしデータを外部化したい場合は、以下のようなテキストに置き換えても良いかと思います。

BG,1     // 背景画像 "1" を表示する.
MSG,3    // テキストID "3" を表示する.
WAIT,30  // 30フレーム待つ.
BG_ERASE // 背景消去.
END      // 終了.

1行が1つの命令となり、カンマ区切りでパラメータを指定します。会話で分岐が発生しない場合はこれだけで実装可能です。

「こんな単純なスクリプト言語使い物にならないのでは……?」と疑問に思うかもしれませんが、イベント中に分岐が発生しない場合にはこれで問題ありません。RPGだとやはり会話で分岐を発生させたくなるかもしれませんが、それについては「イベントの発生条件」に細かく条件を指定することである程度の制御は可能です。

ですが「やはりちゃんとしたスクリプト言語が欲しい……」となった場合は、本格的なスクリプト言語を作る本が参考になるかと思います。

こういった本では、「字句解析」「構文解析」といったスクリプト言語を作る上での必要な知識が書かれています。字句解析と構文解析について簡単に説明します。

例えば以下の独自スクリプトがあるとします。

if(a == 0) {
  print("hello");
}

これを字句解析すると、以下のようにスクリプトが分解されます。

 キーワード 説明
if ifキーワード
( 式のかたまり開始
a 変数 "a"
== 比較演算子
0 数値 "0"
) 式のかたまり終了
{ ブロック開始
print print関数キーワード
( 関数パラメータ開始
"hello" 文字列 "hello"
) 関数パラメータ終了
} ブロック終了

プログラムにおける最低銀の意味を持った単語に分解すること「字句解析」と呼ばれます。そして次の構文解析でこの字句を意味のある階層構造にします。

構文解析とは、以下のような構文木を作ることです。

構文木とは、文字通りプログラム構文を木(ツリー構造)にデータ化したものとなります。

この構文木を上からたどり、下から評価してきます。

そして評価結果が「真」であれば、IF文のブロックを処理していきます。

以上、字句解析と構文解析の処理についてざっくり説明しましたが、考慮すべきことがたくさんあります。

  • 演算子の評価方法(左辺・右辺の考え方)
  • 変数 "a" の評価方法
  • 評価結果の保持方法
  • print命令の処理方法
  • IF文が「偽」だった場合の処理
  • そもそも字句解析をどうやってやるのか。構文木をどうやって作るのか……?

このあたりは大変ですが、本やネット上の資料を調べて少しずつ実装していくのが良いと思います。

まずは、四則演算などの式の評価や、変数の実装から始めてみても良いかもしれません。

5. イベントフラグとイベント変数の管理

これについてはすでに紹介したので、省略します。

6. アイテムの管理 (インベントリ)

RPGのアイテムには大きく分けて、以下の3種類あります。

  • 消耗品:使うとなくなるアイテム
  • 装備品:装備してキャラクターを強化するアイテム
  • 貴重品:イベント専用アイテム

これらを明確に分ける必要がある場合とそうでないときがありますが、通常のRPGは明確に分けます。理由としては、すべてを同じアイテムとして扱ってしまうと、ユーザーが使いたいアイテムが見つかりにくくなるためです。そのためインベントリのカテゴリをそれぞれで分けて管理できるようにしたほうが親切となります。

ただローグライクの場合はインベントリ上、消耗品と装備品を一緒に入れることもあります。

参考資料として、昔ローグライクを作成したときのアイテムテーブルの実装例です。

消耗品アイテムテーブル

  • id: アイテムID
  • type: アイテム種別 (Food:食べ物。Potion:薬。Scroll:巻物。Wand:杖。Orb:オーブ)
  • name: アイテム名
  • hp: HP回復量
  • food: 満腹度回復量
  • atk: 投げたときの攻撃力
  • range: 効果範囲 (all:全体攻撃)
  • extra: 状態異常
  • extval: 状態異常の効力
  • buy: 販売価格
  • sell: 売却価格
  • sort: ソートキー
  • detail: 説明文
  • log: ログに含めるかどうか
id type name hp food atk range extra extval buy sell sort log
int str str int int int str str int int int int int
FOOD1 Food リンゴ   50 2       100 35 1 1
FOOD2 Food 大きなリンゴ   100 4       300 105 2 1
FOOD3 Food 固いリンゴ   25 8       50 18 3 1
FOOD4 Food 毒リンゴ   25 2   poison   600 210 4 1
POTION1 Potion 回復薬10 10 10         20 7 200 1
POTION2 Potion 回復薬20 20 10         50 18 201 1
POTION3 Potion 回復薬30 30 10         100 35 202 1
POTION4 Potion 回復薬40 40 10         250 88 203 1
POTION5 Potion 回復薬50 50 10         500 175 204 1
POTION6 Potion 回復薬60 60 10         750 263 205 1
POTION7 Potion 回復薬70 70 10         1000 350 206 1
POTION8 Potion 回復薬80 80 10         1200 420 207 1
POTION9 Potion 回復薬90 90 10         1400 490 208 1
POTION10 Potion 回復薬100 100 10         1600 560 209 1
POTION11 Potion 回復薬110 110 10         1800 630 210 1
POTION12 Potion 回復薬120 120 10         2000 700 211 1
POTION13 Potion 回復薬130 130 10         2200 770 212 1
POTION14 Potion 回復薬140 140 10         2400 840 213 1
POTION15 Potion 回復薬150 150 10         2600 910 214 1
POTION16 Potion 回復薬160 160 10         2800 980 215 1
POTION17 Potion 命の薬   10     hpmax 3 500 175 216 1
POTION18 Potion 胃拡張の薬   10     food 20 300 105 217 1
POTION19 Potion 力の薬   10     str 1 500 175 218 1
POTION20 Potion 毒薬   10     poison   500 175 219 1
POTION21 Potion 眠り薬   10     sleep   300 105 220 1
POTION22 Potion しびれ薬   10     paralysis   500 175 221 1
POTION23 Potion 混乱の薬   10     confusion   300 105 222 1
POTION24 Potion 怒りの薬   10     anger   1000 350 223 1
POTION25 Potion 元気になる薬   10     powerful   500 175 224 1
POTION26 Potion いやしの薬   10     recover   300 105 225 1
POTION27 Potion 封印の薬   10     closed   300 105 226 1
POTION28 Potion ワープの薬   10     warp   500 175 227 1
SCROLL1 Scroll 魔弾の巻物Lv1     10 all     500 175 232 1
SCROLL2 Scroll 魔弾の巻物Lv2     30 all     1500 525 233 1
SCROLL3 Scroll 魔弾の巻物Lv3     50 all     5000 1750 234 1
SCROLL4 Scroll 袋拡大の巻物Lv1         itemadd 1 2000 700 235 1
SCROLL5 Scroll 袋拡大の巻物Lv2         itemadd 2 3000 1050 236 1
SCROLL6 Scroll 武器強化の巻物         weapon 1 1000 350 237 1
SCROLL7 Scroll 防具強化の巻物         armor 1 1000 350 238 1
SCROLL8 Scroll 麻痺の巻物     1   paralysis   1000 350 239 1
SCROLL9 Scroll 眠りの巻物     1   sleep   1000 350 240 1
SCROLL10 Scroll 混乱の巻物     1   confusion   1000 350 241 1
SCROLL11 Scroll 武器合成の巻物         weponadd   1500 525 242  
SCROLL12 Scroll 防具合成の巻物         armoradd   1500 525 243  
SCROLL13 Scroll 魔除けの巻物         nightmare 100 3000 1050 244 1
WAND1 Wand 毒の杖         poison   3000 1050 248 1
WAND2 Wand 眠りの杖         sleep   900 315 249 1
WAND3 Wand 麻痺の杖         paralysis   2000 700 250 1
WAND4 Wand 混乱の杖         confusion   900 315 251 1
WAND5 Wand 怒りの杖         anger   600 210 252  
WAND6 Wand 火の杖     0       300 105 253  
WAND7 Wand 封印の杖         closed   900 315 254 1
WAND8 Wand ワープの杖         warp   1500 525 255 1
WAND9 Wand チェンジの杖         change   900 315 256 1
WAND10 Wand HP交換の杖         hpswap   1500 525 257 1
WAND11 Wand 炎の杖     10       900 315 258 1
ORB1 Orb 赤ネコのオーブ             3 1 264 1
ORB2 Orb 青ネコのオーブ             3 1 265 1
ORB3 Orb 白ネコのオーブ             3 1 266 1
ORB4 Orb 緑ネコのオーブ             3 1 267 1

装備品テーブル

  • id: アイテムID
  • type: アイテム種別 (Weapon:武器。Armor:鎧。Ring:指輪
  • atk: 攻撃力
  • def: 防御力
  • attr: 属性
  • extra: 特殊効果 (drill:壁を壊す。counter:反撃可能)
  • ext_val: 特殊効果の威力
  • food: 満腹度の減少補正
  • buy: 購入価格
  • sell: 売却価格
  • sort: ソートキー
  • detail: 説明文
  • log: ログに含めるかどうか
id type name atk def attr extra ext_val food buy sell sort log
int str str int int int str int int int int int int
WEAPON1 Weapon 木の棒 2           50 18 100 1
WEAPON2 Weapon 木刀 4           100 35 101 1
WEAPON3 Weapon ダガー 6           250 88 102 1
WEAPON4 Weapon レイピア 10           700 245 103 1
WEAPON5 Weapon 三日月刀 14           1000 350 104 1
WEAPON6 Weapon 妖刀ムラマサ 16           1500 525 105 1
WEAPON7 Weapon 聖騎士の剣 20           3000 1050 106 1
WEAPON8 Weapon ドリル 5     drill 100   500 175 107 1
ARMOR1 Armor ローブ   2       1 50 18 120 1
ARMOR2 Armor 毛皮の鎧   4       1 100 35 121 1
ARMOR3 Armor 鎖かたびら   6       1 250 88 122 1
ARMOR4 Armor エルフの鎧   10       1 700 245 123 1
ARMOR5 Armor メタルアーマー   14       1 1000 350 124 1
ARMOR6 Armor 銀のジャケット   16       1 1500 525 125 1
ARMOR7 Armor プラチナメイル   20       1 3000 1050 126 1
ARMOR8 Armor 反撃の鎧   10   counter   1 2000 700 127 1
RING1 Ring 力の指輪 1           300 105 140 1
RING2 Ring 守りの指輪   1         300 105 141 1
RING3 Ring HP増加の指輪       hpmax 10   300 105 142 1
RING4 Ring 眠りよけの指輪       sleep     2000 700 143 1
RING5 Ring 混乱よけの指輪       confusion     2000 700 144 1
RING6 Ring 通過の指輪       passage     2500 875 145 1
RING7 Ring 力の指輪+1 2           500 175 146 1
RING8 Ring 力の指輪+2 3           1000 350 147 1
RING9 Ring 力の指輪+3 4           2500 875 148 1
RING10 Ring 力の指輪+4 5           5000 1750 149 1
RING11 Ring 守りの指輪+1   2         500 175 150 1
RING12 Ring 守りの指輪+2   3         1000 350 151 1
RING13 Ring 守りの指輪+3   4         2500 875 152 1
RING14 Ring 守りの指輪+4   5         5000 1750 153 1
RING15 Ring HP増加の指輪+1       hpmax 20   500 175 154 1
RING16 Ring HP増加の指輪+2       hpmax 30   1000 350 155 1
RING17 Ring HP増加の指輪+3       hpmax 40   2500 875 156 1
RING18 Ring HP増加の指輪+4       hpmax 50   5000 1750 157 1
RING19 Ring プラチナリング 1 1   hpmax 10   1500 525 158 1
RING20 Ring ドラゴンの指輪 3     hpmax 30   5000 1750 159 1

YouTube

今回の記事を動画にしました