テラリウム徹底攻略ガイド

オブジェクト・モデルのクラス構造

デジタルアドバンテージ
2002/05/18


オブジェクト・モデルのクラス構造

 オブジェクト・モデルのクラスの項には、15のクラスが定義されている。これらのクラスの親子関係を整理して列挙すると次のようになる。

Organism 生物クラス
 Animal  動物クラス
 Plant  植物クラス
OrganismState 生物の状態を表すクラス
 AnimalState  動物の状態を表すクラス
 PlantState  植物の状態を表すクラス
Action アクション・クラス
 AttackAction  攻撃アクション・クラス
 DefendAction  防御アクション・クラス
 EatAction  摂食アクション・クラス
 MoveToAction  移動アクション・クラス
 ReproduceAction  生殖アクション・クラス
EngineSettings ゲーム設定クラス
MovementVector 移動ベクトル・クラス
Vector ベクトルの演算用クラス
テラリウムで使用する15のクラス

 動物(肉食動物あるいは草食動物)をプログラミングする際に重要となるクラスは、Animalクラスと、動物の状態を表すAnimalStateクラスだ。草食動物にとっては、植物の状態を表すPlantStateクラスも重要になる。

■Animalクラス

 テラリウムで動物プログラムを作成するには、Animalクラスのサブクラス(子クラス)としてクラスを作成する。Animalクラスは、上記の表からも分かるように、Organismクラス(Organismは「生物」の意味)のサブクラスであるため、自分の動物プログラムでは、OrganismクラスやAnimalクラスで定義されているメソッドやプロパティの機能を使用することができる。Organismクラスは、動物と植物に共通する特徴(機能)を実装したクラスだ。

 例えば、動物が可能な5つの基本行動(生殖(出産)、攻撃、防御、摂食、移動)には、それぞれAnimalクラス(BeginReproductionメソッドはOrganismクラス)の次のメソッドを使用する。

  • BeginReproductionメソッド
  • BeginAttackingメソッド
  • BeginDefendingメソッド
  • BeginEatingメソッド
  • BeginMovingメソッド

■AnimalStateクラス

 一方、AnimalStateクラスは、ある瞬間の(正確には次の項で説明する各ターンにおける)動物の状態を表すクラスである。「Organismクラス−Animalクラス」の関係と同様に、このクラスはOrganismStateクラスのサブクラスとなっている。

 自分自身の現在の状態を示すAnimalStateオブジェクトは、AnimalクラスのStateプロパティから取得することができる。これを利用すると、例えば現在の自分のエネルギー量は、

State.StoredEnergy

として取得でき、また自分が受けたダメージ量は、

State.Damage

として取得することができる。ここで、StoredEnergyプロパティはOrganismStateクラスのプロパティだが(動物も植物もいくつかの量のエネルギーを持っている)、スーパークラス(親クラス)のメンバにはキャストなしで参照することができる。ちなみに、DamageプロパティはAnimalStateクラス特有のプロパティだ(植物はダメージを受けないが、代わりに食料値(OrganismStateクラスのFoodChunksプロパティ)が下がっていく)。

 同様に、自分以外の生物についての状態は、その生物のOrganismStateオブジェクト(あるいはそのサブクラスのオブジェクト)を得ることによって調べることができる。自分の周りにいる生物を取得するAnimalクラスのScanメソッドでは、AnimalStateオブジェクトの配列を得ることができる。

 OrganismStateオブジェクトやAnimalStateオブジェクトなどの状態オブジェクトは、自分以外の生物を指し示す場合にも使用される。例えば上記のBeginAttackingメソッドでは、攻撃する相手のAnimalStateオブジェクトをパラメータとして指定する。これらの状態オブジェクトはそのときどき(各ターンごと)に生成されるオブジェクトであるが、その中にある生物を一意に識別可能なIDプロパティにより生物が識別されているようだ。逆にいうと、一度取得した状態オブジェクトの内容が更新されることはない。ただし、状態オブジェクトはAnimalクラスのLookForメソッドにより更新することができる。

イベントとターン

 テラリウムでは、すべての生物は1つの「ターン」において1回だけ攻撃、防御、移動、摂食を行うことができる。そして、ターンは0.5秒間隔で次々とやってくる。

 例えば、あるターンで肉食動物が草食動物に対して攻撃を仕掛けるとしよう。すでに述べたように、これにはAnimalクラスのBeginAttackingメソッドを使用する。メソッド名の頭が“Begin”なっていることからも分かるように、この時点で攻撃処理が即座に行われるわけではなく、これによって攻撃開始が指定される。つまりこのターンでは、攻撃を行うということを「セット」するわけだ。実際には、このメソッドが呼び出されることによりAttackActionオブジェクトが生成される。一方、草食動物が同じターンで、BeginDefendingメソッドにより防御していたとすると、攻撃と同様にDefendActionオブジェクトが生成される。そしてこのターンが終了後、テラリウムのシステム側で両者の戦闘が処理され、もし攻撃が防御に勝っていれば、次のターンでは草食動物のダメージ量が増えていることになる。

