LazyOasis
LazyOasis

Reputation: 1

movementspeed not updating in a state machine

THIS IS ALL IN THE STEP EVENT.

I am currently trying to create my first state machine for some enemy AI. Being very new to gml and gamemaker studio 2, my code is very basic as I do not know how to implement built in functions.

In 1 of my states, the rush state, the enemy is supposed to chase the player. I do this by creating some conditions, if the player is to the left of the enemy, the enemy will run left. If the player is to the right, the enemy will run right. This in theory is what I have coded but when I get in game, sometimes it will work, but then spasm and go the other way.

If my character is in the circle, it doesn't run towards the player but instead away. This does not change if I reverse the conditions.

case  behaviour.rush:
{
    //radius in square
        if (point_in_circle(playerObject.x,playerObject.y,x,y,200))
         { 
             //direction to face player
             if (behaviourState == behaviour.rush && playerObject.x           >.     warriorx) hsp = -4;
              else if (behaviourState == behaviour.rush &&     
  playerObject.x <= warriorx) hsp = 4;
            x = x + hsp;
         }

    if (!point_in_circle(playerObject.x,playerObject.y,x,y,200))
    {
        behaviourState = behaviour.idle;    
    }
}

My full code:

image_speed = 1;
vsp = vsp+grv;
Print(behaviourState);
if (hsp > 0) image_xscale = 3; else if (hsp < 0) image_xscale = -3; 

//animation
if (behaviourState == behaviour.idle) sprite_index =     tikiAxeWarriorIdle;
if (hsp == 2 || hsp == -2)sprite_index = tikiAxeWarriorWalk;

if (hsp == 4 || hsp == -4) sprite_index = tikiAxeWarriorRush;

if (point_in_circle(playerObject.x,playerObject.y,x,y,200))
{ 
   Print("in circle");
}
Print(hsp);

switch(behaviourState)
{
    case behaviour.idle:
    {
        //stand still
         if (alarm[1] <= 0) alarm[1] = room_speed * 4;

         if (point_in_circle(playerObject.x,playerObject.y,x,y,200))
         { 
             behaviourState = behaviour.rush;
         }
    }

    case behaviour.wander:
    {
        if (alarm[0] <= 0) alarm[0] = room_speed * 3;

        //move
        if (!place_meeting(x + hsp,y,wallObject)) 
        {
            x = x + hsp;
        }

        if (place_meeting(x + hsp,y,wallObject))//checking frame before.
        {   
            hsp = -hsp;
        }

        //check for behaviour.rush.
        if (point_in_circle(playerObject.x,playerObject.y,x,y,200))
        { 
            behaviourState = behaviour.rush;
        }
    }

    case  behaviour.rush:
    {
        //radius in square
        if (point_in_circle(playerObject.x,playerObject.y,x,y,200))
        { 
            //direction to face player
            if (behaviourState == behaviour.rush && playerObject.x > warriorx) hsp = -4;
            else if (behaviourState == behaviour.rush && playerObject.x <= warriorx) hsp = 4;
            x = x + hsp;
        }

        if (!point_in_circle(playerObject.x,playerObject.y,x,y,200))
        {
            behaviourState = behaviour.idle;    
        }
    }
    case behaviour.attack:
    {
        //attack.   
        //if player is hit, he dies.
    }
}

The expected result is for the enemy to "rush" towards my player position and when over stepped, to face the other way. If my player leaves the circle, it should go back to the idle state.

Upvotes: 0

Views: 89

Answers (2)

Noel
Noel

Reputation: 1

With switch statements, I believe you need to add "break;" in between each Case.

The YoYo documentation here has some good information on switch statements. Now this might not enable your code to run exactly as you're hoping, but it will get you one bug less towards your goal.

The pertinent part of the link states:
"...execution continues after the first case statement with the correct value, until a break statement is encountered....the break is not required, and if there is no break statement the execution simply continues with the code for the next case statement".

So essentially, without a break statement, the code will start at the case block matching the current value, and then run through the code of the all cases below it until it hits a "break;".

Here's what your code would look like with the "break;" added in to the correct spots.

image_speed = 1;
vsp = vsp+grv;
Print(behaviourState);
if (hsp > 0) image_xscale = 3; else if (hsp < 0) image_xscale = -3; 

//animation
if (behaviourState == behaviour.idle) sprite_index =     tikiAxeWarriorIdle;
if (hsp == 2 || hsp == -2)sprite_index = tikiAxeWarriorWalk;

if (hsp == 4 || hsp == -4) sprite_index = tikiAxeWarriorRush;

if (point_in_circle(playerObject.x,playerObject.y,x,y,200))
{ 
   Print("in circle");
}
Print(hsp);

switch(behaviourState)
{
    case behaviour.idle:
    {
        //stand still
         if (alarm[1] <= 0) alarm[1] = room_speed * 4;

         if (point_in_circle(playerObject.x,playerObject.y,x,y,200))
         { 
             behaviourState = behaviour.rush;
         }
    }
    break;
    case behaviour.wander:
    {
        if (alarm[0] <= 0) alarm[0] = room_speed * 3;

        //move
        if (!place_meeting(x + hsp,y,wallObject)) 
        {
            x = x + hsp;
        }

        if (place_meeting(x + hsp,y,wallObject))//checking frame before.
        {   
            hsp = -hsp;
        }

        //check for behaviour.rush.
        if (point_in_circle(playerObject.x,playerObject.y,x,y,200))
        { 
            behaviourState = behaviour.rush;
        }
    }
    break;
    case  behaviour.rush:
    {
        //radius in square
        if (point_in_circle(playerObject.x,playerObject.y,x,y,200))
        { 
            //direction to face player
            if (behaviourState == behaviour.rush && playerObject.x > warriorx) hsp = -4;
            else if (behaviourState == behaviour.rush && playerObject.x <= warriorx) hsp = 4;
            x = x + hsp;
        }

        if (!point_in_circle(playerObject.x,playerObject.y,x,y,200))
        {
            behaviourState = behaviour.idle;    
        }
    }
    break;
    case behaviour.attack:
    {
        //attack.   
        //if player is hit, he dies.
    }
    break;
}

Hope this helps!

Also, a quick tip! One thing I noticed with your code is you repeat a couple expressions a few times. For readability sake, I recommend assigning these to a variable if possible. For example:

var in_circle = point_in_circle(playerObject.x,playerObject.y,x,y,200);

if in_circle {

}
if !in_circle {

}

Upvotes: 0

Steven
Steven

Reputation: 2122

hsp = -hsp sounds very sensitive to the spasm. and since it's affect the hsp as whole, it'll also affect the place_meeting(x + hsp,y,wallObject) part. I don't know the solution right away, but I think you should take a look at that section.

I also personally prefer to split your current hsp in two variables: the direction and speed, where the direction is a value of 1 or -1 and the speed is like hsp, but returns a positive value. And then combine them using speed * direction.
That way, you can calculate the speed without taking direction into account, and vice versa. Which may also solve the conflict you're currently having.

Upvotes: 0

Related Questions