Friday, September 16, 2011

roguelike tutorial 09: wandering monsters

We need some monsters to wander around our caves. How about some fast moving bats?

First let's add some default movement behavior to the CreatureAi.

public void onEnter(int x, int y, int z, Tile tile){

if (tile.isGround()){

creature.x = x;

creature.y = y;

creature.z = z;

} else {

creature.doAction("bump into a wall");

}

}


Let's also give it a method of moving randomly. This common behavior can be called by any subclass.

public void wander(){

int mx = (int)(Math.random() * 3) - 1;

int my = (int)(Math.random() * 3) - 1;

creature.moveBy(mx, my, 0);

}


Now the ai for our bats.

package rltut;



public class BatAi extends CreatureAi {



public BatAi(Creature creature) {

super(creature);

}



public void onUpdate(){

wander();

wander();

}

}


We could set up a system for dealing with different monster speeds but this is simple enough: bats move twice for every one of your moves. Easy to implement, easy to understand.

Now we add bats to our CreatureFactory. I picked some low hp and attack so they could nibble on you a bit but shouldn't be too much of a problem.

public Creature newBat(int depth){

Creature bat = new Creature(world, 'b', AsciiPanel.yellow, 15, 5, 0);

world.addAtEmptyLocation(bat, depth);

new BatAi(bat);

return bat;

}


And in our PlayScreen we need to update createCreatures. How about 20 bats per level?

for (int i = 0; i < 20; i++){

creatureFactory.newBat(z);

}


And now that our player is in some danger of being killed, let's add a check after the world get's updated.

if (player.hp() < 1)

return new LoseScreen();


Try it out. You should see bats being flying about and being batty.


If you run this you'll soon notice that the bats drop dead from attacking each other or even attacking themselves. Suicide bats are funny but they quickly go extinct.

Let's add a check to the first line of the moveBy method in the Creature class. It should bail out early if we're not actually moving. This will take care of creatures killing themselves when all they want to do is stand in one place.

if (mx==0 && my==0 && mz==0)

return;


Creatures should also be able to see what other creatures are in the world so the CreatureAi can know what's going on.

public Creature creature(int wx, int wy, int wz) {

return world.creature(wx, wy, wz);

}


We can now improve the CreatureAi wander method to make sure creatures don't fight other's like them.

public void wander(){

int mx = (int)(Math.random() * 3) - 1;

int my = (int)(Math.random() * 3) - 1;



Creature other = creature.creature(creature.x + mx, creature.y + my, creature.z);



if (other != null && other.glyph() == creature.glyph())

return;

else

creature.moveBy(mx, my, 0);

}


You could also make it keep trying until mx != 0 && my != 0, that way it would never stand in the same spot. You may want to make sure it doesn't try to move into a wall or make it able to go up or down stairs.

And there you go. You now have some deep and bat-filled caves to explore.



Using the glyph in messages is lame; Creatures should have a name.

private String name;

public String name() { return name; }


Using constructor injection, update the creatureFactory to pass in the appropriate name. Finally, update any messages that used the creature's glyph to now use the creature's name.

Much better.

download the code

No comments:

Post a Comment

Popular Posts