■AttackCompleted、DefendCompleted、EatCompletedイベント

 テラリウムで発生するイベントは、このターンと深く関連している。次に列挙したイベントは、攻撃、防御、摂食を“Begin〜”メソッドで行った次のターンで発生する。

  • AttackCompletedイベント
  • DefendCompletedイベント
  • EatCompletedイベント

 これら3つの行動は、それぞれイベントが発生した時点ですでに完了している。しかし攻撃対象の生物が1回の攻撃で死ぬとは限らないし、1回の“噛み付き”でエサを完食するとは限らない。このような場合は、イベント・ハンドラに渡されたイベント引数をチェックして行動がどのような結果で完了したかをチェックしたり、あるいは対象としている生物の状態を再取得したりして、必要とあらば攻撃や摂食を続行する必要がある。

■MoveCompleteイベント

 MoveCompletedイベントは、上記の3つのイベントと少し異なり、移動が完了するまで発生しない。つまり1度BeginMovingメソッドにより移動先を指定しておけば、移動が完了するまで、複数のターンにわたって生物は移動を続けることになる。このためすでにセットした移動を取り消すためのStopMovingメソッドも用意されている。また、BeginMovingメソッドには移動先を示すMovementVectorオブジェクトをパラメータとして指定するが、移動中のいずれかのターンで、再度BeginMovingメソッドを呼び出せば、移動先を変更することができる。なお同じターン内で複数のBeginMovingメソッドを呼び出した場合には、最後の呼び出しが有効となる。これはほかの“Begin〜”メソッドでも同じだ。

■Attackedイベント

 ほかの生物から攻撃を受けたときに発生するAttackedイベントは、1つのターンで複数回発生する点で、ほかのイベントとは異なっている。ただし攻撃も防御も、1回につき1つの生物に対してしか行うことができないため、自分を攻撃している生物のうちどの生物を相手にするのか、あるいはどれも相手にせずにとっとと逃げるのかは戦略次第だ。AttackedEventArgsのAttackerプロパティからは、攻撃をしている生物のAnimalStateオブジェクトを取得することができる。

■LoadイベントとIdleイベント

 プログラムで何の動作も起こさなくても、毎ターンごとに発生するイベントが2つある。ターンの最初に発生するLoadイベントと、ターンの最後に発生するIdleイベントだ。

 Loadイベントは、すべてのイベントに先立って発生するので、このタイミングでは、ほかのイベントで共通して利用するような変数の設定や初期化などをあらかじめ行っておくことができる。

 一方、Idleイベントは、ほかのすべてのイベントが発生したあとに発生する。生物プログラムによっては、このイベントのみを処理し、そこで自分と、自分の周りの生物の状態を取得して、すべての行動を決定しているものもあるようだ。

 このLoadとIdle以外のイベントについては、1つのターン内での発生順序は明記されていないが、プログラムを書いて少し調べてみたところ、ここまでに説明したイベントは、それぞれの次のような順序で発生するようである。

  1. Loadイベント
  2. MoveCompletedイベント
  3. AttackCompletedイベント
  4. EatCompletedイベント
  5. DefendCompletedイベント
  6. Attackedイベント(複数発生する可能性あり)
  7. Idleイベント

 “Begin〜”メソッドによりセットされたそれぞれの行動は、ターン終了後にシステム側で一括して処理されるようなので、上記2〜6までのイベントがどのような順番で発生したとしてもさほど問題にはならない。ただし前述したとおり、“Begin〜”メソッドでセットした行動は最後のものだけが有効となる。このため、例えばMoveCompletedイベントの発生時にBeginAttackingメソッドを呼び出してセットした攻撃を、それ以降の別のイベント発生時に上書きしないようにしなければならない。すでに行動がセットされているかどうかは、IsAttackingプロパティなどの、“Is〜”プロパティにより調べることができる。

■ほかのイベント

 ここまでに挙げたイベント以外にも、生物が生まれた時点で1回だけ発生するBornイベント、生物がテレポートされたときに発生するTeleportedイベント、自分の子を産んだ直後に発生するReproduceCompletedイベントがある。出産という行動は、BeginReproductionメソッドにより開始されるが、これが完了してReproduceCompletedイベントが発生するまでには、最短でEngineSettings.TicksToIncubate(現在の設定では10)のターンが必要となる(途中エネルギーが少なくなってくると、この期間は長くなる)。

 最後にテラリウムでの時間の単位であるティック(Tick)について触れておこう。ティックは1ターンで1ずつ増えていく。例えば、今述べたように出産を開始してから10ターン後に子供が生まれるが、これは出産に10ティックかかるというのと同義だ。

 また、例えば生物が生きていられるティック数(すなわち生物の寿命)は、種によってあらかじめ決まっていて、プログラムからは“Species.LifeSpan”で取得することができる。また、“State.TickAge”は生物が誕生してからのティック数(すなわち現在の年齢)を表している。


 INDEX
  [連載]テラリウム徹底攻略ガイド
  第3回 オブジェクト・モデルと生物テンプレート
     テラリウムのオブジェクト・モデル概要
   オブジェクト・モデルのクラス構造
     生物テンプレートの詳細(1)
     生物テンプレートの詳細(2)
 
インデックス・ページヘ  「連載  テラリウム徹底攻略ガイド」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間