ゲームプランナーが『バグの少ないデータを効率的に作る』ための最低限の知識と考え方
ゲームって、「データ」をいっぱい作らなきゃいけないんですよ。
例えばドラクエのごとく「スライム」を登場させるにしても、
とか。
でも頭の中で考えるだけじゃゲームは生まれないので、ゲームに反映するためにちゃんと「データ」として持たなければいけません。こういう感じに。
問題はですね。
って話があるんですよ。
データ数が少ないならまだしも、コンシューマのゲームみたいにがっつり作りこむゲームとか、ソシャゲみたいな長期間の運営するゲームみたいのはモロに影響を受けます。
私は制作中のタイトルに途中から参加して、ゲームデザインをしたり引き継いだりもちょくちょくするんですが……この時もっとも恐れるのが、
ってパターン。それはもう
ってくらいには泣きそうになります。
まともなデータ構造だったらもっと簡単に分かりやすく把握しやすいデータをバグも少ない形で作れるのに。何が悲しくてこんなバグが出て当然の作り方をしなければならぬのか。
この記事はですね。そんな悲劇を少しでも止められたらいいなー……と思って書いていきます。
プランナー(ゲームデザイナー)さんの中には
という人もいるかもしれませんが……。
それで万事解決OKだったら私は苦労していません。残念ながら、他人に任せっきりにしていたら恐ろしく作りにくいデータ構造になってた、みたいなパターンはしばしば存在します。(もちろん、ちゃんとしたデータ構造を作ってくれるプログラマーさんはおられますし感謝感激雨あられですよ)
実際に大量のデータを設計・入力・運用していくのはプランナー側なので、少なくとも
というのが出来た方がいいじゃないかと思うのですよ。
データ作るの自分達だし。
とはいえ小難しい話をして「よく分かんねぇ!めんど!!」ってなるのもアレなので、この記事では初歩の初歩的な話、つまり
ってのを目標に、これから解説していこうかと思います。
◆前提:大量のデータを管理するには?
さて、しっかり説明する前にちょっと前提の話をします。
ゲームには大量のデータが必要になりますが、その大量のデータを管理したり、必要な時に必要な情報を取り出したりするのに便利なのが「データベース」です。
まぁこの記事では小難しい話をしないと誓っているので、正確な説明はヨソに任せるとして。ざっくり言うと、
こういうデータの表(テーブル)を目的毎にいっぱい作ってデータを管理しているってイメージを持ってもらえればそれでいいです。
(敵のデータ表、装備のデータ表とか)
ただ、各データの表(テーブル。家具じゃありませんよ?もう覚えましたね?)がバラバラにあっても機能しません。
例えばこういうデータのテーブルがあったとして、
「ゆうしゃが装備している武器の情報が欲しい」という場合は……
こんな感じで、「テーブル間で共通したデータ( ↑ の場合は「超強い剣」という名前)を基に必要な情報を引っ張ってくる」みたいなことをします。
まぁよくわかんなくても、何となく ↑ の画像がイメージできてればそれでいいです。
以上、前提の話オワリ。
さて、ここで重要なのが記事の冒頭に書いた
って話で、それをこれから解説していきます。
まぁ「俺はデータベース使わないから関係ねーや!!」って人もいるかもしれませんが、どういう方法をとるにしろ、これから話す考え方はデータ管理をする上で把握しておいて損はないと思いますよ、はい。
◆バグいっぱいになるデータ構造
さて、あなたはこれからとあるゲームのキャラクターデータを作ることになったとしましょう。RPGで考えてみましょうか。どんなデータが必要になりますかね?
まぁまず「名前」は必要そうですね。えぇ。
それから当然、「ステータス」も必要でしょう。
RPGなら属性もあるので、属性耐性も必要ですかね。キャラ毎に属性耐性をつけられるようにしていきます。
はい。これで、ゲームによっては既に地獄の一丁目に突入しています。このままデータをどんどん増やしていくと、死ぬほど作るのが大変でバグが出るようになってきます。
「何を言っているんだ?」と思われそうですが……ここはRPGにおける属性界の狂気、皆大好きポケモンのデータを例として扱ってみましょうか。
◇悪例をポケモンで例えると
えぇ~っと、ポケモンの属性(タイプ)ってどれくらいありましたっけ。
最新作のアルセウスで考えてみましょう。18タイプらしいです。
はい。だいぶ横に長くなりました。横長すぎてまともに画像が見えないですね。まぁ別に中身は重要じゃないので「なんかいっぱい入力するところが増えた」って雰囲気だけ感じ取ってください。
んでキャラクターデータなので、これを『全キャラクター分』作るのを考えてみましょうか。アルセウスのポケモン図鑑はNo.240までなので、240体分の属性耐性を設定する必要があります。
なので数字で考えると、単純に考えると属性耐性のデータだけで
のデータ入力が必要になるわけですよ。いっぱいですね。大変ですね。でもやるっきゃねぇですね。私はやりたくないです。
データがいっぱいということは、デバッグもいっぱいになります。
1キャラずつ全属性(タイプ)の攻撃を当てて仕様通りのダメージの通り方(こうかはばつぐんだ!とか)になるかどうかをチェックしないといけません。4320パターンのチェックが必要です。
まぁでも根性で頑張ればやれなくもない。
ただ超がんばってデバッグまで終わらせても、こんな話が飛んでくることもあります。
さぁて、まずは240種のキャラから「でんきタイプ」のキャラを探さないといけません。18キャラいるみたいなので彼らの属性耐性、つまり18データ分を変えます。
そして再度デバッグするわけですが、まぁ人間ミスをするものです。↓ みたいなこともちょくちょく起きます。
はい。非常に危険です。「完了だ!!」じゃねぇんですよ。
「変えたと思ったけど変わってなかった」っていうのは、単に入力していなかっただけならまだマシなんですが、最悪なのは「変えるべきじゃない別の所を変えていた」というパターンです。
例えば「いわタイプ」の設定の隣にある、「むしタイプ」への耐性を変えてしまっていたとか。No.27のサンダースをいわ弱点にするつもりが、No.26のシャワーズがいわ弱点になってたとか。
特に、既にデバッグ完了済みのところのデータが変わっていると、そのバグを抱え込んだままリリースされてしまうこともあって危険です。デバッグ完了しているデータをわざわざチェックしないし。
この辺を気にし始めると、「18キャラに対する1つの属性耐性の修正」でもデバッグは18データじゃ済まなくなってくるので、けっこう面倒な話になってきますね。
こんな感じで、
ってことが言えます。こわーい!さいてい!!
◇データの入力箇所は極力少なく
入力するデータが多ければ多いほどバグは増えるのであれば、逆に言えば入力するデータが少なければ少ないほどバグも手間も減っていきます。
今回のポケモンの例でいえば、
ってした方が効率的です。言い換えると
って話です。例えばこんな感じ。
キャラクターデータと属性耐性データを分離させて、「でんきタイプ」のキャラは皆「でんきタイプの属性耐性」で管理するよ!って形。
これなら属性耐性のデータはタイプ毎の18パターンを設定するだけで済みます。数にすると
なので、キャラ毎に設定していた4320に比べて「7.5%」しかありません。大幅削減ができました。(いやそれでも324って多いけどさ。ポケモン……)
更に言えば
みたいな仕様変更が起きた際も、変えるのは属性耐性データにある「でんきタイプのいわ耐性」1つで済みます。18個データを変更していたのが1つのデータ変更で済むのです。
バグの確認も全てのでんきタイプのキャラを試す必要はなく、1~2キャラを選んで確認すれば(ちゃんとそのキャラがでんきタイプって確認がとれているなら)十分です。
このようにまったく同じ仕様であっても、どうやってデータを入力して管理してくのか……というデータ構造によってそのゲームの作りやすさとバグの多さは大きく変わります。
ポケモンの属性耐性という極端な例を出しましたが、これはあらゆるデータに適用できる考え方です。
例えばRPGで「装備」を何十個、何百個と用意したけど、装備ごとに装備可能なキャラクターを毎回設定するべきなのか?とか。
属性耐性も「タイプ」みたいのが無くても、「(砂漠ステージの敵とかで)水属性のみ弱点の敵」が大量にいるなら、それは本当にキャラ毎に属性耐性を設定するべきなのか?とか。
要は
って話ですね。
さて、次は別の問題があるデータ構造の話。こういうデータ構造だと、システム的な都合でアイディアが活かせなくなりがちだよって話です。
◆アイディアを邪魔するデータ構造
けっこう初歩的な話なんですが、かなりデータの柔軟性を失うのが
みたいな作り方です。
問題点といえば……単純にこれ、3つ目の「落とすアイテム」を設定したくなったらどうするんですかね?列を追加して「落とすアイテム3」を設定すればいい?
ははは、御冗談を(真顔)
◇データ列を増やして何が悪い!!?
「悪いわボケェ!!!」と叫びたくもなりますが。
ちゃんと説明するとですね。これ、
と思ってもらっていいです。
200体分の敵データを作っていたなら、何も設定しないにしても200体に対して追加した分のデータを作らなければなりません。
もちろん、「何もない場合は空白にしておいてもらえれば無視するよ」っていう作り方で誤魔化すこともできますが……。
「入力できる場所がある」というだけでバグの温床になったりはします。入力するべき場所じゃないのに変なデータが入っちゃってたとか。
列が増えれば増える程1行のデータを把握するのが難しくなってくるので、危険度は増していきます。
そして何より、データを設定すると新しく追加する「落とすアイテム3」のデータを取得して引っ張ってくる処理がプログラム側にも必要になってくるので、プログラマーさんの手を煩わせることにもなります。
ただ3つのアイテムを落とさせたいだけなのにね。
そんな感じなので、列を増やして対応する方針だと例えば
ってのを成立させようと思うと全敵に対して「落とすアイテム1~100」まで設定しなければなりません。無駄に大変でデメリットが大きすぎるので、こういう話は絶対に成立しないです。
ちなみに長期間運営しているゲームなんかだとデータ数も千とか万とかいってもおかしくないですし、運営中にリスキーな行動で無駄バグを作るべきではないので、特にこの辺りの変更はかなり慎重になります。
つまり、
という何とも悲しい結末を、こういうデータの作り方は生み出してしまいます。必要な制限であれば良いのですが、大抵は窮屈なだけの無駄な制限です。
ではこれ、どうすればいいのでしょうか?
◇1 対 X の構造を作る
こうした
という場合は、「テーブル構造を分けて何個も設定できるようにする」と良いです。今回のエネミードロップの話だとこういう感じ。
※真面目に ↓ の画像を見るとデータの繋ぎ方が変なんですがその辺は後で解説します。
「スライム」に対しては2つの設定があるから2行のデータでそれを作る。「だいまおう」は1行、「Hなお姉さん♡」は3行。
ちなみにドロップが無い敵ならこのドロップアイテムテーブルにデータを作らない。
こうした「 1 対 X 」の構造、つまりデータ数に対して「列」ではなく「行」で対応すると、例え100種の「ドロップアイテムがある」みたいなものを作っても他のデータには影響を与えません。100行分のデータを頑張って作れば良いだけなので、プログラマーさんの手を煩わせることもない。
こうして余計なバグを増やさず、思いついたアイディアを邪魔せずデータが作れるわけです。
◇データ列を増やす対応でもいいやつ
さて、これまで「データ列を増やすんじゃねぇ!悪!!」的な論調で話しましたが。データ列を増やすでも問題ないかなーってパターンも、もちろんあります。
この辺は制作思想とかも入るので絶対の正解はないんですが、例えば状態異常耐性みたく
は1つのポイントですかね。例えば毒攻撃を受けた時にそのキャラの毒耐性の値を拾ってくるんだけど、その時に毒耐性が「存在していない」と判定できずにゲームの処理的にバグが出る……みたいなパターン。
ドロップアイテムのような構造で作れば「新しい状態異常を追加する時に列を増やさなくて済む」という話はありますが……。
長く運用するようなゲームだとIDがぐちゃぐちゃになりがちだったり、データを追加し忘れたキャラがいても気が付きにくかったりするので、こういう場合は列を追加していくような方針の方が良いかもしれません。
要は
みたいな話はあるのかなーって思います。
◆おまけ:どうやってテーブルを繋ぐ?
さて、これまでの説明で、個人的に「最低限は知っておいて欲しいこと」の説明は終わりです。
ただ「考え方」について分かりやすさ重視で説明していったので、例えばこの表だと敵の名前でテーブルを繋ぐような形になっていましたが……
実際には名前で繋ぐことはせず、基本的にテーブルとテーブルを繋ぐときは「ID」を使用することが多いです。
というのも名前で繋いじゃうとですね。例えば
って思った時に、「だいまおう」の名前が入っていたテーブルを全部変えなきゃいけないんですよ。そんで1個でも修正が漏れたらバグります。
更に言えば「大魔王」の名前をもつ敵が2データ分(例えば片方が影武者的な存在で、名前は同じにしているのが)いたら、片方のデータだけが欲しいのに2データ分引っ張っちゃいます。
なので、データを繋ぐものは基本的に
っていう性質の物でテーブルを繋ぎます。
そして、それを満たしているのが「ID」なわけです。識別用に割り振られた番号ってのは「名前」みたいにちょっとした都合で変えられたりしないので。
なので、例えばドロップアイテムのこのテーブルも実際には
こういう感じで管理されていきます。
また、IDは(私は)基本的に数字の連番(1~)で振ることが多いんですが、場合によっては数字に意味を持たせたり、テキストも組み合わせたりします。
例えば「その装備IDが武器・防具・装飾品のどれなのか」を一目で識別したいのなら、
てな感じですね。
数字に意味を持たせる場合は、↑の例なら「1~2桁は武器・3桁は防具・4桁は装飾品」でやってますけど、当然武器は100個以上は作らない前提の作りなので、その辺りはそのゲームの仕様と相談になります。
柔軟で分かりやすいのはテキストと組み合わせるパターンですが、「数字」ではなく「文字列」で扱う必要が出てくるので、この辺りはプログラマーさんと相談して方針を決めておいた方が良いです。
◆おまけ:「正規化」って何だ?
さて、ちゃんとデータ構造についてお勉強するぞ、と思った人がぶつかるのがこの「正規化」をしようねって話です。
なんかけっこう説明が分かりづらいんですよね。ただまぁ、ここまで記事を読んで内容を理解している人なら実用レベルでの把握は問題ないかなって思います。
なにせ今回の記事はこの「正規化」の話を分かりやすく分解して説明しているだけなので。正規化について超ざっくり説明すると
てな感じです。正規化が進めば進むほどテーブルの分割が進み、無駄なデータが無くなっていきます。
※ハイパーざっくりしたことしか言ってないので興味ある人はリンク先とか見てみてください。
ただし正規化はやればやるほどいい物でも無くて、あんまり分割しすぎるとデータを取ってくるのが大変になったりはします。
なので正規化だけなら第5正規化とかもありますが……だいたい第3正規化くらいまでやるといい的な事はよく言われていますね。
プロジェクトによって最適な形は違うので、チーム制作とかならプログラマさんと相談して最終的に決めればええんでないかとは思います。
◆まとめ
はい、今回の記事は以上になります。
今回の話をまとめると、
ですかね。
よろしくないデータ構造は、生産性も落とすしバグも増やすので
とすら言えます。
責任もって自分で作りきるならいいんですけども。だいたい泣きを見るのはもう引き返せない段階で呼ばれた後任の人間っていう……。
まだ変更できる段階ならいいんですけども。
……とまぁ偉そうなことを書いてますが、ぶっちゃけ私もこの辺りに詳しいわけでもなくてですね。しがないゲームデザイナーですし。
見る人が見たら「いや、ここはそうじゃねぇだろ!」とか「こうした方がもっと効率がいいだろ!!」とかあると思うので、そういう人はぜひ記事を書いてください。情報がたらぬぇ。
◆宣伝
ちゃんとデータ構造を考えながらゲームを作っていて、そのゲームが現在Steamでアーリーアクセス版をリリースしています。
データ的なバグは少ない方だと思いますよ。誤字はあるけども!!!
あと面白いゲームを作るためのゲームデザインの話を色々書いてたり、
今回の記事と似たタイプのものだと、こういう記事とか書いてます。
興味ある人は読んでみてくださいなー。
サポート(投げ銭、金銭支援)歓迎です。 頂いたお金はゲームの開発費に使用させていただきます。 ↓ 支援が多いと私のゲームのイラスト枚数が増えたりオリジナルの曲が組み込まれたりします。美味しいお肉を食べに行ったりはしません。