HTML5 Game Development Blog

  • Tiled Game Engine slide



Game AI – basic unit behavior (ramble)

Category : Tiled Game Engine Apr 15th, 2015

Pages: 1 2

Basic game AI
Units is a key stone of any RPG game. They can have different roles, like traders, beckoning customers, regular citizens, loitering around the neighborhood, guards to protect the peace of inhabitants and etc. In most cases all that roles is managed by game AI, that is intended to generate some behavior patterns for units. Let’s create some.

To start we need to define some properties for out units, so that Game Engine can bind behavior pattern to them. To do so we introduce new property in the unit object called behavior:

Game AI: unit behavior

Setting unit behavior in Tiled Map Editor

There are 2 pre-defined behavior patterns in the Tiled Game Engine:

  • ramble – defines a simple random unit movement in defined area
  • guard – defines a simple guard behavior. Until guard area is not trespassed unit behaves as “ramble” unit – navigates inside guard zone. As soon as unit will detect breach of guard zone it will switch to worried”  mode navigate to violator and attack it.

So, let’s start with code structure and define, how to link behavior pattern with certain unit.

Defining behavior pattern

We use class factory pattern, like we did it for entities. This factory is very simple, but will allow us to abstract unit from certain AI name.

AI factory

The code for AI factory is following:

    /** @constructor */
    function AI() {};

    /**
     * Register new behavior pattern for further usage
     * @param   {String}    name    AI behavior pattern name name
     * @param   {AIPattern} gears   AI behavior class to register
     */
    AI.prototype['register'] = function(name, gears) {
        this[name.toLowerCase()] = gears;
    };

    /**
     * Link AI behavior pattern with entitiy.
     * @param   {Entity}    entity  Entity object to link
     * @param   {String}    name    AI behavior pattern name
     * @param   {Array}     args    Initialization arguments for AI pattern
     * @return  {Boolean}   TRUE on success, FALSE otherwize
     */
    AI.prototype['bind'] = function(entity, name, args) {
        if (!entity) return false;
        name = name.toLowerCase();
        if (!this[name]) return false;

        return this[name]['bind'](entity, args);
    };

Very simple. but very powerful. So, if required game AI is registered in the factory it will be linked with certain entity. Now, let’s modify entity code, so it starts to respect game AI field.

Link entity with AI

Behavior property is common for any entity and we should made changes in the base Entity class:

Entity.prototype.init = function(data, assetManager, map) {
    ...
    // get custom properties
    if (data['properties']) {
        ...
        if (data['properties']['behavior']) {
            // behavior pattern
            if (TGE.AI) {
                // split string representation of arguments to regular array
                var b = data['properties']['behavior'].split('(');

                if (b.length > 1) {
                    b[1] = b[1].split(')')[0].split(',');
                }

                // set "brains" for that entity
                TGE.AI.bind(this, b[0], b[1]);
            }
        }
    }
    ...
};

Now, if we define behavior property for certain unit and that behavior pattern is registered Tiled Game Engine will automatically set some “brains” for that unit.

Simple game AI pattern – ramble

Ramble is the easiest game AI pattern, that we can imagine, but it will allows us develop AI pattern technology for our Game Engine.

We can create AI pattern in different way. 2 options came in mind, with its pros and cons:

  1. Extend in run time entity instance with some AI gears;
  2. Create some namespace with logic and monitor entity events.

Extending entity object, from JavaScript perspective modifying object will generate new hidden classes and will cause opp-code deoptimization. This may be acceptable if we are not targeting for high performance, but not in our case. From other side that approach is easy to code and debug, as far it strictly linked with certain entity instance. For ramble AI pattern, when our units will not cooperate with each other this is acceptable, but for other cooperative units it will bring some extra, non-intuitive code to link units.

Creating namespace with AI logic, but not linked directly with entity is better way, from our point of view. This will eliminate us from hidden classes and will made it easy to create cooperative AI. But from other side it harder to code and debug. at least from first glance. In Tiled Game Engine it is up to game developer to choose how to make it’s AI. We use 2nd way – defining namespace.

In any case AI pattern class should implement one method interface:

    function AIPattern() {
    };

    AIPattern.bind = function(ent, args) {
        if (!args) args = [];

        _ents[ent['id']] = {args: args}
        return true;
    };

    TiledGameEngine.AI.register('AIPattern', AIPattern);

Pages: 1 2

SHARE :

Leave a Reply

Your email address will not be published.


Like it? Share It!

We're making our best to provide good and valuable content. Please help us by clicking on one of the social icons, thanks for everything.