What if? What if? What if? What if? What if?
That quickly became my mantra.
When implementing any kind of enemy behavior, simple or no, you wind up asking yourself "What if?" a lot.
And not just "What if?". You have to think about a lot of things. I'm always reminded of Liz England's excellent The Door Problem on what game designers actually do all day. There's just a lot of stuff to consider. And when one small part of it doesn't work, it all comes crashing down.
In coming up with behavior for my generic monster type I had two basic states in mind:
- The monster had to wander around the map in a seemingly aimless manner, yet also slowly make his way towards the village.
- When close to a villager or building, go destroy it.
For the first state, I already had some experience with this very behavior from my game Truffle Shuffle. (WARNING: doesn't work in Win8 for some reason...) In it, the trippy shroom clouds float around the level and eventually make their way to your base to damage it. The logic is pretty simple. For 80 percent of the time, the cloud will choose a random direction to move. The other 20 percent has the cloud moving towards the base.
With that as my starting place I created a case statement to fire off every 2 seconds or so. It has three states: wander aimlessly, head to the town center, and go idle. The idea here is to give a sense that the monsters are just doing their thing, and yet they will eventually force a confrontation with the player. I can tweak the percentages to get more or less aggressive monster types. Right not the idle state doesn't appear to do much, but when animations are in, they could growl, look about, scratch an itch, etc.
The resulting behavior is pretty good. I set the time interval between changing states to be based on distance traveled (which is assigned through a random_range). This way the monster doesn't walk the same distance each time.
Random distance and direction is accomplished by picking a point on a circle of a random size around the monster. Here's the script:
//move in a random direction.
point = irandom(360);
radius = random_range(50,100);
radius = floor(radius);
targetX = x + lengthdir_x(radius,point);
targetY = y + lengthdir_y(radius,point);
targetX = floor(targetX);
targetY = floor(targetY);
//check to make sure destination is within the room boundaries.
if(targetX>0 && targetX<room_width && targetY>0 && targetY<room_height)
moving = true;
move_towards_point(targetX, targetY, GameControl.monsterSpeed);
event_user(0); //not a valid destination. Try again!
There's a conditional in the step event (AKA the update function for your non Game Maker people) that checks to see of you've reached the destination and re-fires the case statement to give the monster new orders:
dist = point_distance(x,y,targetX,targetY);
if(dist < 5)
moving = false;
speed = 0;
This all came together pretty fast. I should have known the other part would be far more complicated.
What if? What if? What if? ...