「ゲームプログラミング」の版間の差分

削除された内容 追加された内容
596 行
 
== 特殊イベントのフラグの作り方 ==
==== フラグとはの基本 ====
RPGなど、ゲーム中で1回しかおきない特殊なイベントとかを作りたい場合があるでしょう。RPG以外でも、シミュレーションゲームなどで特殊イベントを実装したいこともあります。たとえば、もし日本の中世の戦国時代シミュレーションゲームで「桶狭間の戦い」が3回も起きたりしたら困ります。
 
619 行
 
 
==== ゲームでは3段階のフラグ変数は2値か3値か4値か?も必要 ====
ゲームでは3段階のフラグも必要です。
 
一般にIT産業では「フラグ」と言った場合、状態 on または off の意味で、数値「1」か「0」の二つのいずれかの使います。
626 ⟶ 627行目:
 
 
ですがゲームでは数学とは異なり、
:イベント状態 の「未発動」
:または「イベント発動中だがイベント未クリア」
:または「イベントクリア済み」
の3種類の状態を使うこともあります。
 
 
637 ⟶ 642行目:
という3段階の区別が必要なのに、ON/OFFの2通りだけでは区別できないからです。
 
このようにゲームでは、情報科学の伝統的な理論とは異なり、イベント変数としてのフラグ変数を「2」または「1」または「0」の三つのうちのいずれかを使って記述する場合もあります。
なので、必要に応じて、3段階のフラグも作りましょう。
 
なので、必要に応じて、3段階のフラグも作りをなんらかの方法で実装する必要が生じしょう
 
 
==== 3段階フラグ変数をどう実装するか? ====
ゲームでは、3段階のフラグが必要になる場合もあります。
 
では、どうやって、ゲーム用の3段階のフラグ変数を用意するのでしょうか?
 
下記のような、いろいろな方式があります。
 
どの方式も一長一短ですので、あまり上手い方法はありません。 なので最終的には、ご自身の制作されるゲームに適した方式を使ってください。
 
 
==== 3値変数の方式 ====
もっとも単純なのは、整数変数(たとえば <nowiki>int ibento[配列指数]</nowiki> みたいに宣言)を用意して、値が0なら未亜h津堂、値が1なら発動中、値が2ならイベントクリア済み、のように判定する方式です。
 
つまり、
:<nowiki>int ibento[配列の番号] = 0</nowiki> なら、そのイベントが未発動
:<nowiki>int ibento[配列の番号] = 1</nowiki> なら、そのイベントが発動中
:<nowiki>int ibento[配列の番号] = 2</nowiki> なら、そのイベントがクリア済み
 
 
たとえば依頼イベントなら、とりあえず、
:依頼されてない段階: 0
:依頼されたが解決してない段階: 1
646 ⟶ 673行目:
 
 
C言語でゲームを作るなら、配列を使って、0/1/2の三値のフラグ変数を管理すると、ラクに管理できるでしょう。
このようにゲームでは、情報科学の伝統的な理論とは異なり、イベント変数としてのフラグ変数を「2」または「1」または「0」の三つのうちのいずれかを使って記述する場合もあります。
 
 
この方式の欠点は、メモリを余分に使うことです。数値は0、1、2しか使わないのに、整数型を宣言しているので、確保したメモリのほとんどが使われていません。
C言語でゲームを作るなら、配列を使って、0/1/2の三値のフラグ変数を管理すると、ラクに管理できるでしょう。
 
 
なお、数学でいう「3値論理」とは、上述イベント変数のような手法とは、本来は意味が異なる。1950~1970年ごろ、かつて三値論理学が大学などで研究された事もあったが、現代では滅多に使わないので、気にしなくていい。
 
なお、情報科学にはビット列という概念がありますが(たとえば 1011 0010 みたいな数値列)、
 
==== 2個の2値変数を使う方法 ====
ビット列は、ゲームのフラグ管理では、あまり実用的ではないです。通常の二値ビットだけでなく、もし三値ビット(2202みたいなの)でイベント処理をしても、よくあるミスで、ビット列が1個ズレるバグで、となりの桁のイベントがズレてしまうバグがあります。
2個の2値変数を使って、イベントの3段階の状態わけ(未発動/発動中/クリア済み)を実装する方法もあります。
 
 
たとえば、配列で「イベント発動判定フラグ」配列 <nowiki>hatudo[]</nowiki>および「クリア判定フラグ」配列 <nowiki>kuria[]</nowiki>を用意して、
 
たとえばイベント番号が8番のイベントを発動させるなら <nowiki>hatudo[8]=1</nowiki> にセットするような方式です。
:※ 厳密には配列は0番から数えるので8個目は <nowiki>hatudo[7]</nowiki> にするべきかもしれないが、説明の単純化のため無視した。
 
その後、イベント8番をもしプレイヤーがクリアしたなら、」<nowiki>kuria[8]=1</nowiki> にセットするというわけです。
 
この方式の利点は、フラグの意味が明確になる事と、もうひとつは値をブール型で宣言すればメモリの節約になることです。
 
短所として、変数または配列の数が2倍になります。
 
また、イベントクリア後に発動判定フラグをどう処理するか(0に戻すか、それとも1のままにするのか)、人・会社によって方針が異なるかもしれません。
 
 
==== 備考ビット列 ====
さて、散々これからビット列の話をしましたが、しかしゲーム制作では、できれば(ビット列の処理ではなく)配列でイベント変数を実装するほうが安全です。
 
もしビット列を使うなら、考え方は下記のようになるでしょう・・・・・・・
 
 
配列の代わりに、ビット列を使う方式もありますが、しかしゲームのフラグ管理では、あまり実用的ではないです。
 
