テラリウム徹底攻略ガイド(改訂版)

草食動物を作成する(1)

泉 祐介+デジタルアドバンテージ
2003/05/10
Page1 Page2 Page3 Page4 Page5 Page6 Page7

草食動物を作成する

 このKAnimalクラスを使って、草食動物“Tabata”(tabata.cs)を作成してみた(ちなみに、このプログラムの最初のバージョンは、第1回のテラリウム・コンテストの開始直後にほんの一瞬だけEcosystemで栄華を誇った)。ここでは、その動物のコードのうち、主要な部分を解説していくことにしよう。KAnimalクラス自体の解説は、このTabataの後に解説する。

属性によるポイント配分

 まずプログラムの冒頭で記述しなければならない各種属性について説明しよう。

[assembly: AuthorInformation("TeamDA", "TeamDA@d-advantage.jp")]
[assembly: OrganismClass("Tabata")]

[AnimalSkin(AnimalSkinFamilyEnum.Ant)]

[EatingSpeedPoints  ( 0)] // 植物を食べる速さ
[AttackDamagePoints ( 0)] // 攻撃力
[DefendDamagePoints (20)] // 防御力
[MaximumSpeedPoints (16)] // 移動の速度
[CamouflagePoints   ( 0)] // 偽装(身を隠す)能力
[EyesightPoints     (50)] // 視野の広さ
[MaximumEnergyPoints(14)] // 体力

[CarnivoreAttribute(false)]
[MatureSize(25)]
草食動物Tabataで設定している属性値

 [assembly: OrganismClass("Tabata")]では、KAnimalクラスのサブクラスとして記述するクラスの名前を指定する。例えばこの例では、プログラムtabata.csの中で“Tabata”というクラスを記述していることを示す。この属性により、テラリウム・アプリケーションは、インスタンス化するクラスを決定することができる。余談になるが、このTabataというのは、今後もさまざまな動物をシリーズ化して作るという予定から、山手線の田端駅から名前をとった。以後、動物の特徴や性格、強さなどに応じて、イメージが合致する山手線の駅名を作者の独断と偏見にて付けてゆくつもりである。

 次の[AnimalSkin(AnimalSkinFamilyEnum.Ant)]はスキンの指定である。ここでは、標準で用意されているスキンの1つである「アリ」のスキンを使用した。ほかのスキンを指定したい場合は、「Terrariumオブジェクト・モデル」のAnimalSkinFamilyEnumの項に定数の名前が載っているので、それを参考にしてほしい。

 続く7行が、この生物のベース・ポイントを決める属性だ。今回は、草食動物ということで、ほかの動物を攻撃するよりも、攻撃から身を守る方が重要だと考えて、このようなポイントの割り振り方になっている。というのも、草食動物はあまり戦闘に向いていないからだ。

 まず、草食動物は、エネルギー状態が空腹(Hungry)、または飢餓状態(Deterioration。空腹よりエネルギーがない状態)であるときなどにしか、ほかの動物を攻撃できない。また、肉食動物は、その動物の基本的な攻撃力や防御力にEngineSettings.CarnivoreAttackDefendMultiplierで設定されている値が乗じられることになっている。つまり、草食動物は肉食動物に比べて戦闘能力が劣るような設定に始めからなっているのだ。ついでにいえば、草食動物はほかの動物を攻撃して殺したとしても、当然のことながらその動物を食べられるわけではない。

 そういうわけで、敵を早めに見つけるのに必要な視野の広さ(EyesightPoints属性)、攻撃によるダメージを軽減するための防御力(DefendDamagePoints属性)、逃げるための移動速度(MaximumSpeedPoints属性)に多くのポイントを割り振った。特に、視野の広さは、食料となる植物を探すうえでも必要になるため、全体の半分となる50ポイントを割り振っている。そのほか、蓄えることのできるエネルギーの最大値を決める体力(MaximumEnergyPoints属性)にもポイントを割り振った。食料にありつけない状態が多少続いたとしても、あらかじめエネルギーが蓄えられている状態であれば、生き延びることができるからである。

 偽装能力(CamouflagePoints属性)にまったくポイントを割り振らなかったのは、偽装がほかに比べて重要でないと考えたからだ。確かに、場合によっては偽装も有効であるが、偽装してもほかの生物に見つかるときは見つかるものだ。このポイントが0であっても、まったく偽装できないわけではないので、あえて偽装能力にはポイントを割り振らなかったのである。また、植物は急いで食べなくてもなくならないと判断し、植物を食べる速さ(EatingSpeedPoints属性)にもポイントを割り振らなかった。

 ポイント配分の説明が長くなってしまったが、次の行の説明に移ろう。CarnivoreAttributeは、肉食動物か草食動物かを指定する属性である。Carnivoreは「肉食動物」の意味であるから、草食動物の場合はこの属性にfalseを指定することになる。

 最後の行の[MatureSize(25)]は、動物の大きさの指定である。見てのとおり、ここでは25を指定している。このアトリビュートに指定できる値は25から48までの整数で、数値が大きいほど成熟したときの動物の半径も大きい。ここでの設定は、成熟したときの動物の大きさが最小であることを示している。

 一般に大きい動物は、小さい動物に比べて攻撃力、防御力などの戦闘能力が高い。また、一定時間に消費するエネルギーは大きくなるものの、貯めておくことのできるエネルギーも大きい。しかし、MatureSizeを大きくすると、その大きさにまで生物が成長するのには時間がかかってしまう。従って、生物が次の世代を繁殖するまでにかかる時間も長くなってしまうというわけだ。そのため、ここではなるべく早く繁殖活動に入れるように小さな数値を設定した。

 なお、動物の半径と書いたが、テラリウムの座標系においては、動物は円ではなく正方形であるものとして扱われることになっている。これについては、次回以降で座標系の説明をするときに一緒に話すことにしよう。

