与Robocode不同的是,你可以把多个生态圈组成一个大的生态系统。动物可以借助一个叫teleporter(它看上去像一个在生态系统范围内滚动的蓝色大球)的东西从一个生态圈迁徙到另外一个生态圈。任何与teleporter接触的生物都会传输到另外一个生态圈中去。
理论上,一种生物取得成功的标志就是它占据了整个生态圈。我对此很感兴趣,不过要牢记的一点就是,如果某种生物种群壮大到吃完所有的食物来源时,那么它们的好日子也就快到尽头了。你所创建的生物应该善于捕获食物,但同时也要给它的猎物留下足够的生长和繁殖的机会。
另外你还要注意:在引入草食动物之前,你应该保证至少生态圈已经有了一种植物;如果你想引入肉食动物,那么生态圈至少应该已经有了一种草食动物和一种植物。如果你创造的生物企图破坏游戏规则,那么它将抛出一个例外来终止这种行为。
创建一种新植物或者动物的最简单方法就是找到一个现成的类并以它为模板。例如,下面的代码可以创建一种最简单的肉食动物,代码来源于Terrarium主页:
using System;
using System.Drawing;
using System.Collections;
using System.Reflection;
using System.IO;
[assembly: OrganismClass("Barracuda")]
[MatureSize(30)]
[CarnivoreAttribute(true)]
[AnimalSkin(AnimalSkinFamilyEnum.Beetle)]
[MarkingColor(KnownColor.Red)]
[MaximumEnergyPoints(0)]
[EatingSpeedPoints(0)]
[AttackDamagePoints(30)]
[DefendDamagePoints(20)]
[MaximumSpeedPoints(30)]
[CamouflagePoints(0)]
[EyesightPoints(20)]
public class Barracuda : Animal {
AnimalStatetargetAnimal;
ArrayListfoundAnimals;
protected override void Initialize() {
Idle += new IdleEventHandler(IdleEvent);
MoveCompleted += new MoveCompletedEventHandler(MoveCompletedEvent);
}
void IdleEvent(object sender, IdleEventArgs e) {
try {
WriteTrace("Idle");
if(CanReproduce)
BeginReproduction(null);
if ( IsAttacking || IsMoving
|| IsEating ) {
return;
}
if(targetAnimal == null) {
targetAnimal
= FindNewTarget(false, double.MaxValue);
} else {
targetAnimal
= (AnimalState) LookFor(targetAnimal);
}
if(targetAnimal != null )
{
if
( !Is
if ( State.EnergyState < EnergyState.Full && !targetAnimal.IsAlive)
{
BeginEating(targetAnimal);
}
else {
//
Find new undead target if available
}
}
else {
MoveToTarget();
}
}
}
} else {
//
No animal to smack down
StopMoving();
// Hibernate
}
foundAnimals = null;
} catch(Exception exc) {
WriteTrace(exc.ToString());
}
}
void RefreshTarget() {
if ( targetAnimal == null
) {
return;
}
AnimalStatenewState = (AnimalState)
LookFor(targetAnimal);
if(newState != null) {
targetAnimal
= newState;
} else {
targetAnimal
= null;
}
}
AnimalStateFindNewTarget(boolmySpecies, double min)
{
if ( foundAnimals == null
) {
foundAnimals
= Scan();
}
double minDistance = min;
AnimalStatepossibleTarget
= null;
if(foundAnimals.Count >
0) {
//
Always move after closest animal if there is one
foreach(OrganismStateorganismState
in foundAnimals) {
if(organismState
is AnimalState && IsMySpecies(organismState) ==
mySpecies) {
if(DistanceTo(organismState) < minDistance) {
possibleTarget
= (AnimalState) organismState;
minDistance
= DistanceTo(organismState);
}
}
}
}
return possibleTarget;
}
void MoveToTarget() {
if ( targetAnimal == null
) {
return;
}
// Go as fast as we can, as
long as we only burn half of our stored
energy
intpossibleSpeed = 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));
}
void MoveCompletedEvent(object sender, MoveCompletedEventArgs
e) {
WriteTrace("Move Completed");
try {
RefreshTarget();
if
( targetAnimal != null ) {
if
( targetAnimal.IsAlive ) {
if(WithinAttackingRange(targetAnimal)) {
if
( State.EnergyState < EnergyState.Full ) {
BeginAttacking(targetAnimal);
}
}
else {
MoveToTarget();
}
}
else {
if
( WithinEatingRange(targetAnimal) ) {
if
( State.EnergyState < EnergyState.Full ) {
BeginEating(targetAnimal);
}
}
else {
MoveToTarget();
}
}
}
} catch(Exception exc) {
WriteTrace(exc.ToString());
}
}
public override void SerializeAnimal(MemoryStream
m) {
// Don't care about state. My
animals are smart
}
public override void DeserializeAnimal(MemoryStream
m) {
// Don't care about state. My
animals are smart
}
)