技教えシステム_解説記事1
技教えシステム_解説記事1
解説記事1:二進数、それはゲームの選択肢を増やす最良の手段
ゲームには選択肢が必要不可欠である
はじめまして、空気です。
突然ですが皆さん、ビットゲームメーカーで作品を作っているとき、こんな願望を抱いたことはないでしょうか?
「教え技機能をつけてえ!」
教え技、すなわち、キャラがレベルアップで覚える技のカテゴリから離れたプレイヤーのエディット要素。
ゲームというものはクリアというゴールを目指し、その達成過程を楽しむ娯楽です。
でも、目標のためにひた走ることは、それ単体ではなんの味気もなく面白味もない。
日本に住み、学生時代に受験勉強という退屈なものに青春時代を費やした皆さんならこのことは身に染みて感じられるでしょう。
受験はいたってシンプルです。合格というゴールに到達するためにあらかじめ決められた学習内容をただひたすらに反復する。
同じ目標達成のために走る行為でも、これほど退屈なことはありません。
受験もゲームも、どちらも目標達成のために目の前の課題に取り組む作業であるという点では、両者は共通しています。
ですが、この二者には決定的な違いがある。それは、かたや受験はつまらないものなのに、かたやゲームは楽しいものである、ということ。
では、この違いを決定づける最大要素とはなにか。
それこそ、「プレイヤーの選択肢」なのです。
ゲームをクリアするために、プレイヤーは様々な選択をすることが出来る。
どんな技で敵を倒すか、何を装備するのか、どれくらいレベルを上げるのか、誰を仲間にするのか…
選択肢はプレイヤーの数だけ千差万別です。
そして、その千差万別の選択肢のすべてがゲームをクリアするための正解である。
すなわち、ゲームをクリアする過程の体験はプレイヤーが自らの手で自分だけの目標達成の物語を紡ぐことに他ならないのです。
この体験は画一的な過程を経たゴールしかありえない受験勉強では、決して得られない体験といって差し支えないでしょう。
ゲームには「選択肢の自由」が必要不可欠なのです。
そして、教え技というものはプレイヤーを技選択の制限から解き放ち、自由な選択肢を与えるもっともお手軽にして、もっとも強力な手段なのです。
教え技システムはデータがでかい
さて、ここまではゲームにおける教え技がいかに優秀な要素かを述べてきました。
ここまでお読みいただいた読者の皆様は、教え技がプレイヤーに対しいかに効果的に作用するかをご理解いただけたことでしょう。
では、ここでそんな読者の皆様に質問です。
教え技を用意する時、ゲームの側ではどれくらいのデータを管理する必要があるでしょうか。
…ちょっと質問が大雑把すぎましたね。
もう少し具体的な事例を考えてみましょう。
例えば、あなたはプレイアブルキャラが12人いるゲームを作っているとしましょう。
そして、プレイヤーに「選択肢の自由」を与えるために、12個の教え技を設定するとしましょう。
しかし、当然12人の全員が全員、12個の教え技をすべて習得可能にしてしまうわけにはいきません。
あれほど選択肢の自由だのなんだのと言っていたお前が急に何を言い出すんだといいたくなる気持ちは分からなくもないですが、キャラクターには個性というものが一定必要なのです。
これについて議論しだすと話が脱線するので、細かい話は割愛しますが、とりあえず今はそういうものだと一旦飲み込んでください。
さて、話を戻します。
12人のキャラが、全員が全員12個の教え技を覚えられるわけにはいかない。
これはつまり12人のキャラそれぞれに習得可能な教え技に制限を設けなければならないということです。
どのキャラも12個の教え技に対し、覚えられる、覚えられないのいずれかをデータとして記録している必要があるということです。
そして、この12個の教え技に対する習得可否のデータは、当然12人分が必要になります。
さて、だいぶ回り道になりましたが、ここで冒頭の質問を内容を多少改めた上でもう一度問いましょう。
12人のキャラが12個の教え技を持つとき、その習得可否データは合計でいくつになるでしょうか。
答えは…12×12 = 144
144!!
そうです。察しのいい方は既にお気づきかもしれませんが、この144というやたらめったらでかい数字こそが教え技システム実装に対し大きな弊害となる数値なのです。
さて、144のデータ入力を終えたで。ほんで、残ってるデータ枠は…112!?うせやろ!?
この記事をお読みの皆様は「ビットゲームメーカー」なる融通の利かないツールでゲームを作り続けている酔狂者だと存じております。
そして、そんなあなた方なら、先ほど述べた144という数値がいかに脅威的かはすぐにご理解いただけるでしょう。
教え技が習得可能かどうかは「真」「偽」という二種の「状態」で分別できることは想像に難くありません。
そして、ビットゲームメーカーで「状態」というものを保持する方法は主に二つあります。
一つ目が「フラグ」、もう一つが「変数」です。
「フラグ」がオンオフの切り替えによる2種判断。「変数」が数字による大量パターンの判断。
二種の「状態」を管理する要素をざっくり説明するとこのように言えるでしょう。
教え技の習得可否という「状態」は、「真」「偽」の二種で表すことができるという性質上、「フラグ」による管理が適切なように思われます。
では、まずは「フラグ」で管理する方法を考えてみましょう。
144個の真偽データを144個のフラグにそれぞれ当てはめていきます。
キャラ1は…
技1:覚える、技2:覚える、技3:覚えない、技4:覚える、技5:覚えない…
………
……
…
ふう、ようやく打ち終えたで。全部でフラグ144個分。シンプルにきつい作業やったわ。
さて、それはそうと144ってかなりの数のフラグを使ってもうたなあ。
他の要素のためにも枠は残しとかなあかんのやが…
どれどれ、残ってるフラグ枠は…112?
…112!?うせやろ!?半分も残ってないやんけ!!!!
フラグによる管理はとにかく枠を壟断する
144 + 112 = 256
256、これが一体何を意味する数字か、皆さまはお分かりでしょうか。
256、この数字はビットゲームメーカーで1ゲーム作品内で使える「フラグ」の数の上限値です。
そして先ほど述べた様に、12人のキャラと12の教え技を管理するために必要な「フラグ」枠は144。
教え技システムを実装しようとするだけで、なんと全フラグの半分以上の枠を使うことになってしまうのです。
もし読者の中に切れ味鋭い頭をもつ方がいらっしゃれば、習得可能不可能全部を記録しなくても覚えるほうか覚えないほうかどちらかだけを記録したら「フラグ」枠は半分くらいで済むじゃない、という天才的アイデアを思い浮かべているかもしれません。
しかし、ビットゲームメーカーではそれが不可能なのです。
なぜなら、ビットゲームメーカーではデータ探索のキーを複数指定できないから。
習得可否データは「キャラクター」と「技」の二つの条件をキーとして、その習得可否を「真」もしくは「偽」で返します。
二種類のキーから真偽探索をする場合は、例えば「真」が答えになるキーの組だけ記録しておいたとすると、探索時は一致するキーの組が存在することを確認すればそれで問題ありません。
データシートやjsonファイルなら複数キーによる探索は容易に行えるでしょう。
しかし我々が取り扱うのはビトゲです。
ビトゲではキーとして取り扱えるのはフラグの連番だけ。
「キャラクター」と「技」の組み合わせすべてに連番を割り当て、各連番に「真」「偽」の値を格納しておく方法をとらざるを得ないのです。
つまり、半分以上の「フラグ」枠を食いつぶすことが避けられないのです。
そして、「フラグ」というものはもちろん技教えシステムの為だけのものではありません。
ゲーム本編内の様々なシーンで用いる、ゲーム設計の根幹部分すらを支えるものです。
どのような形式の作品を作っているかにもよりますが、「フラグ」の使用数が100を超えるのは日常茶飯事、作りこまれた作品であれば200を超過するものもあるでしょう。
そんななかで貴重な「フラグ」枠をどちらかというとサブ要素にあたる教え技システムで144も使うのはあまりにも本筋を見失っているとしか言えません。
せや!二進数を使えばええんや!!
教え技システムを実装したい。でも、そんな大量の枠を裂くわけにはいかない。
我々は今、二つの目論見が衝突する問題に直面しています。
この問題をどうやって解決したものか…
問題を一度俯瞰的に考えるため、一つ表を作ってみました。
下の表をご覧ください。これは「はかいこうせん」という技を12のキャラクターが習得可能かどうかを〇と罰で示したものです。
画像の下に〇のついたキャラクターが「はかいこうせん」を習得でき、×のついたキャラクターが「はかいこうせん」を習得できないものとします。
「フラグ」を利用して「はかいこうせん」の習得可否を保存する場合は、表に従い12個の連番フラグにオンオフを入れるわけですね。
ただ一応きっちり付け加えておくと表中の真偽値だけで終わりではありません。教え技は12個を想定しているわけですから、表と同じ○×が残り11パターン存在しそれらについても12個の連番フラグで記録することが必要になります。
とんでもなく気の長い作業です。
ところで、この表、実は〇×から表記方法を変えて表してみるとどうみえるでしょうか。
…そうですね。たとえば〇を1に、×を0に一旦変えてみましょう。変えたあとの表がこちらです。
ほーん、あれ、これ、なんかどっかで見たことあるな。なんやっけ、1と0だけが並ぶ数値表記方法……あ、思い出したわ。確か二進数とかいうやつや。
……ん?
…せや!!二進数を使えばええんや!!!!
二進数を使ってデータ領域を超圧縮
さて、ようやく本題にたどり着きました。
ここからが本記事における、空気が最も言いたかった部分です。
それはずばり、二進数をつかう
これが本記事における最大の主張です。
え?二進数を使うとかいうけど、これをどうやって記録するんや?結局0と1の二種判別を12個並べるから必要な枠の量は変わらんのちゃうんけ?
その疑問もごもっともです。
ですが、一つ考えてみてください。二進数は数値です。そう、数値。
たとえば先ほど表で見せた数値は011001110011
これを十進数に直してみましょう。
するとその値は1024+512+64+32+16+2+1 = 1851
ふふ、どうです?この値を見てさすがにそろそろみなさんも察し始めたことでしょう。
1851という数値は「フラグ」ではない、もう一つの記録要素を使えば容易に記録できる…
そうです。12枠も「フラグ」を食っていた習得可否データは、二進数形式で記録することでたった一つの変数に統合することが出来るのです!
まさに超圧縮!!
これこそ、私が二進数形式でデータを保存しようと試みた動機なのです!
結びに
さて、本記事では私がなぜわざわざ二進数でデータを記録する方式を採用したのか、その大雑把な経緯をご紹介しました。
次の記事では二進数形式でデータを保存することのメリットについて、具体例を交えながらより掘り下げた説明をしていきたいと思います。
長文になりましたが、ここまでご精読いただきありがとうございました。
技教えシステム_解説記事2
技教えシステム_解説記事2
解説記事2:二進数を採用する理由
どうも、空気です。
この記事では前回に引き続き、二進数による教え技システムについて解説していきたいと思います。
前回の記事をまだ読んでいないよって方は、先にそちらから読んでいただけると、本記事内で説明することについてより一層の理解をしていただけることと存じます。
それでは、始めます。
はじめに
さて、前回の記事では、データの管理について2進数を利用することで使用するデータ枠の数を大幅に減らせるということを説明しました。
ですが、前回の記事を読んだだけではいまだ疑問をお持ちの方もいらっしゃることと存じます。
たとえば、「なんでわざわざ二進数なんて回りくどいものを使うんや。視覚的にもわかりやすい10進数じゃあかんのか」とか「二進数なんていうけどビトゲでは10進数しか操作できひんで。それやのに間違いなく管理できるんか?」といった感想をお持ちの方は少なくないでしょう。
ですので、本記事では二進数を取り扱うことについて、様々なアングルからそのメリットを考察し、説明していきたいと思います。
二進数に自信ニキの方にとっては読むだけ時間の無駄な記事ですので、読み飛ばすことをお勧めします。
二進数とは何ぞや
いきなりですが、質問です。
二進数とは何でしょうか。
いや、そんなことはとっくに知っとるわ、という方、しばしこの茶番にお付き合いください。
さて、話を戻しまして、二進数とは何でしょうか。
2を基数とし、2倍ごとに位取りを行う形式。
位を順に底2の冪ごとにとる形式。
調べればいくつもの表現が出てきますが、どうも言葉で説明されてもピンときませんね。
では、一度10進法とくらべながら、その振る舞いを見てみましょう。
10進法はご存じの通り、この現代世界で最も普遍的に使用されている数値表現形式です。
位を1,10,100,1000…と10の倍数ごとにとり、各位の値は0~9で表す、みなさんが最も直観的に考えることが出来るであろう数値表現形式です。
2進法とはこれに対し、各位を1,2,4,8,16,32,…と2の倍数ごとにとり、各位の値を0もしくは1で表す表現方法です。
……うーん、これだけ説明されてもなんのこっちゃ分かりませんね。
もう少し具体的に振る舞いを見てみましょう。
二進数の振る舞い
二進数についてより理解を深めるために、まずはその振る舞いを見ていきたいと思います。
といってもいきなりその振る舞いを直接的に説明することは難しいため、まずは準備運動として10進数の振る舞いを見てみましょう。
まず、サンプルとして一つ数値を用意します。
そうですね…今回は1741という数値を例にとって考えてみましょう。
では、突然ですが一つ質問です。
あなたは今、コンビニで買い物をしています。お会計は1741円でした。
支払いのためにお財布を覗いてみると中には1000円、100円、10円、1円がそれぞれ9枚ずつ入っていました。
おつりが出ないよう支払いをするためには、何円を何枚ずつ出せばよいでしょうか。
簡単ですね。
答えは1000円1枚、100円7枚、10円4枚、1円1枚…
考えずともすぐに分かることです。
そして、考えずにわかるこのことこそが10進数の振る舞いそのものなのです。
先ほど、あなたはお金の枚数を数えるとき、どのように数えたでしょうか。
多くの人はおそらく、
「うーん、1741やから、とりあえず一番でかい1000円が一枚やろ? ほんで残りが741やから、次にデカい100円が7枚、これで残額が41円や。ほな、後は10円が4枚と最後に余った1円が1枚やな」
といった塩梅に頭の中で枚数計算を行ったことでしょう。
とても単純です。
そして、この単純さはなにも10進数だけに限るものではありません。
二進数の振る舞いを考えるときは、この計算を、二進数対応の値をつかって考えればいいのです。
あらためて二進数の振る舞いを考える
では、先ほどは10進数で1741を分解したように、今度は2進数で分解してみましょう。
10進数では位取りが1,10,100,1000…と10のべき乗ごとにとっていました。
2進数ではこれを2のべき乗、すなわち1,2,4,8,16,32,64,128,256,512,1024…を用いて計算します。
ただ、一つだけ注意したいことがあります。
それは、桁上がりの法則が10進数と2進数では異なることです。
10進数の桁上がりは、同じ位の枚数が10枚集まると発生します。
たとえば、10円玉が10枚集まると合計100円。
十円玉1枚は10、十円玉2枚は20、5枚は50、9枚は90、というように枚数が0~9枚の時は10の位の数として表せますが、10枚集まるとそれは100、すなわち十個セットで100円玉一枚とカウントしなければなりません。
これの言わんとしていることは、10の位の数として選べるのは0~9のどれかのみ。10に到達すると、一桁上の位の値としてカウントしなければならない。
このような法則性があります。
そしてこれは何も10の位だけでなく、100も1000も10000も、すべての位で普遍的に成立している法則だということです。
一方、2進数では桁上がりが10進数よりももっと早く発生します。
例えば2の位と4の位について考えてみましょう。
2は一つであれば2です。一方2が二つ集まると4です。
はい、もう繰り上がりです。
2進数では一つの位に選べる数字は0か1のみです。2つ集まると、それだけで繰り上げの必要が生じます。
……ちょっと直観的には理解しにくいかもしれません。
では、一つ具体的な数値を使って考えてみましょう。
2進数を使い、十進数でいう10までの値をカウントしてみます。
どうでしょう、二進数の振る舞いについてご理解いただけたでしょうか。
では、次はこれと同じ方法で先ほど10進数で分解した1741を今度は二進数で分解してみましょう。
二進数の位取りは小さいものから順に1,2,4,8,16,32,64,128,256,512,1024,2048…です。
先ほど十進数で1741を分解したときは10の倍数かつ1741以下である1000を最初の分解値として選択しました。
二進数でもそれは変わりなく、分解値は2の倍数かつ1741以下の物から順に選びます。
2048は1741より大きいですから、最初は1024がよさそうです。
では、一旦1024を一つ確保することとして、1741から1024を引いてしまいましょう。
すると残りは1741 – 1024 = 717 となります。
717も同じようにして分解を続けます。
717 – 512 = 205 512が一つ
205-256 = -51 256はなし
205-128 = 77 128が一つ
77 -64 = 13 64が一つ
13 – 32 = 19 32はなし
13-16 = -3 16はなし
13-8 = 5 8が一つ
5-4 = 1 4が一つ
1-2 = -1 2はなし
1-1=0 1が一つ
以上をまとめると
1714 = 1024 + 512 + 128 + 64 + 8 + 4 + 1
であることが分かります。
そしてこれを二進数で表すと
11011001101
となるわけです。
これが2進数という表記方法の基本的な扱い方になります。
ご理解いただけたでしょうか。
……私にはこれ以上の説明はできそうもないので、理解していただけたものとして話を先に進めていきたいと思います。
二進数を利用することによるメリット
さて、ひとまず二進数についてのおよその振る舞いは理解していただけたことと思います。
ここからはもう一歩踏み込み、二進数を使用するメリットを説明していきましょう。
二進数を利用する最大のメリット、それはずばり、情報記録枠の圧縮です。
前回の記事でも少し触れましたが、二進数は0もしくは1のデータを複数個、一つの変数枠だけで記録することができます。
「真」「偽」のような二種判定データは「フラグ」を利用する場合は、データごとに「フラグ」枠を確保しなければなりません。
しかし、二進数を利用すればこれらの「真」「偽」羅列を二進数変換し、数値として変数に格納することで使用枠を大幅に圧縮できます。
具体的にどれだけ圧縮できるかを説明しますと、ビットゲームメーカーの変数の最大値は99999999ですから、2^26 – 1 = 67,108,863を考慮して、26個の真偽データを変数一枠に治めることができるのです。
(2^26 – 1は初項1、公比2、項数26の等比数列の和です。なんやそれって方はとりあえず変数一つで26桁の二進数を保存でき、26の真偽データを格納できるということだけ覚えておいてもらえれば構いません。ただし、中高生でこれから大学受験をする君たは等比数列のことからよく覚えておきなさい)
(負の値まで拡張すればもっといけるやろという方もいるかもしれませんが、処理の単純化のために今回は考えないことにします。)
また、いま説明したことは「フラグ」に比しての情報圧縮量のメリットですが、単純な「真偽」データの保存だけに限るなら、他のあらゆる進数方式より2進数が優れていることは言うまでもありません。
たとえば、直観的に分かりやすい10進数で保存することを考えてみましょう。
十進数の各位に0もしくは1を選択的に入れることで、真偽データを保存するのです。
想像してみた感じ、不可能ではないですし、直観的には扱いやすそうな気がしますね。
ですが、この方法には大きな無駄があります。
先ほど説明したようにビットゲームメーカーの変数最大値は99999999。
つまり、十進数で保存できるデータ数はたったの8個。
二進数方式と比較すると、その効率は三分の一以下です。
このことからも、以下に二進数が合理的手段であるかはご理解いただけるでしょう。
ビトゲで操作できるのは10進数やん。それなのに2進数を取り扱うことは現実的にできるんか?
さて、ここまでは真偽データを二進数で処理することに関して、その論理的メリットを開設してきました。
しかしながら、この議論はあくまで机上の話。
ビットゲームメーカーでは2進数を直接的に操作することはできません。
ビットゲームメーカーで操作できるのは10進数です。
冒頭でも提示したように、10進数から2進数を操作できるんかという疑問をお持ちの方はいらっしゃるかもしれません。
しかし、ご心配は不要です。
この疑問に単刀直入に回答しますと、答えはイエスです。
理由は明白。
十進数も二進数もどちらもその本質は数値の表記方法で、示している数値事態の性質にはなんら変わりがないからです。
もうすこし具体的に説明しましょう。
今、十進数で00100と01000いう値を考えてみます。各値の先頭についている0はこの後足し算をするために便宜的に付け加えた0で、00100は100と01000は1000と同じです。
では、ひとまずこの数値を使って足し算をしてみましょう
1000 + 100 = 1100
つまり
01000 + 00100 = 01100
ということになります。
これは各桁で繰り上がりの発生しない計算ですから、それぞれの位の値を足すだけで簡単に和が求められますね。
では、次は引き算を見てみましょう。
01100 – 01000 = 00100
これも直観的にすぐに分かる回答です。
引き算の繰り下がりがありませんから、各位でそれぞれ引き算をすればすぐに答えを出すことができます。
では、次は2進数について同じことを考えてみましょう。
まず、11111(2)という数値を考えてみます。末尾の(2)はこの値は二進数で示されているということです。
この値を十進数変換すると
11111(2) = 16 + 8 + 4 + 2 + 1 = 31
となります。前半で述べた二進数が2のべき乗を位としてとる話を考えれば、ご理解いただけると思います。
そして、これだけでなく、以下に3つほど、数字を考えてみたいと思います。
00010(2) = 2
01100(2) = 8 + 4 = 12
10001(2) = 16 + 1 = 17
さて、まずはこれらの数値について、二進数表記のままいくつか計算をしてみたいと思います。
11111(2) – 00010(2) = 11101(2)
11111(2) – 01100(2) = 10011(2)
11111(2)-10001(2) = 01110(2)
これは分かりやすいですね。
00010(2) + 01100(2) = 01110(2)
01100(2) + 10001(2) = 11101(2)
10001(2) + 00010(2) = 10011(2)
こちらも視覚的にご理解いただけることでしょう。
ところで、上で示した計算について、それぞれ右辺と左辺の関係を10進数を通じて見てみたいと思います。
11111(2) – 00010(2) → 31 – 2 = 29 11101(2)→ 29
11111(2) – 01100(2) → 31 – 12 = 19 10011(2)→ 19
11111(2)-10001(2) → 31 – 17 = 14 01110(2)→ 14
00010(2) + 01100(2) → 2 + 12 = 14 01110(2)→ 14
01100(2) + 10001(2) → 12 + 17 = 29 11101(2)→ 29
10001(2) + 00010(2) → 17 + 2 = 19 10011(2)→ 19
さて、お分かりいただけたでしょうか。
二進数の計算結果と十進数の計算結果は表記方法こそ異なるものの、どちらも同じ値を示しています。
そして、なによりも注目したいのが二進数でも繰り上がり、繰り下がりが無いように計算すれば、特定の位の値を変更しながら、それ以外の位の値はそのままにしておくということが出来ること。
つまり、2進数の値を都度10進数に変更しながら計算、さらに繰り上がりと繰り下がりが発生しないようにする。
このルールさえ守れば、ビットゲームメーカー上でも二進数を操り、二進数で真偽データ管理を行うことが出来るのです!
もっと具体的に
さて、ここまでの記事をお読みいただいた皆様は、二進数で真偽データの管理を行うことが可能であることはお分かりになられたと存じます。
しかしながら、一体これをどうやって教え技システムに反映するんだという、実装部分についてはいまだ曇りがかかった方もおられるでしょう。
そこで、最後にこの二進数を用いてどんな風にデータを管理するのか、その具体的方法の一つをお教えしたいと思います。
まず、下の表を思い出してください。
これは前回の記事でもお見せした、「はかいこうせん」の真偽データです。
まずは、このデータを一つの変数として格納する方法を考えましょう。
表の右側の数値を低位の二進数と考えます。すると、「はかいこうせん」の習得可否データは十進数に直したとき、
1 + 2 + 16 + 32 + 64 + 512 + 1024 = 1651
となります。すなわち、「はかいこうせん」の習得可否データを格納したい変数に1651を入れておけば、表中一連のデータをすべて格納できることになります。
技教えシステムではこのデータを使い、システムを動かしていきます。
それでは、次はその方法を説明……
と行きたいですが、そろそろ話も長くなってきましたので、本記事では一旦、話をここまでにいたしましょう。
どうやって習得可能かどうかを判断するのか、そういったさらに踏み込んだ話は、次の記事で説明して参りたいと思います。
結びに
さて、本記事では二進数とはなんぞや、そして習得可否データをどのように二進数に変換し、それをビットゲームメーカーの変数に落とし込むのかという説明をいたしました。
話も本筋に踏み込み、記号的な説明が増えてきてしまうなか、最後までお読みいただいた皆様には感謝申し上げるばかりです。
次回の記事では、いよいよこの習得可否データをつかってどのようにシステムを動かすのか、その具体的方法を説明して参りたいと思います。
どうぞ、次の記事もよろしくお願い申し上げます。
技教えシステム_解説記事3
技教えシステム_解説記事3
解説記事3:システムの理論解説
はじめに
どうも空気です。
前回に引き続きいよいよ三回目となるこの記事では、いよいよ二進数値として保存した真偽データ群を実際のシステム上でどのように使用するのか、その方法を説明していきたいと思います。
まず、今我々は何を作ろうとしているのか
さて、いきなり質問です。
まず、今我々は何を作ろうとしているのか。
皆さんはここまでの記事をお読みいただいた上で、この質問に的確に答えられるでしょうか。
なんや?突然そんな質問をして。教え技システムを作ろうとしているんちゃうんか?
全くその通りです。
ですが、その考えはいささか大雑把すぎるのです。
教え技システムといっても、システムはその中身を機能によっていくつかの部分に分解することができます。
教える技を選択する部分、覚えるキャラを選択する部分、選択したキャラが選択した技を覚えられるか判定する部分、実際に習得する部分……
できる限り大枠で分けても4つの機能に分解されるのは分かるでしょうか。
そして今、二進数による可否データを用いて作ろうとしているのは上のどの部分か、これを頭に入れておくことが大切です。
私は以前の記事で、キャラクターに個性を持たせるため習得できる技に制限をかけるとお話ししました。
我々が今、2進数可否データを用いてやろうとしていることは、この習得技の制限動作、すなわち「選択したキャラが選択した技を覚えられるか判定する部分」です。
もし、すべてのキャラが全ての技を自由に習得できるゲームを作る場合は、今から説明するシステムは全て不要なものです。
この記事で私がお話しするのは、あくまで「選択したキャラが選択した技を覚えられるか判定する部分」の構成だということを念頭に置いたうえで、続きの話をお読みください。
システムの概念
さて、まずはシステムがどんなものかを考えるのに先立ち、システムは何を目的として、どんなデータを操作するのかということを理解しましょう。
下の図をご覧ください。今、我々が作ろうとしているものについて、その大まかな概念図を用意しました。
ここで、キャラ固有番号とはあらかじめキャラに重複のないように割り当てた番号、技固有番号とはあらかじめ技に重複のないように割り当てた番号を意味します。
具体的には技はスキル欄のs011と言った数値の下二桁を切り出して割り当てると都合がいいでしょう。
キャラに関してはスキルと同じようにc001のような下二桁を切り出して当てはめたいところですが、ビットゲームメーカーの仕様により、下二桁の先頭が0となる値は後々不都合が生じてしまいます。(たとえばc001の下二桁を切り出すと01となりますが、これは好ましくない)。
ですので、下二桁を切り出したのち、それに10を加えた値を固有番号とするのが無難かと思われます。(c001なら切り出した下二桁01に10を加えた11を固有番号とする。C012なら同様に22が固有番号になる)
さて、上の概念図が意味するところは、blackboxの中身は一旦脇に置き、blackboxにキャラ固有番号と技固有番号を入れるとblackboxは受け取った固有番号のキャラが受け取った固有番号の技を覚えられるかどうかという結果を出力するということです。
とても単純な話ですね。
固有番号から可否データを取り出そう!
では、次はこの単純なシステムを構成するblackboxの中身を見ていきましょう。
用意するのは入力するためのキャラ固有番号、技固有番号、そして習得可否二進数を格納した可否変数です。
これらを使って入力されたキャラが入力された技を覚えるかどうか、その結果を出力するには……その方法を具体例を通して考えていきます。
下の図をご覧ください。これは実際に私が投稿した技教えサンプルにおける、「つるぎのまい」という技の習得可否を示したものです。
(前回までの記事とキャラクターの並びが逆になっていますが、投稿したシステムの仕様に準拠したほうがよいと判断したため入れ替えました。オーガポン(一番右の緑色のキャラクター)が二進数最小位、ケフカ(一番左の紫のキャラクター)が二進数最大位として可否データは作成しております)
技教えサンプル中で「つるぎのまい」はs015のスキルですから、技固有番号は15になっています。
また、「つるぎのまい可否」という「つるぎのまい」の習得可否を記録する変数には
100000111001(2)がデフォルトで格納されています。
100000111001(2) = 2105になりますから、「つるぎのまい可否」には2105が格納されていることになります。
では、ここでシステムの動作を確認するため、カイリュー(左から6番目の黄色いムーミンみたいなやつ。通称マルスケデブ)が「つるぎのまい」を覚えようとする場合の動作を追ってみましょう。(技教えサンプル内ではなぜか名前が韓国語になっていますが気にしないでください)
カイリューはc006にあたるキャラなので、そのキャラ固有番号は16です。
また、「つるぎのまい」はs015にあたる技なので、技固有番号は15になります。
そして、今我々はカイリューが「つるぎのまい」を覚えるかどうか調べるため、
「つるぎのまい可否」という変数の値2105を与えられました。
では、この三つの情報からカイリューが「つるぎのまい」を覚えるかどうか判別しましょう!
…………
……
…
できるかボケ!!アホ!!(矢野先生波感)
二進数可否データを用いる最大の弊害
以前投稿した記事で私は二進数データを用いる最大のメリットはデータ枠の圧縮だといいました。
しかし同時にこのデータ枠の圧縮というのはシステムを複雑化させる最大の弊害となってしまうのです。
では、なぜシステムが複雑になるのか。その答えは、目的のデータを取り出すために一回り多くの手間がかかることが避けられないからです。
二進数データそのものへは直接アクセスできますが、その内部の個別習得可否データへは直接アクセスできない。可否変数に格納されている数値を、特定の法則によって変形することで初めて所望のキャラの習得可否データを取り出すことができる。
そのためには何段階かの処理が必要で、その処理を実装するためにシステムを複雑化する結果となってしまうのです。
先ほどのカイリューが「つるぎのまい」を覚える場合を例に見てみましょう。
二進数可否データにおいてカイリューが「つるぎのまい」を覚えるかどうかは、低位から6桁目に格納されています。
この6桁目の値が1ならカイリューは「つるぎのまい」を覚える、0なら覚えない。
二進数データにはこのように情報が記録されます。
先ほどの表をもう一度見てみましょう。
表中の低位から6桁目(右から6桁目)の値は1です。つまり、カイリューは「つるぎのまい」を覚えることができます。
システムはカイリューが「つるぎのまい」を覚えるという判断をするためにこの低位から6桁目の「1」という値を的確に取り出す必要があるのです。
いま、システムが処理を行うための情報として持っているのは覚える技は「つるぎのまい」であるという技固有番号の数値15と、技を覚えるのはカイリューであるというキャラ固有番号16です。
この二つの値を使って可否変数から所望の位の値をとりだすにはどうしたらいいのでしょうか。
それには現在保持している二つの値に加え、もう一つの値を用意する必要があるのです。
キャラ固有位値の導入経緯
今まで、我々はキャラ個別番号と技個別番号の二つの変数を用いてシステムを動かすことを考えていました。
ですが、この二つの変数だけでシステムを完結させるにはいささか不都合があります。そこで、先述したキャラ固有位値の概念を新たに導入しようというわけです。
新しい変数を導入する前に、まずはシステムの概要がどんなものだったか改めて振り返ってみましょう。
下の図をご覧ください。図は以前にも示したシステム概念図を、blackboxの中身を多少詳細にした上で再び示したものです。
Blackboxの中身は主に二つの処理で構成されています。最初が技固有番号を利用した選択技の可否変数取得、その後取得した可否変数から対応キャラの可否格納桁の値を抽出し1か0かを判別するという構成です。
最初の可否変数の取得はその構造もシンプルです。技固有番号を教え技として設定するすべての技に連番で割り当て、そしてその順で変数枠の連番を確保しておけばいいのです。
スキルの固有番号をスキル欄番号の下二桁と一致するように定めた上で図のように可否変数を設定しておけば、適当な仮変数1に[20 + スキル固有番号]の値を格納しその後適当な仮変数2に「変数番目の変数を代入:仮変数1番目の変数」を行うことで仮変数2に可否変数が取得できます。
さて、blackboxの中身について最初のブロックの問題は容易く解決しました。しかし、問題はこの後です。
取得した仮変数から、カイリューの可否データを格納している桁の値をとりださなければいけません。
さて、先ほどもお話ししたように、今我々の手元にあるのは技固有番号、キャラ固有番号、可否変数の三つです。
このうち、技固有番号は今は関係ありません。すでに技に対応する可否変数をとりだすことに成功したため用済みです。
いま、我々がしようとしているのはとりだした「つるぎのまい」の可否変数から、カイリューが覚えるかどうかを記録した桁をとりだすことです。
ですが、この目的を達成するにあたり我々が今持っているカイリューの固有番号16はあまりにも不適当です。
いや、キャラにはそれぞれ前から連番ふってるんやろ?ほなら、二進数の桁を前から数えて連番の数と合致する奴をとればいいやんけ。
こう思う方もいらっしゃるでしょう。しかし、この処理は非常に複雑です。なぜなら、ビットゲームメーカーにはべき乗が存在しないから。
ゆえに連番参照で処理をしようとすると不要なループ処理が入り込み、全体構造がますますややこしくなってしまいます。
この複雑化への対策として固有位値を導入するのです
固有位値の導入
まず、固有位値とはどんな概念か、説明するより視覚的に見てもらった方が早いと思うので表を用意しました。
固有番号と併記しましたので一度ご覧ください。
どうでしょう?ざっくりと雰囲気は掴んでいただけたでしょうか。
固有位値とは端的に言えばキャラごとに与えた2のべき乗の値。
式的に表すと固有番号をn、固有位値をmとしたとき m = 2n-11で表されることが分かるかと思います。
そしてこの固有位値は可否変数から選択キャラの可否データを抽出する際に非常に強力な効果を発揮します。
それは、可否変数においてあるキャラのデータが1の時、その1はキャラの固有位値に一致しているからです。
このことが固有位値という新たな概念を導入することで享受できる最大の利便性なのです。
実際に抽出計算をしてみよう!
物は試しと言いますし、まずは実際の計算をして如何に固有位値が便利かを確認してみましょう。
ここまでの説明で出てきた「つるぎのまい」の可否変数とカイリューの固有位値はそれぞれ、
「つるぎのまい」の可否変数:100000111001(2) = 2105
カイリューの固有位値:32
です。この情報を用いて、カイリューが「つるぎのまい」を習得できるかどうかのデータを取り出します。
で、肝心の方法ですが、それは…
- 固有位値×2
- 可否変数を二倍された固有位値で割った剰余を取得
- 剰余を固有位値で割った商を取得、これがカイリューの習得可否データ!!
以上になります。
……詳しく見てみましょう。
まず、「つるぎのまい」の可否変数100000111001(2) = 2105、これを2のべき乗ごとに分解して多項式形式で表すと、
2105 = 2048 + 32 + 16 + 8 + 1
で表されます。下の表を見ていただくと、数値の意味をより深く理解していただけると思います。
表上の可否変数値と固有位値の関係性は、先述した可否変数の1の値が固有位値に一致するという話にも適っていますね。
さて、では続いては2105という値からカイリューの可否データを取り出していきます。
- 固有位値×2
カイリューの固有位値は32なので二倍すると64になります。
- 可否変数を二倍した固有位値で割った剰余を取得
2105÷ 64 = 32 余り 57 ∴剰余は57
- 剰余を固有位値で割った商をとる
57 ÷ 32 = 1 余り 25 ∴商は1
はい、出ました。答えは1、つまりカイリューは「つるぎのまい」を覚えることができます。
もう少し一般的な説明
さて、先ほどのクソ雑計算を見て、そんなんでええんかと思った方もいらっしゃるでしょう。(受験生はむしろ当然やろなにこの程度で記事にしとるんやクソ野郎くらいに思おうね。そう思えなかった受験生の君は素因数分解と等比数列を今すぐ基礎からやり直せ。)
ここではもう少し話を深堀し、先ほどの計算で的確に1が取り出せる理由を説明しようと思います。
(1)の部分は説明するまでもないので、(2)のところからお話しします。
(2)で可否変数を二倍した固有位値で割った剰余をとる理由
これはすなわち、カイリューより固有位値が大きいキャラの可否データの除去です。
一度表を見てみましょう。
先述したように、二進数表記の可否変数においてある桁に1が存在することは、可否変数に対応するキャラの固有位値成分が存在することです。
例えば、可否変数が111111111111(2)であれば、その十進数上の値は各キャラの固有位値をすべて足し合わせた4095になります。
では本筋に戻り、なぜ固有位値の二倍で可否変数を割った剰余をとれば、カイリューより固有位値が大きいキャラの可否データを除去できるのか。
それはカイリューより固有位値が大きいキャラの固有位値が、すべてカイリューの固有位値の二倍で割り切れるからです。
64,128,256,……、これらは全てカイリューの固有位値の二倍こと64で割り切れます。(固有位値は2のべき乗で定めているので当然っちゃ当然ですが)。
そして反対に、固有位値がカイリュー以下のキャラの固有位値は全員分足し合わせても63です。つまり、カイリュー以下の固有位値のキャラが「つるぎのまい」を覚えようが覚えまいが、この剰余算出の計算において影響を与えることは全くありません。
カイリュー以下のキャラの習得可否に応じてではありますが、剰余計算では0~63の整数のいずれかを得ることができます。
これが可否変数をカイリューの固有位値の二倍で割った剰余を算出する理由です。
(3)で得られた剰余をカイリューの固有位値で割る理由
さて、先ほど算出した剰余ですが、これはカイリューが「つるぎのまい」を覚えるかどうかによってその値の分布が完全に二分されます。
では、ここで一つ質問です。
カイリューより固有位値が小さいキャラの固有位値をすべて足し合わせるといくらになるでしょうか?
その答えは31です。
そうです、この31という数値を見ればわかるように先ほど0から63に分布すると述べた剰余の値は、カイリューの固有位値が32ですから、カイリューが「つるぎのまい」を覚えるなら32~63に、覚えないなら0~31に分布しているはずなのです。
さて、ここまで説明すればなぜ剰余をカイリューの固有位値で割った商をとるかはもうお分かりでしょう。
得られた剰余は0~63、つまりカイリューの固有位値32で割った時の商は0もしくは1しかありえず、さらにカイリューの「つるぎのまい」の習得可否に応じて分布範囲が32で二分されるため、カイリュー以下の固有位値のキャラの習得可否に関わらず、カイリューが覚えるなら1が、覚えないなら0が答えとして出てくるからなのです。
概念図の修正
ここまで解説してきたとおり、可否変数から選択キャラが技を習得するかどうかを抽出するために、新たに固有位値の概念を導入することにしました。
そうすると一度ここまで想定してきた概念図に修正を加える必要があります。といっても、それほど大きなものではありません。入力変数を固有番号から固有位値へと変更するだけのものです。
先ほど、私が提示した概念図は上のようなものです。この図では入力としてキャラ固有番号と技固有番号を利用していますね。
修正はキャラ固有番号をキャラ固有位値に変えるだけですから、変更後の概念図は下のようになります。
まとめ
今回の記事は先の二つに比べてもかなり長くなってしまったので、簡単にまとめます。
- 二進数データを使って行うのは選択したキャラが選択した技を習得可能か判断する処理。
- 可否変数はキャラ固有番号から直接習得可否データを取りだすことが困難なので、固有位値を利用して値を抽出する。
- 可否変数は技を覚えたいキャラの固有位値の二倍で割った剰余で高位桁を除去し、さらに固有位値で割った商をとることで習得可否データを取り出すことができる
以上、本記事で解説した主要な事項です。
結びに
さて、大変長い説明になってしまいましたが、ここまでお読みいただいた読者の皆様、厚く感謝申し上げます。
次の記事では今回の記事で説明した理論を踏まえ、システム全体の構成を実際のイベントを持ちいて解説していきたいと思います。
どうぞ、次回の記事もよろしくお願い申し上げます。
技教えシステム_解説記事4
技教えシステム_解説記事4
解説記事4:システム全体構成
あいさつ
どうも、空気です。
記事を書き続けている間にどんどんと文章量が増え、分割をしていきとうとう4回目の記事となってしまいました。
今回の記事では前回の記事で説明しました二進数データの管理方法を踏まえた上で、ビットゲームメーカー上でのイベントを用いながら詳細な解説をしていこうと思います。
今回は既に存在するビトゲ上のイベントの説明という形式上、淡白な解説が中心になるかとは思いますがどうぞ最後まで温かい目でよろしくお願いいたします。
はじめに
さて、今回はいよいよ全体のシステム構成を説明する回となりました。
それにあたり、まずはいくつか見ていただきたい画像がございます。
下の画像群をご覧ください。
以上、提示しました五つの画像。これらは今回私が技教えサンプルで実際に実装しましたイベントの大まかなフローです。(形式が不正確なのは私が断片的な知識で適当に作ったからなので許して)。
今回はこれらのイベントについて、その詳細と振る舞いを説明して参りたいと思います。
技教えサンプルの実際のイベントをもとに説明しますので、お手元にビットゲームメーカーと技教えサンプルをご用意いただけると、より分かりやすいかと思います。
習得可否判定イベント:技教えお姉さん
最初に解説するのは技教えお姉さんこと習得可否判定イベントです。これまでの記事でもその動作理論について散々触れて来た部分になります。
先に提示しましたフローで言うと、以下のフローが該当します。
このイベントで使用する変数
・仮変数1~5
・進行度変数
・人頭変数1~6
・個別ビット1~6
・技可否変数
・技習得変数
それぞれの変数の説明
・仮変数1
習得する技の固有番号を格納します
・仮変数2
習得するキャラの固有番号を格納します
・仮変数3
序盤、一時的な保持変数として使用した後、途中で用途を切り替え、習得するキャラの固有位値を格納する変数として使用します。
・仮変数4
序盤、技の可否変数格納先として使用した後、途中で用途を切り替え、技の習得変数格納先として使用します。
・仮変数5
一時的な保持変数として使用します。
・進行度変数
進行度を記録します。これはイベントの途中で発生するキャンセル動作時にデフォルトの0に修正し、キャンセル動作後後発のスクリプトが起動しないために使用します。
・人頭変数1~6
パーティにいるキャラクターの固有番号がはじめから格納されています。このイベントでは人頭変数の値を直接変えることはせず、参照して仮変数に値を代入する形で格納値を利用します。
・個別ビット1~6
パーティにいるキャラクターの固有位値がはじめから格納されています。値の並びは人頭変数と同じになっています。このイベントでは個別ビットの値を直接変えることはせず、参照して仮変数に値を代入する形で格納値を利用します。
・技可否変数
技を覚えられるかどうかの可否データが格納されています。変数の並びは技固有版番号の順に並んでいます。このイベントでは技可否変数の値を直接変えることはせず、参照して仮変数に値を代入する形で格納値を利用します。
・技習得変数
キャラクターが技をすでに覚えているかどうかのデータが記録されています。記録方式は可否変数と同様です。技習得変数はこのイベントでキャラが技を習得した場合、習得したという事実を記録するために値を書き換えます。
説明
1行目から12行目
進行度変数に1を代入。
13行目から92行目
習得技選択、選択した技の固有番号を仮変数1に格納
習得技を選択しなかった場合は進行度変数に0を格納、以降の処理を分岐で発生させないようにする。
93行目~139行目
進行度変数に2を代入
習得キャラ選択、仮変数3に選択したキャラの固有番号が格納されている人頭変数の変数Noを格納。(例:人頭変数1の変数Noは11なので、1番目のキャラを選択した時は仮変数3に11を格納)
習得キャラを選択しなかった場合は進行度変数に0を格納。
140行目~204行目(フローのオレンジ囲みの部分)
選択したキャラが選択した技を習得できるかの判定。
142行目、仮変数2に選択したキャラの人頭変数(固有番号)格納。
現在仮変数3に選択したキャラの人頭変数の変数Noが格納されているため、仮変数2には変数番目の変数:仮変数3を格納する。
(仮変数3に11が格納されている場合、仮変数2には変数No11の変数の値が格納される。変数No11の変数は人頭変数1なので、仮変数2に格納されるのは人頭変数1の値)
143行目、144行目、仮変数3に選択したキャラの個別ビット(固有位値)格納。
個別ビットの変数Noは人頭変数の変数Noを+6した値である。(例:人頭変数1の変数Noは11、個別ビット1の変数Noは17)
現在、仮変数3には選択したキャラの人頭変数の変数Noが格納されている。仮変数3に6を加算することで選択したキャラの個別ビットの変数Noが得られる。
その後、仮変数3に変数番目の変数:仮変数3を格納すれば、仮変数3の中身は個別ビットの変数Noから個別ビットの値に入れ替わる。
(仮変数3に17が入っている場合、変数No17の変数は個別ビット1なので、仮変数3には個別ビット1の値が格納される。)
145行目、146行目、147行目、仮変数4に選択した技の可否変数格納
各技の可否変数の変数Noは技固有番号に+20した値である。(例:「つるぎのまい」の技固有番号は15、「つるぎのまい」の可否変数の変数Noは35)
現在、仮変数1には選択した技の技固有番号が格納されている。よって、仮変数5に(仮変数1)+20の値を格納することで、可否変数の変数Noを得る。
その後、仮変数4に変数番目の変数:仮変数5を代入し、選択した技の可否変数を格納する。
148行目~151行目、可否変数から選択したキャラの可否データ抽出
以前の記事で説明した方法で可否データの抽出を行う。
148行目、仮変数3を二倍、仮変数3には選択したキャラの固有位値が格納されているため、計算後は固有位値の2倍を得る。
149行目、(仮変数4)%(仮変数3)を計算する。剰余計算で高位桁を除去する。
150行目、仮変数3÷2、再び固有位値に戻す
151行目、(仮変数4)÷(仮変数3)
※151行目に関して注意
ビットゲームメーカーには商計算が存在しない。そのため、151行目の計算後の仮変数4には小数部分を含む値が格納される。
しかしながら小数部分が含まれていてもキャラが技を覚えられるかの判別は容易で、計算後の仮変数4が1以上なら覚えられる、1未満なら覚えられないと判別すればよい。
152行目~177行目
仮変数4の値を参照し、イベントの続行判定。キャラが技を覚えられるなら進行度変数を3に、覚えられないなら進行度変数を0にする。
179行目~204行目、習得済みかどうかの判定
進行度変数が4ならこの領域の処理を行う。
技習得変数という、あるキャラがある技をすでに習得済みかどうかを、可否変数と同様のデータ形式で記録している変数があるため、同様の処理で判別を行う。
最終的に習得済みなら1以上の値が、未収得なら1未満の値が仮変数4に格納され、さらに習得可能なら進行度変数を4に、習得不可能なら進行度変数を0にする。
205行目~228行目、習得イベントの起動
進行度変数が4なら技覚え共通フラグをオンにし、技教えお姉さんのイベント終了後に技覚え共通イベントが自動発動するようにする。
終了
技覚え共通イベント
習得判定イベントもとい技教えお姉さんが終了した後、フラグで自動発動するイベントです。仮変数1に格納された技固有番号と仮変数2に格納されたキャラ固有番号を参照しながら、実際にキャラに技を覚えさせるイベントです。
このイベントの構造は説明するまでもなく単純で、条件分岐木状に配置されたイベントを仮変数の値によってたどり、最終たどり着いた習得コマンドを発生させるだけのものです。説明するより見てもらった方が早いと思います。
個別編成イベント
パーティのキャラクターを変えるイベントです。フローのまんまでこれ以上説明することもないので省略。
加入共通処理
個別編成イベントにおいてパーティに加入が発生した場合、加入共通フラグがオンになり個別編成イベント終了後このイベントが自動起動します。パーティの内容変更に伴い、パーティの中身を格納している人頭変数と個別ビットの値を調整する必要が生じるため処理を行います。
イベントは加入共通処理フラグがオンの間、繰り返し起動します。
このイベントで使用する変数
・ループ変数
・仮変数1~4
・人頭変数1~6
・個別ビット1~6
それぞれの変数の説明
・ループ変数
現在、イベントが何回目の起動かを記録します。
・仮変数1
個別編成イベント終了時に新しくパーティに加えたキャラのキャラ固有番号が格納された状態でこのイベントが始まります。
・仮変数2
個別編成イベント終了時に新しくパーティに加えたキャラのキャラ固有位値が格納された状態でこのイベントが始まります。
・仮変数3、仮変数4
一時的な保持変数として使用します。
・人頭変数1~6
パーティメンバーの固有番号を格納しておく変数です。前詰で値は格納され、パーティメンバーが6人未満の時は、開いた枠には10が格納されます。(例:パーティメンバーが4人の時は人頭変数5、人頭変数6には10を格納します。)
・個別ビット1~6
パーティメンバーの固有位値を格納しておく変数です。前詰で値は格納され、パーティメンバーが6人未満の時は、開いた枠には0が格納されます。(例、パーティメンバーが2人の時は個別ビット3~6には0を格納します)
ふんわりとした雰囲気
まず、このイベントの動きについて雰囲気をお伝えするために図を作ってみました。イベント開始時は人頭変数にキャラ加入前の状態、仮変数に加入キャラの固有番号が入っているという想定で図をご覧ください。また、ループ変数は初回起動が1、その後起動ごとに1ずつ加算されていきます。
上の図はもともとパーティが4人の状態で、新たに固有番号が12のキャラを加入させようとしたときの処理を想定しています。人頭変数はパーティにメンバーがいるならキャラ固有番号が、いないなら10が格納されています。
今回はパーティが4人の想定ですから、1~4にはキャラ固有番号が、5,6には10が格納されているわけです。
加入共通処理ではイベントを一度起動すると、現在のループ変数に応じた人頭変数の値を確認、その値が10なら仮変数1に格納された加入キャラの固有番号をループ変数に応じた人頭変数に格納します。
この処理をループ変数が1~6の間で加算しながら6周させることで、現在値が10になっている人頭変数に加入キャラの固有番号を格納するのです。
また、この話だけを聞くとパーティ人数が4人以下で、人頭変数に複数の10が存在する場合に、それらをすべて仮変数1で上書きしてしまわない?と思う方もいらっしゃるかもしれません。
しかし、その問題については一度代入が発生した段階でループ変数を7まで飛ばし、イベントの最後にループ変数が7の時に、加入共通処理フラグをオフにする処理を挟み込むことで対策することが出来ます。
加えて、このイベントでは人頭変数の書き換えと同時に、個別ビットの書き換えも行います。個別ビットの値のキャラごとの並びは人頭変数と同じですから、同一ループで一括化することができます。
説明
1行目~9行目、ループ変数初期化
ループ変数は使用しない時は常に0となるよう設計されています。
一週目に入るため、ループ変数が0の場合は1に変更します。
10行目~12行目、ループ変数に応じた人頭変数の値取得
ループ変数に応じた人頭変数の値を仮変数4に取得します。
最初、仮変数3に10+ループ変数の値(人頭変数の変数No)を格納し、その後仮変数4に変数番目の変数:仮変数3を代入します。
(例:ループ変数が1なら人頭変数1を仮変数4に、ループ変数が4なら人頭変数4を仮変数4に取得します。)
13行目
仮変数4から10を引きます。この時、iを現在のループ変数値として、人頭変数iが10、すなわちi番目にキャラがいないなら仮変数4は0となります。
(例:今、ループ変数が1だとします。この時仮変数4には人頭変数1の値が格納されています。人頭変数1の値が15であったとき、仮変数4には15が格納されていることとなり、そこから10を引いた値は5になります。)
(例:今、ループ変数が5だとします。この時仮変数4には人頭変数5の値が格納されています。ところで、加入前のパーティ人数が4人だとすると、この時パーティに5番目のキャラは存在せず、人頭変数5の値は10となり、したがって仮変数4にも10が格納されていることとなります。この状態で仮変数4から10を引くとその値は0となります。)
14行目~73行目、人頭変数と個別ビットの書き換え
14行目の条件分岐
仮変数4が0の場合真、そうでない場合に偽となります。これはループ変数の値をiとして人頭変数iが10、すなわちi番目のキャラがいない場合に真を得ることになります。
(例:今、ループ変数が5であるとします。また、加入前のパーティ人数は4人、すなわち人頭変数5が10であるとします。この時、先の処理により仮変数4の値は0になっているはずです。よって、分岐条件は真となります。)
14行目の条件分岐の真の中身15行目~68行目
現在のループ変数と連番が一致する人頭変数および個別ビットの値を、新規加入キャラの固有番号と固有位値で上書きします。また、以降の重複処理を避けるためループ変数を7にしてイベント全体の末尾で加入共通処理フラグがオフとなる処理が発生するようにします。
14行目の条件分岐の偽の中身 69行目~72行目
偽が発生するときはループ変数値iと連番が等しい人頭変数にすでにパーティにいるキャラの番号が格納済み場合です。これ以上の処理は不要なのでループ変数を+1して次のループへ移ります。
74行目~83行目 脱出処理
本イベントは加入共通処理フラグがオンの間、繰り返し起動し続けます。ゆえに、どこかのタイミングでフラグをオフにしてイベントを終了する必要があります。
ループ変数は加入処理が発生するor六周目のループが終了した際に7となります。
よって、ループ変数が7の場合にフラグをオフにしてこれ以上同イベントが起動しないようにします。
離脱共通処理
個別編成イベントにおいてパーティに離脱が発生した場合、離脱共通フラグがオンになり個別編成イベント終了後このイベントが自動起動します。パーティの内容変更に伴い、パーティの中身を格納している人頭変数と個別ビットの値を調整する必要が生じるため処理を行います。
このイベントで使用する変数
・ループ変数
・仮変数1~5
・人頭変数1~6
・個別ビット1~6
それぞれの変数の説明
・ループ変数
現在、イベントが何回目の起動かを記録します。
・仮変数1
個別編成イベント終了時にパーティから離脱したキャラのキャラ固有番号が格納された状態でこのイベントが始まります。
・仮変数2
個別編成イベント終了時にパーティから離脱したキャラのキャラ固有位値が格納された状態でこのイベントが始まります。
・仮変数3、4、5
一時的な保持変数として利用します。
・人頭変数1~6
パーティメンバーの固有番号を格納しておく変数です。前詰で値は格納され、パーティメンバーが6人未満の時は、開いた枠には10が格納されます。(例:パーティメンバーが4人の時は人頭変数5、人頭変数6には10を格納します。)
・個別ビット1~6
パーティメンバーの固有位値を格納しておく変数です。前詰で値は格納され、パーティメンバーが6人未満の時は、開いた枠には0が格納されます。(例、パーティメンバーが2人の時は個別ビット3~6には0を格納します)
ふんわりとした雰囲気
まず、このイベントの動きについて雰囲気をお伝えするために図を作ってみました。離脱処理イベントは加入処理イベントと比較して一回り処理量が増加しており、その構造は主に二つに分けて考えることができます。
一つ目
一つ目は人頭変数から離脱キャラのデータを取り除き初期化する処理です。フローの黄色破線で囲まれた部分に当たります。
二つ目
人頭変数が関与するイベントは全て人頭変数が前詰であると想定して作られています。そのため、初期化によって10が中腹に発生した場合、人頭変数の位置調整をする必要があります。
また、イベントの仕様上人頭変数の羅列内部に10が孤立的に存在する場合は必ず一つしか孤立の10は現れません。さらに現れるのは現在のループ変数と同じ連番以降の人頭変数のみになります。
よって、人頭変数初期化イベントと前詰イベントは同一ループ内で処理することができ、初期化イベントの直後に前詰イベントを発生させることで処理数を最小にすることができます。
説明
1行目~9行目、ループ変数初期化
ループ変数のデフォルト値は0です。ループ変数が0の場合に1を代入して一週目を開始します。
10行目~12行目、仮変数4にループ変数に応じた人頭変数の値格納
10行目、11行目、仮変数3にループ変数に応じた人頭変数の変数No格納
12行目、仮変数4に変数番目の変数:仮変数3を代入、これにより仮変数4にはループ変数番目の人頭変数が格納される。
13行目、仮変数5に仮変数4をコピー
後で使うのでコピーを取ります。
14行目、仮変数4から離脱キャラの固有番号を引く
現在、仮変数1には離脱したキャラの固有番号が格納されています。仮変数4から仮変数1を引くことでその差を取得します。このとき、現在のループ変数値番目の人頭変数の値と、離脱するキャラの固有番号の値が一致していれば、差は0になります。
15行目、条件分岐
仮変数4が0なら真を、そうでないなら偽を返します。
仮変数4が0の場合は現在のループ変数番目の人頭変数の値と、離脱するキャラの固有番号が一致しているので、離脱キャラの固有番号および固有ビットを人頭変数から除去する処理を発生させます。
反対に仮変数4が0でない場合は一切の処理を行いません。
16行目~79行目、離脱キャラの人頭変数および個別ビット除去処理
現在のループ変数の値に応じて、連番値が等しい人頭変数および個別ビットを初期化します。
また、この処理に入った場合、後続の前詰処理において仮変数5が10になっている必要が出てくるため、17行目で仮変数5に10を代入します。
84行目~151行目、人頭変数および個別ビットの前詰処理
人頭変数羅列に孤立した10が発生する問題を解決するため、人頭変数の値を前に詰めます。
84行目、条件分岐
仮変数5が10の場合に真を、そうでない場合に偽を返します。
ここで、仮変数5には値の取り方に3つのパターンが存在します。
- 現在のループ変数番目の人頭変数と離脱キャラの固有番号が一致しておらず、人頭変数削除処理が発生していない。この時、仮変数5≠10。
- 現在のループ変数番目の人頭変数と離脱キャラの固有番号が一致しており、人頭変数削除処理を行った。この時、削除処理中に仮変数5に10を代入した。
- 現在のループ変数番目の人頭変数の値は離脱前から10であった。この時、仮変数5には10が格納されている。
それぞれのパターンの詳細は説明し始めると長くなるので割愛しますが、気になる方は参考までにお考え下さい。
85行目~147行目、人頭変数、固有ビットの値入れ替え
現在のループ変数番目の人頭変数を、現在のループ変数+1番目の人頭変数と入れ替えます。先に提示した図をイメージしていただけると分かりやすいかと思います。
同様の方法で個別ビットの方も入れ替えます。個別ビットの並びは人頭変数と同じなので、同一ルートで処理することが出来ます。
また、この処理は現在のループ変数の値が6の場合には不要です。
152行目
ループ変数+1
このループにおける一通りの処理が終了したため、次のループに向かいます。
153行目~162行目、脱出処理
6周目の処理が終了し、152行目でループ変数が加算されると、現在のループ変数は7となります。これ以上は処理を行わないため、ループ変数が7の場合に離脱共通処理フラグをオフにして、終了後にイベントが再起動しないようにします。
以上
さて、長くなりましたが、これをもって技教えシステムについて一通りの説明が完了しました。
私自身がこのような記事を執筆した経験も多いわけではなく、至らぬ点も多いとは存じますが、当記事が皆さまのビットゲームメーカーライフの一助になりましたら至上の喜びです。
稚拙な文章を最後までお読みいただき本当にありがとうございました。
そして、今後ともよろしくお願い申し上げます。