Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I want to make a game where you have to run over a bunch of zombies with your car. When moving around, the zombies have a few things to take into consideration:

  • When there's no player around they might just roam about randomly. And even when some other component dictates a specific direction, they should wobble to the left and right randomly (like drunk people). This implies a small, random, deviation in their movement.
  • They should avoid static obstacles. When they see they are headed towards a wall, they should reorient themselves.
  • They should avoid the car. They should try to predict where the car will be based on its velocity and try to move out of the way.
  • When they can, they should try to get near the player.

All these types of decisions they have to do seem like they should be implemented in different components. But how should I manage them? How can I give different components different weights that reflect the importance of each decision (in a given situation)?

I would need some other component that acts as a manager, but do you have any tips on how I should implement it? Or maybe there's a better solution?...

share|improve this question
2  
First things first. There are approximately one megazillion "component based" ways of designing code, which one are you using? –  Patrick Hughes Jun 22 '12 at 19:26
    
@PatrickHughes I'm using Unity. –  Paul Manta Jun 22 '12 at 20:14
    
I've added "unity" and "AI" to your tags with the hope that it brings in experienced answers because Unity is a popular kit. –  Patrick Hughes Jun 22 '12 at 20:53
1  
I'm not really sure if you need different component for that matter. –  Ali.S Jun 22 '12 at 21:10
add comment

2 Answers

up vote 1 down vote accepted

First of all, you need to separate the AI and the actions the creature can take. The "wobbliness" you desire can be implemented in a MoveForward function, relieving the AI from having to worry about it.

Secondly, I recommend a behavior-based AI. You keep a list of behaviors, probably subclasses of a BaseBehavior object, sorted in the order of importance. In your case, it'd probably be something like the following:

  • Kill player
  • Avoid car
  • Avoid wall
  • Move towards player
  • Wander

Each behavior would have a function called WantsActive, which would return true if the behavior needed to be used. (For example, KillPlayerBehavior would only return true when the player was in range.) Every time Update is called, you loop through the list of behaviors, calling WantsActive on each and stopping when one returns true.

This one would have its Execute function called, resulting in the creature performing that behavior. If you wanted it to be able to perform multiple behaviors in one frame, you could even check the return value of Execute, with true meaning "no more actions" and false meaning "continue with next behavior." When the manager got false in this case, it'd just resume the WantsActive loop where it left off.

This approach is nicely object-oriented, it avoids hard-coding behaviors within the Creature class, and it is very easily extendable with new behavior classes, even at runtime. The same manager can work with any number of different behavior combinations.

You might want to Google subsumption architecture.

share|improve this answer
add comment

This is a very simplistic finite-state machine solution (ZombieBrainModule.Update() specifically) set up in a components-based style, but it should get you on the right track. Note that I use the word "module" and not "component" below so as to avoid confusion with Unity's built-in components, which as gajet suggested, are not needed.

using UnityEngine;

//drop this on each zombie-representative GameObject in the Unity IDE
public class ZombieController : MonoBehaviour
{
    ZombieBrainModule ai;
    LifeModule life;
    WeaponModule weapon;
    //etc.

    void Start()
    {
        ai = new ZombieBrainModule(this.transform, life, weapon);
    }

    void Update()
    {
        ai.Update(); //think about what I, Zombie, intend to do (in this case, motion + weapon actions) and store these
        life.Update(); //eg. for regeneration?
        //etc.
    }

}

public abstract class Module
{
    public abstract void Update();
}

using UnityEngine;

public class ZombieBrainModule
{
    private LifeModule life;
    private WeaponModule weapon;

    public ZombieBrainModule(this.transform, life, weapon);
    {
        this.life = life;
        this.weapon = weapon;
        this.transform = transform;
    }

    public void Update()
    {
        //Pseudocode; a very simplistic finite state machine.

        if near a wall
            avoid nearest wall;
        else
            if player nearby
                if player in car
                    run away from player;               
                else
                    if life.remaining > 25% //clever zombie!
                        go toward player;
                        if player within firing range
                            weapon.fire;
                    else
                        run away from player;
            else
                wander;
    }
    //to keep things simple, I avoided heavy class hierarchies, but you could easily use a base Entity class which holds refs to the various modules, from which Zombie and Player would derive.

Note This excludes the zombie from avoiding walls when he is doing something else. If you want wall avoidance to also happen whilst the zombie is avoiding the player or chasing them, you will need to take some sort of an average of the two vector directions the zombie is being pulled toward. For instance, you might aim for a total float weighting of 1.0f, so you apply your wall avoidance weighted as 0.3f of that, and your player seek (or avoid) as 0.7f of that. After normalising the influence vectors (call 'em wallInfluence and playerInfluence), multiply each respective one by it's fractional weight, then sum the two vectors for the final motion vector by which you will update your zombie's transform.position. Some of these influence weights may vary continuously based on other factors, eg. proximity to the player or his one-and-a-half tons of roaring 70's muscle car.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.