攻撃対象を判定するIsBrunt

 草食動物は、基本的にほかの動物を攻撃する必要がないわけであるから、すべての動物を攻撃しないというのも1つの手ではある。そのようにしたい場合、このメソッドには“return false;”という1行を書くだけでよい。

 ただ、それでは面白くないので、今回のTabataではほかの動物も少しは攻撃することにした。方針は次のとおりだ。

  • 自分自身と同じ種である動物と、すでに死んでいる動物は攻撃対象としない。
  • 寿命などの関係で、子孫を残すことができない時期に達したときは、敵が強いか弱いかには関係なくほかの生物を攻撃対象とする。ほかの生物の邪魔をしようというわけだ。
  • そうでない場合は、敵が十分に近くにいて、かつ勝算がある場合に限って攻撃対象とする。

 さて、うえに示した方針をコードの形で書くと次のようになる。

protected override bool IsBrunt(OrganismState target) {
  AnimalState a = target as AnimalState;
  if(a == null) return false;
  if(IsRetire) {
    return !IsMySpecies(target) && target.IsAlive;
  }
  return
    !IsMySpecies(target) &&
    target.IsAlive &&
    CanWin(a) &&
    DistanceTo(target) < distToBeBrunt;
}
パラメータで与えられた生物が攻撃対象となるかを判定するIsBruntメソッド

 IsRetireは、このTabataクラスで用意したプロパティだ。すでに子孫が残せない時期になるとtrueとなるようにしている。IsMySpeciesは、引数に渡した生物が自分自身と同じ種であればtrueを返すメソッド、IsAliveはその生物が生きているときにtrueになるプロパティ、CanWinはKAnimalクラスで定義されているメソッドで、引数に渡した動物と戦闘をしたときに、その動物に勝てる見込みがあるかどうか返す。そして、DistanceToは、自分から指定した生物までの距離を返すメソッド、distToBeBruntはこのクラスで用意したフィールド(現行では定数を格納している)で、生物との距離がこのフィールドの値より小さければその生物に攻撃をしかけようというわけだ。

 IsRetireの中身についてもここで触れておこう。

protected bool IsRetire {
  get {
    return Species.LifeSpan - State.TickAge < State.ReproductionWait;
  }
}
生物がすでに出産が可能な年齢を超えているかを判定するIsRetireメソッド

 Speciesは、その生物の「種」に関する情報が格納されているISpecies型のオブジェクトを得るためのプロパティだ。LifeSpanはそのISpeciesインターフェイスのプロパティで、その動物が生存することのできる全ティック数を表す。TickAgeはOrganismStateクラスのプロパティで、自分の年齢をティック数単位で表したものである。つまり、自分が生まれてからその時点までのティック数に等しい。従って、不等式の左辺(Species.LifeSpan - State.TickAge)は、その動物が寿命を迎えるまでの残りティック数を表している。

 一方、右辺のReproductionWaitは、OrganismStateクラスのプロパティで、次の生殖活動に入ることができるようになるまでのティック数を表す。Terrariumの生物は、いったん生殖活動を終えるとそのあとしばらく生殖活動ができなくなる。その間隔は環境や生物の半径などによって決まるのだが、次の生殖活動ができるようになるまでの残りティック数が、このプロパティで表されるようになっている。いい換えれば、このプロパティが0になるまで次の生殖活動ができないということになる。

 すなわちこのプロパティでは、次の生殖活動ができるようになるまでに寿命を迎えるかどうかを判定しているのである。


 INDEX
  テラリウム徹底攻略ガイド(改訂版)
  第4回 KAnimalクラスを使った草食動物の作成
     KAnimalクラスとは
   草食動物を作成する(1)
     草食動物を作成する(2)
     草食動物を作成する(3)
     KAnimalクラスのプロパティとメソッド
     KAnimalクラスで処理しているイベント(1)
     KAnimalクラスで処理しているイベント(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 記事ランキング

本日 月間