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

KAnimalクラスのプロパティとメソッド

泉 祐介+デジタルアドバンテージ
2002/05/25

KAnimalクラスのプロパティとメソッド

 ここまで、KAnimalクラスの中身にはあまり触れずに草食動物を1つ作成してみたわけだが、ここでKAnimalクラスの中身についても触れていくことにする。

移動を開始するBeginMovingメソッド

 BeginMovingメソッドは、もともと既存のAnimalクラスにあるメソッドであるが、先に述べたとおりKAnimalクラスでオーバーロードをしている。

 コードはこんな感じだ。

protected void BeginMoving(Point point,int speed) {
  if(moveCount > 0) return;
  lastDest = point;
  speed = SpeedCheck(speed);
  point = RangeCheck(point);
  base.BeginMoving(new MovementVector(point,speed));
}

protected void BeginMoving(Point point) {
  BeginMoving(point,FavSpeed);
}

protected void BeginMoving(OrganismState os) {
  BeginMoving(os.Position,FavSpeed);
}
AnimalクラスのメソッドをオーバーライドしたBeginMovingメソッド

 コードを見れば分かるが、最初のメソッドが基本的なものになっている。このメソッドでは、MovementVectorの代わりに目的地と速さを直接指定するようになっている。SpeedCheckは、指定された速さが、その動物の移動速度として許容される範囲内にあるかどうかを調べるメソッド、RangeCheckは指定した目的地が世界の中にあるかどうかを調べるメソッドである。

 2つ目のメソッドは目的地だけを指定した場合で、この場合は速度として先に解説したFavSpeedプロパティを使う。また、3つ目のメソッドは目的地の代わりに目標物として生物を指定するもので、先の草食動物を作成する際に使ったのはこのメソッドだ。

 ちなみに、SpeedCheckとRangeCheckの定義は次のようになっている。

protected int SpeedCheck(int speed) {
  return (speed > Species.MaximumSpeed) ?
    Species.MaximumSpeed : (speed < 2) ? 2 : speed;
}

protected Point RangeCheck(Point o) {
  int nx = o.X;
  int ny = o.Y;
  nx = (nx < 0 ? 0 : nx);
  nx = (WorldWidth <= nx ? WorldWidth-1 : nx);
  ny = (ny < 0 ? 0 : ny);
  ny = (WorldHeight <= ny ? WorldHeight-1 : ny);
  return new Point(nx,ny);
}
指定された速度と目的地をチェックする2つのメソッド

敵から逃げるRunAwayメソッド

 RunAwayは、指定した動物から遠ざかるためのメソッドである。方針は単純で、指定された動物のいる方向と反対の方向に移動を始めるだけだ。ただし、その動物との距離に応じて、速度は変えることにし、特に敵がうんと近づいてきた場合は、全力疾走で逃げるようにした。

protected void RunAway(AnimalState target) {
  Vector vector = Vector.Subtract(target.Position,Position)
    .GetUnitVector().Scale(300);
  int speed = FavSpeed;
  if(DistanceTo(target) < distToThreat2) {
    speed = Species.MaximumSpeed;
  } else if(DistanceTo(target) < distToThreat1) {
    speed = target.Speed+2;
  }
  BeginMoving(Vector.Add(Position,vector) ,speed);
}
敵から逃げるために移動を開始するRunAwayメソッド

 最初の行でVectorクラスというのが登場したが、これは数学や物理でいうところの2次元ベクトルを扱うクラスだ(Javaなどでいうところのベクトルとは異なるので注意してほしい)。このクラスの詳しい使い方はTerrariumオブジェクト・モデルに譲ることにするが、この行では指定された動物のいる方向とは反対の方向をさすベクトルを作成している。

 ベクトルの大きさは、あたりさわりのない数値として300にした。最後の行で、現在の位置にこのベクトルの値を加えて目的地としているのだが、あまり小さな数値を指定すると、誤差などで方向が不正確になりやすい。かといって、あまり大きな数値にしてしまうと、すぐに目的地がテラリウムの世界の外になってしまう。すると、先に説明したRangeCheckの丸めの影響で、移動する方向が本来求める方向からずれてしまうのだ。

 続くif文は移動する速さを設定する部分だ。distToThreat1、distToThreat2はいずれもKAnimalクラスの内部で定義されているフィールドで、どのくらいの距離をもって動物が近づいていると見なすかを決める値である。相手との距離がdistToThreat1を下回ったときは対象となる動物がそこそこ近づいていることを、distToThreat2を下回ったときは、うんと近づいていることをそれぞれ表す。MaximumSpeedはIAnimalSpeciesインターフェイスのプロパティで、その生物が移動するときに出すことのできる最大の速さである。

 最後の行で、最初に求めたベクトルを使って、動物と反対方向に移動を開始している。先にも述べたが、自分の現在位置に移動したい方向(と大きさ)を持つベクトルを加えると、目的地を計算することができる。

 さて、すでに気付かれた読者もいるかもしれないが、引数には動物を1つしか指定できないので、複数の動物にはさまれているときなどには対処できていないのがこのメソッドの難点である。さらにいえば、先に作成した草食動物Tabataも、このメソッドを単純に使っているだけなので、脅威となる動物が複数いるときには対処できない。

