Jump to content

Delay enemy actions


ChrisC14
 Share

Recommended Posts

I have a group of enemies that I loop through and perform various actions with, in my update loop. Basically it checks if each enemy in the group is either at a wall and should turn back, or at a ledge of a platform, and should either 1) turn back, 2) jump, 3) fall off the ledge.

 

The problem I'm having is that nothing is working properly as the update of course happens 60 times a second, and it rapidly checks the conditions and makes decisions. 

 

My attempted solution is to attach a timer to each of the enemies in the group, and check if the timer is expired before attempting these actions. Then in the actions function I start the timer, which should run for a couple of seconds. The theory being that after taking an action, it should delay attempting again (per enemy) and by that time the enemy has moved on and the condition (at the ledge, etc.) has passed.

 

I can't figure out a) if this possible and B) how to do it in Phaser. Since the timer object seems to require a callback, I thought I would make a callback function set/change a flag on the enemy that tracked if it could perform the action or not. I have code like this:

 

Enemy creation:

    spawnSlime: function() {        // create a new slime        var yellowSlime = this.slimes.create(760 + Math.random() * 100, 70 + Math.random() * 60, 'medSlime');        yellowSlime.anchor.setTo(0.5, 0.5);        yellowSlime.animations.add('slime-walk', [0, 1, 2, 4, 3, 2, 1, 0], 6, true);        this.physics.arcade.enable(yellowSlime);        this.physics.arcade.collide(yellowSlime, this.layer_world);        yellowSlime.body.gravity.y = this.GRAVITY;        yellowSlime.body.collideWorldBounds = true;        yellowSlime.play('slime-walk');        yellowSlime.speed = -(Math.random() * 40);        // create a timer for each slime        yellowSlime.actionTimer = this.game.time.create(false);        yellowSlime.actionTimer.loop(2000, function(){yellowSlime.actionReady=true;}, this);        // ready for actions, which the timer will be used to provide a pause between actions        yellowSlime.actionReady = true;        yellowSlime.body.velocity.x = yellowSlime.speed; // console.log(yellowSlime.body.velocity.x);        yellowSlime.slimeID = this.slimeCounter += 1; console.log('new slime ID: '+yellowSlime.slimeID)    },

As you can see I attempt to attach a timer to the slime there, and a callback anonymous function which changes the actionReady state.

 

Here is the code for the slime actions:

        // slime actions        this.slimes.forEach(function(thisSlime){            // collide all slimes with world            this.physics.arcade.collide(thisSlime, this.layer_world);            this.physics.arcade.overlap(thisSlime, this.lavas, this.lavaDamage, null, this);            // Slime meets obstacle or ledge.. either turn back, fall off ledge, or jump            console.log('actionReady: '+thisSlime.actionReady);            if (thisSlime.actionReady) {                if (thisSlime.body.blocked.down) { // slime is on the ground                    // don't check this slime again for 2 seconds                    thisSlime.actionReady = false; console.log('about to start timer');                    thisSlime.actionTimer.start();                    if (thisSlime.body.blocked.left) {                        // go right                        thisSlime.body.velocity.x = thisSlime.speed;                    } else                    if (thisSlime.body.blocked.right) {                        // go left                        thisSlime.body.velocity.x = -thisSlime.speed;                    } else                    if (this.tileGet(thisSlime, this.layer_world, 'right') == 0) {                        // slime on ledge, drops off to the right                        if ((Math.random() * 3) > 2) { // 1 in 3 chance to jump, otherwise fall off ledge                            // make slime jump                            thisSlime.body.velocity.y += 60; console.log('slime'+thisSlime.slimeID+' is jumping');                        } else {                            thisSlime.body.velocity.x = -thisSlime.speed; console.log('slime'+thisSlime.slimeID+' is going back left');                        }                    } else                    if (this.tileGet(thisSlime, this.layer_world, 'left') == 0) {                        // slime on ledge, drops off to the left                        if ((Math.random() * 3) > 2) { // 1 in 3 chance to jump, otherwise fall off ledge                            // make slime jump                            thisSlime.body.velocity.y += 60; console.log('slime'+thisSlime.slimeID+' is jumping');                        } else {                            thisSlime.body.velocity.x = thisSlime.speed; console.log('slime'+thisSlime.slimeID+' is going back right');                        }                    } else {                        // no conditions met, keep actionReady as true                        thisSlime.actionReady = true;                    }                }            }

So this function checks the actionReady boolean, and then attempts the actions by first checking the conditions (at a wall or ledge). I have a tileGet function that checks what tile is beyond the ledge, which works.

 

If at a wall it just turns around. However if at a ledge, it makes a random choice for turn back | jump | continue and fall off ledge. 

 

As mentioned the timer starting is supposed to change the condition for a couple of seconds so that the slime is not checking/making decision rapidly, canceling them out. 

 

I'm not getting an error here, but the slimes are just always falling off the ledge, and the condition seems to be rapidly checked, as if the timer isnt working, as evidenced by my console output:

 

https://www.dropbox.com/s/minssx6l754g03k/Screenshot%202014-05-10%2022.23.36.png

 

 

When I tried a function instead of an anonymous function, I would get an error. The call:

yellowSlime.actionTimer.loop(2000, this.readyForAction(yellowSlime), this);

and the function:

    readyForAction: function(entity) {        entity.actionReady = true;    },

Any help would be appreciated. Keep in mind that I'm not an expert in javascript, I'm still learning, so there may well be js problems - and I'm not quite sure if/how the Phaser timer function can be used for this.

 

thanks

Chris

 

Link to comment
Share on other sites

The way you set that up I would just get rid of the timer and do it this way:

 

- remove all timer stuff (including the actionReady flag)

 

- on slime creation do

this.actionTimestamp = 0;

- instead of the actionReady check you check this:

if (this.actionTimestamp < game.time.time) {  this.actionTimestamp = game.time.time + 2000;//... your action logic here}

Since game.time.time always is the current time in milliseconds, this way any time the slime takes an action, it notes the current time + 2000ms .. and only takes another action if the current time is bigger then this value. (So only if two seconds or 2000 milli seconds have elapsed).

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...