なおまず、情報科学にはビット列という概念があります(たとえば 1011 0010 みたいな数値列)
 
 
ビット列としてゲームのフラグ管理では、あまり実用的ではないです。通常の二値ビットだけでなく、もし三値ビット(2202みたいなの)でイベント処理をしても、よくあるミスで、ビット列が1個ズレるバグで、となりの桁のイベントがズレてしまうバグがあります。
 
たとえば、
688 ⟶ 743行目:
なお、「三値ビット」等といいましたが、正確には、ビットとは2進数の値のことですので、3進数以上では「バイト」を使って「3値バイト」とか「3進バイト」とか言うほうが厳密かもしれません。ですが、そこまで厳密に体系化されてない事と、そのため作家や会社によって表現が違うので、よく2進ビット列をソフトウェア的に組み合わせて3値処理や4値処理を実装したりするので、慣習的に「3値ビット」や「4値ビット」みたいな言い回しでも通用したりします。
 
 
さて、散々ビット列の話をしましたが、ゲーム制作では、できれば(ビット列の処理ではなく)配列でイベント変数を実装するほうが安全です。
 
もしかしたらファミコン時代の古いゲームなら、メモリの節約のためビット列で処理する事もあったかもしれませんが、現代なら配列でイベント管理するほうが安全でしょう。(ファミコン時代のRPGによくあるバグで、メモリのオーバーフローを起こしてイベントフラグのズレるバグが幾つかある。)
703 ⟶ 756行目:
C言語では16進数(0からFまで)を扱えるので原理的には16進ビット列(正確には「16進バイト列」というべきだろうが)等もありえますが、しかし慣習的にゲームのイベント管理で使うビット列は、よく聞くのは、せいぜい4値ビットまでです。それ以上は寡聞にして聞きません。
 
==== 2値フラグで押し通すことも可能 ====
==== 備考 ====
イベント1個につき、on/offの状態分けだけで、配列変数を1個だけしか使わない方法も、ゲームのジャンルによっては可能です。
こういった、ゲームのフラグ処理には、あまり上手い方法はありません。
 
どうやるかというと、イベントのクリア判定と、次のイベントの発動とを兼用する事です。
 
 
これはこれで利点もある方式で、一本道シナリオのゲームならバグ防止にもなり、ゲーム中で本来なら発動すべきイベントが未発動になるバグなどを未然に防げる長所もあります。
 
ですが短所として、一本道でないフリーシナリオ的なイベント攻略順序の自由なゲームの設計が、なかなか難しくなるでしょう。
 
また、仕様変更などでイベントの発生順序が変わった場合なども、修正が面倒になるでしょう。
 
 
==== うまい方法は無い ====
こういった、ゲームのフラグ処理には、あまり上手い方法はありません。
 
また、あまり凝った特殊フラグ処理のシステムを実装(?)すると、デバッグがとても大変になります。
 
なので、初心者は、あまり凝りすぎないフラグ管理システムにしましょう。
 
 
721 ⟶ 787行目:
 
そしてゲーム開発において、特殊イベント処理のデバッグは、そのデバッグ作業のなかでも、かなり手間のかかる部分です(通しプレイなどが必要なので)。
 
 
==== 複数イベントのモジュール化 ====
フラグ管理は、原理的にはすべてのイベントに クリア/イベント中/未発動の意味で、2/1/0 の場合分けをすればいいのですが、
しかしプレイの快適性のためには、それだけでは不十分な場合もあり、さらなる手法が必要です。
 
 
743 ⟶ 810行目:
それがRPG制作の宿命でしょう。
 
RPGやシミュレーションゲームなどの面白さの要因のひとつとして、プレイヤーの知的好奇心を刺激するために未知の情報を提供するテクニックがありますが、ならばプレイヤーが既に知っている事をゲーム中で教えられても面白くないので、そういうイベントは省略できるようにしたほうがテンポがよくなります。
 
このための制作テクニックとしては、ゲーム中のイベント群を幾つかのモジュールにまとめると、管理しやすくなります。
750 ⟶ 817行目:
たとえば、ある1つのイベントの発生からクリアまでの複数のイベントを、モジュール1個として考えます。作家によっては「大イベント」「中イベント」などの表現をする場合もあるかもしれませんが、要するにイベントのモジュール構造のことです。
 
;欠点など
これらのモジュール化の欠点として、複数の変数が階層構造になるので、ややプログラミングの手間が増えます。なので、プロトタイプ制作などの段階では不便ですが、しかし最終的にモジュール化をしないと、プレイのテンポ感を損ねてしまいます。
 
しかし、一方として各イベントごとに「イベント進行度」とかの数値を割り当てる方式だけで対応しようとすると、短編RPGなどで簡単なフラグ構造でない限り、イベントを飛ばしたりする方法に対応しづらくなりますし、仕様変更なども困難になります。なので、階層構造になってでも、モジュール化をしたほうがよい場合もあります。
 
 
773 ⟶ 841行目:
 
 
さて、プレイヤーは未来予知を何らかの理由でしてしまっている場合もありますが、しかし作者にとってゲーム中でもリアリティなどの理由で
 
しかし作者にとってゲーム中でもリアリティなどの理由で、
:「どうしても、このイベントを飛ばさないでほしい」、
:あるいは「飛ばされると、リアリティ追加のためのイベント追加が大変になる」、
782 ⟶ 848行目:
 
なので、飛ばさないでほしいと思う重要な会話イベントについては、
:そのイベントを重要アイテムの入手イベントとくっつけたり等の方法をすると、
プレイヤーを自然とそのイベントを飛ばさないように誘導できるので一石二鳥的になります。