• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GameMaker Animating NPC walk

  • Thread starter Joao Cruz Malhao
  • Start date
J

Joao Cruz Malhao

Guest
So im trying to add walk animations to an NPC, somehow using the "moveX" "moveY" and syncing the angle to its appropriate walk animation, (npc_walk_up, etc) just dont know how to code it. Considering im still fairly new could i have a tip or help? Thank you.



Code:
    if(counter >= room_speed *3){
        var change = choose(0,1);
        switch(change){
            case 0: state = states.idle
            case 1:
                my_dir = irandom_range(0,359);
                moveX = lengthdir_x(spd, my_dir);
                moveY = lengthdir_y(spd, my_dir);
                counter = 0;
        }
 
D

dannyjenn

Guest
I believe that room_speed is deprecated, so if you're new you shouldn't be using it. (Use either fps or game_get_speed(gamespeed_fps) instead.)

As for your question... is this 4-directional movement, or 8-directional movement? An array with some constants could come in handy here...
Code:
// constants (you can put this anywhere):
#macro RIGHT 0 // (0 div 90)
#macro UP 1 // (90 div 90)
#macro LEFT 2 // (180 div 90)
#macro DOWN 3 // (270 div 90)

// array (put this part in e.g. a controller object's create event):
global.npc_walk[DOWN] = npc_walk_down;
global.npc_walk[UP] = npc_walk_up;
global.npc_walk[LEFT] = npc_walk_left;
global.npc_walk[RIGHT] = npc_walk_right;

// the code:
my_dir = irandom_range(0,359);
sprite_index = global.npc_walk[(((my_dir+(90 div 2)) mod 360) div 90)]; // <-- I think this is right, though I haven't tested it.
The idea is to convert your 0 - 360 number to its corresponding constant 0 - 3 (i.e. the array's index number), such that 0 - 45 map to RIGHT (=0), 45 - 135 become UP (=1), 135 - 225 become LEFT (=2), 225 - 315 become DOWN (=3), and 315 to 360 become RIGHT (=0).
 
Last edited by a moderator:
J

Joao Cruz Malhao

Guest
I believe that room_speed is deprecated, so if you're new you shouldn't be using it. (Use either fps or game_get_speed(gamespeed_fps) instead.)

As for your question... is this 4-directional movement, or 8-directional movement? An array with some constants could come in handy here...
Code:
// constants (you can put this anywhere):
#macro RIGHT 0 // (0 div 90)
#macro UP 1 // (90 div 90)
#macro LEFT 2 // (180 div 90)
#macro DOWN 3 // (270 div 90)

// array (put this part in e.g. a controller object's create event):
global.npc_walk[DOWN] = npc_walk_down;
global.npc_walk[UP] = npc_walk_up;
global.npc_walk[LEFT] = npc_walk_left;
global.npc_walk[RIGHT] = npc_walk_right;

// the code:
my_dir = irandom_range(0,359);
sprite_index = global.npc_walk[(((my_dir+(90 div 2)) mod 360) div 90)]; // <-- I think this is right, though I haven't tested it.
The idea is to convert your 0 - 360 number to its corresponding constant 0 - 3 (i.e. the array's index number), such that 0 - 45 map to RIGHT (=0), 45 - 135 become UP (=1), 135 - 225 become LEFT (=2), 225 - 315 become DOWN (=3), and 315 to 360 become RIGHT (=0).
The code has worked but what's happening is when moving in any direction, the npc switches rapidly between all the different sprite directions
 
D

dannyjenn

Guest
Could you post your code? It should look something like this:
Code:
   if(counter >= game_get_speed(gamespeed_fps) *3){ // changed room_speed to game_get_speed(gamespeed_fps)
       var change = choose(0,1);
       switch(change){
           case 0:
               state = states.idle;
               break; // <-- you forgot this break statement, though I don't believe that's the problem
           case 1:
               my_dir = irandom_range(0,359);
               sprite_index = global.npc_walk[(((my_dir+(90 div 2)) mod 360) div 90)]; //
               moveX = lengthdir_x(spd, my_dir);
               moveY = lengthdir_y(spd, my_dir);
               counter = 0;
       }
If that's what you have, I'm not sure what the problem is. It's inside the if statement, so the sprite should only ever change whenever the direction changes (once every 3 seconds).
 
J

Joao Cruz Malhao

Guest
Could you post your code? It should look something like this:
Code:
   if(counter >= game_get_speed(gamespeed_fps) *3){ // changed room_speed to game_get_speed(gamespeed_fps)
       var change = choose(0,1);
       switch(change){
           case 0:
               state = states.idle;
               break; // <-- you forgot this break statement, though I don't believe that's the problem
           case 1:
               my_dir = irandom_range(0,359);
               sprite_index = global.npc_walk[(((my_dir+(90 div 2)) mod 360) div 90)]; //
               moveX = lengthdir_x(spd, my_dir);
               moveY = lengthdir_y(spd, my_dir);
               counter = 0;
       }
If that's what you have, I'm not sure what the problem is. It's inside the if statement, so the sprite should only ever change whenever the direction changes (once every 3 seconds).
that helped, but there's still some bugs, they disappear when they switch to the idle state (i believe), and its now a mix of when moving its either stuck with the idle spr or it uses the correct directional animation. bit hard to explain. here's all my code:


Create event of boar_obj:


Code:
global.boar_walk[DOWN] = boar_walk_down;
global.boar_walk[UP] = boar_walk_up;
global.boar_walk[LEFT] = boar_walk_left;
global.boar_walk[RIGHT] = boar_walk_right;
enum states {
    idle,
    wander,
    alert,
    attack,
    reproduce
}
state = states.idle;
counter = 0;
spd = 2;
my_dir = irandom_range(0, 359);
moveX = lengthdir_x(spd, my_dir);
moveY = lengthdir_y(spd, my_dir);
Step event of boar_obj:
Code:
if(state == states.idle) {
    #region Idle
  
    //behaviour
    counter += 1;
  
    //Transition Triggers
    if(counter >= room_speed) {
        var change = choose(0,1);
        switch(change) {
            case 0: state = states.wander;
            case 1: counter = 0; break;
        }
    }
    if(collision_circle(x,y, 64, obj_player, false, false)){
        state = states.alert;
    }
  
    //Sprite
    sprite_index = boar_spr;
  
  
    #endregion
}
else if(state == states.wander) {
    #region wander
  
    //Behaviour
    counter += 1;
  
    x += moveX;
    y += moveY;
  
    //Transition Triggers
    if(counter >= game_get_speed(gamespeed_fps) *1){ 
       var change = choose(0,1);
       switch(change){
           case 0:
               state = states.idle;
               sprite_index = boar_spr
               break; 
           case 1:
               my_dir = irandom_range(0,359);
               sprite_index = global.boar_walk[(((my_dir+(90 div 2)) mod 360) div 90)]; //
               moveX = lengthdir_x(spd, my_dir);
               moveY = lengthdir_y(spd, my_dir);
               counter = 0;
       }
    }
    if(collision_circle(x,y, 64, obj_player, false, false)) {
        state = states.alert;
    }
    //sprite
    //sprite_index = boar_spr
              
    #endregion
}
else if(state == states.alert) {
    #region Alert
  
    //Behaviour
    my_dir = point_direction(x,y, obj_player.x, obj_player.y);
    moveX = lengthdir_x(spd, my_dir);
    moveY = lengthdir_y(spd, my_dir);
    x += moveX;
    y += moveY;
  
    //transition triggers
    if(!collision_circle(x,y, 64, obj_player, false, false)){
        state = states.idle;
    }
    if (collision_circle(x,y, 32, obj_player, false, false)){
        state = states.attack;
    }
    //sprite
    sprite_index = boar_spr
  
  
  
    #endregion
}
else if(state == states.attack) {
    #region Attack
  
        my_dir = point_direction(x,y, obj_player.x, obj_player.y);
    moveX = lengthdir_x(spd, my_dir);
    moveY = lengthdir_y(spd, my_dir);
    x += moveX;
    y += moveY;
  
        if (collision_circle(x,y, 16, obj_player, false, false)){
      
        ///activate attack animation, each animation cycle = 1 attack, not done yet
        sprite_index = boar_attack_spr;
        image_speed = 0.1;
        }
            if(!collision_circle(x,y, 250, obj_player, false, false)){
        state = states.idle;
        sprite_index = boar_spr;
            }
  
  
  
    #endregion
}
 

TheouAegis

Member
Can we please just replace 90 div 2 with 45 already? It is driving my OCDness crazy! lol :eek::bash:

one thing I notice is in your transition from the idle state to the wandering state, you never change the sprite for one entire second.

Your Alert and Attack states don't set the sprite based on direction at all.
 
J

Joao Cruz Malhao

Guest
Can we please just replace 90 div 2 with 45 already? It is driving my OCDness crazy! lol :eek::bash:

one thing I notice is in your transition from the idle state to the wandering state, you never change the sprite for one entire second.

Your Alert and Attack states don't set the sprite based on direction at all.
i agree with you but im still fairly new to gml , how would i need to change the code so it's based on direction? (ive replaced 90 div 2 with 45 xD)
Thank you
 
J

Joao Cruz Malhao

Guest
Can we please just replace 90 div 2 with 45 already? It is driving my OCDness crazy! lol :eek::bash:

one thing I notice is in your transition from the idle state to the wandering state, you never change the sprite for one entire second.

Your Alert and Attack states don't set the sprite based on direction at all.
*bump*
 
N

NeZvers

Guest
Code:
//get direction
var dir = point_direction(0, 0, hspd, vspd);
//sprite to choose
var spr = (dir div 45) % 8; // (0 to 8) if we get 360 or up, then start from 0
 
Top