勝てるかどうかを判定するCanWinメソッド

 これは、指定した動物と戦闘したときに、勝てそうかどうかを調べるメソッドだ。コードは次のようになっている。

protected virtual bool CanWin(AnimalState a) {
  if(a == null) return false;
  return 0.5 * LeftTicks(State,a) > LeftTicks(a,State);
}
勝てるかどうかを判定するCanWinメソッド

 “LeftTick(動物A,動物B)”は、動物Aが動物Bから攻撃を受け続けたときに、動物Aが何ティック耐え続けられるかを計算し返すメソッドだ。このCanWinメソッドは、お互いに攻撃し続けたときに、こちらが敵よりも長く生存できるときにtrueを返すようにしている。ただし、少し余裕を取る意味で、自分が生存できるティック数の方には0.5を掛けた。

 ちなみに、LeftTicksメソッドの定義は次のようになっている。

static private double LeftTicks(AnimalState a, AnimalState b) {
  int aHitpoint =
    EngineSettings.DamageToKillPerUnitOfRadius * a.Radius - a.Damage;
  int bAttackpoint =
    b.AnimalSpecies.MaximumAttackDamagePerUnitRadius * b.Radius;
  int aDefendpoint =
    a.AnimalSpecies.MaximumDefendDamagePerUnitRadius * a.Radius;
  return aHitpoint / Math.Max(1, bAttackpoint - aDefendpoint);
}
攻撃を受け続けた場合に何ティック耐えられるかを計算するLeftTicksメソッド

 詳しい計算の内容についての説明は割愛するが、aHitpoint、bAttackpoint、aDefendpointにはそれぞれ動物aのヒット・ポイント(ダメージに対する耐久力)、動物bの攻撃力、動物aの防御力がそれぞれ格納されるようになっている。最後のreturn文で、これらの値を基に生存できるティック数を求めている。

ランダムに移動するWanderメソッド

 Wanderは周りに食料などが何もないときに、食料を求めて移動したいときに使うメソッドだ。

 といっても、現在の実装ではランダムに目的地を選んで、そこに移動をさせているだけだ。コードは次のとおり。

protected void Wander(int speed) {
  if(IsMoving) return;
  int RandomX = OrganismRandom.Next(0, WorldWidth - 1);
  int RandomY = OrganismRandom.Next(0, WorldHeight - 1);
  BeginMoving(new Point(RandomX,RandomY), speed);
}

protected void Wander() {
  Wander(FavSpeed);
}
ランダムに目的地を決め、移動を開始するWanderメソッド

 IsMovingは、その動物が移動中であるかどうかを調べるAnimalクラスのメソッドである。OrganismRandomは生物に固有の乱数を発生させるためのクラスで、ここでは0からWorldWidth-1の範囲の乱数、0からWorldHeight-1の範囲の乱数を順に生成している。WorldWidthとWorldHeightはフィールド(陸地)の幅と高さを示しているAnimalクラスのプロパティだ。


 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 記事ランキング

本日 月間