using System; using System.Drawing; using System.Collections; using System.Reflection; using System.IO; [assembly: OrganismClass("KSK")] [assembly: AuthorInformation("keisuke", "mail@tmepuri.org")] // 動物のサイズは小さめに [MatureSize(30)] // trueならば肉食動物 [CarnivoreAttribute(true)] // 動物の外見はサソリを選択 [AnimalSkin(AnimalSkinFamilyEnum.Scorpion)] // 全体図に表示される色(未実装?) [MarkingColor(KnownColor.Yellow)] // 移動距離が長くなることを想定して体力は多めに [MaximumEnergyPoints(10)] // 襲われる可能性は無視してゆっくり食べる [EatingSpeedPoints(0)] // 手早くしとめないと逃げられることがあるので // 攻撃力は高めに [AttackDamagePoints(40)] // 防御力0。やられる前にやれ [DefendDamagePoints(0)] // フィールドが混み合っていれば、簡単に獲物を追い // つめられるので、移動速度は低めに [MaximumSpeedPoints(20)] // 偽装能力0。丸見え [CamouflagePoints(0)] // 視界が狭いとあてずっぽうで獲物を探さなければ // ならないので、少し多めに [EyesightPoints(30)] // 草食動物と肉食動物はどちらもAnimalクラスの // サブクラスとして実装する public class KSK : Animal { AnimalState targetAnimal = null; int wanderingCount = 0; Vector wanderingVector = null; //イベントハンドラの登録 protected override void Initialize() { Idle += new IdleEventHandler(IdleEvent); MoveCompleted += new MoveCompletedEventHandler(MoveCompletedEvent); } // Idleイベントハンドラ。定期的に呼び出される void IdleEvent(object sender, IdleEventArgs e) { try { // 可能ならば出産する。出産する条件は成人して // いること、体力が十分あること、以前出産して // から十分時間が経過していること if (CanReproduce) { BeginReproduction(null); WriteTrace("Reproduction"); } // 行動中ならば何もしない if (IsAttacking || IsEating || IsMoving || State.EnergyState > EnergyState.Normal) { return; } // 獲物がいなければ探す。すでにターゲットを見つ // けていれば、最新の情報(座標など)を取得する if (targetAnimal == null) { targetAnimal = FindNewTarget(false, double.MaxValue); } else { targetAnimal = (AnimalState) LookFor(targetAnimal); } // ターゲットがいれば攻撃するか、食べるか、隣接する // まで移動する。いなければ、ランダムに移動する if (targetAnimal != null ) { if (!AttackOrEat()) { if (!IsMoving) MoveToTarget(); } } else { if (!IsMoving) BeginWandering(); } } catch(Exception ex) { WriteTrace(ex.ToString()); } } // ターゲットに関する最新の情報を取得する void RefreshTarget() { if ( targetAnimal == null ) return; targetAnimal = (AnimalState) LookFor(targetAnimal); } // 視界内でもっとも近くにいる獲物をターゲットにする AnimalState FindNewTarget(bool mySpecies, double min) { ArrayList foundAnimals = Scan(); double minDistance = min; AnimalState possibleTarget = null; int count = 0; if (foundAnimals.Count > 0) { foreach (OrganismState organismState in foundAnimals) { if (organismState is AnimalState && IsMySpecies(organismState) == mySpecies) { count++; if (DistanceTo(organismState) < minDistance) { possibleTarget = (AnimalState) organismState; minDistance = DistanceTo(organismState); } } } } // トレースウィンドウにデバッグメッセージを出力する WriteTrace("FindNewTarget: " + count.ToString()); return possibleTarget; } // 指定した動物のそばへ移動する void MoveToTarget() { if ( targetAnimal == null ) { return; } // 残り体力を考慮して移動速度を決める int possibleSpeed = Species.MaximumSpeed; while(possibleSpeed > 2 && State.EnergyRequiredToMove(possibleSpeed, possibleSpeed) > (State.StoredEnergy / 2)) { possibleSpeed /= 2; } if (possibleSpeed < 2) possibleSpeed = 2; BeginMoving(new MovementVector(targetAnimal.Position, possibleSpeed)); } // MoveCompletedイベント。移動終了すると呼び出される。 void MoveCompletedEvent(object sender, MoveCompletedEventArgs e) { WriteTrace("Move Completed"); try { RefreshTarget(); // 障害物にあたって止まったのか、目的地に到着したのか if (e.Reason == ReasonForStop.Blocked) { if (targetAnimal != null) { if (!AttackOrEat()) { MoveToAvoid(e); } } else { wanderingCount = 0; BeginWandering(); } } else { if (targetAnimal != null) { if (!AttackOrEat()) { MoveToTarget(); } } else { targetAnimal = FindNewTarget(false, double.MaxValue); if (targetAnimal == null) { BeginWandering(); } else { MoveToTarget(); } } } } catch (Exception ex) { WriteTrace(ex.ToString()); } } // 近くに獲物がいないときは、ランダムに移動する void BeginWandering() { if (wanderingCount < 1 || wanderingVector == null) { WriteTrace("New Direction"); wanderingCount = 10; wanderingVector = new Vector( 20 * (OrganismRandom.Next(0, 3) - 1), 20 * (OrganismRandom.Next(0, 3) - 1)); } else { wanderingCount--; } Point newDest = Vector.Add(Position, wanderingVector); BeginMoving(new MovementVector(newDest, 3)); } // 近くに獲物がいれば、生きていれば攻撃し、 // 死んでいれば食べる bool AttackOrEat() { bool action = false; if (!IsEating && !IsAttacking ) { if (targetAnimal.IsAlive && WithinAttackingRange(targetAnimal)) { action = true; if (State.EnergyState < EnergyState.Normal) { WriteTrace("Attack"); BeginAttacking(targetAnimal); } } else if (!targetAnimal.IsAlive && WithinEatingRange(targetAnimal) && State.EnergyState < EnergyState.Full) { WriteTrace("Eat"); BeginEating(targetAnimal); action = true; } } return action; } // 障害物を回避するアルゴリズム。いろいろ試したあげく // ランダムに移動して距離を置くシンプルな解法で様子見 void MoveToAvoid(MoveCompletedEventArgs e) { try { WriteTrace("Avoid"); targetAnimal = null; wanderingCount = 2; BeginWandering(); } catch (Exception ex) { WriteTrace(ex.ToString()); } } // Terrariumを保存、再開するときに呼び出されるメソッド // 保存すべき状態情報がなければ、空でかまわない public override void SerializeAnimal(MemoryStream m) { } public override void DeserializeAnimal(MemoryStream m) { } }