M
madorca
Guest
Hello everyone,
I know this question asked many times before and yes I checked old posts and tried different solutions and approaches as much as I could but I'm still learning :/ (I started to GMS 4 months ago, pretty new).
I will try to explain my problem.
I'm trying to make a topdown shooter (a really bad imitation of nuclear throne).
The player movement, collision, shooting etc works without a problem.
But the enemy..
The enemy uses state machine.
I followed FriendlyCosmonaut's tutorial for that.
(It has idle, wander, alert and attack state. It's using collision circle to check if the player is near or not and behave accordingly).
But they were hugging the walls while chasing me. They needed some AI. So I searched for that and found that it is possible using grids / pathfinding.
I decided to go for mp_grid. I somehow managed to implement the grid system and did the pathfinding for the enemy. So far so good.
The problems that I'm facing are;
1 - when the enemy enters it's "alert state" and starts to chase me, it creates the path towards me but its sprite is facing always to the right side.
2 - In order to calculate the path, im using an alarm instead of the step event. While the enemy is chasing me, there isn't any problem changing its states, the problem starts when I exit its range. Then the enemy enters its "idle state" and start to slide along the path / till the end.
I really appreciate if you can help me with this.
Thank you^^
Here are my codes.
I know this question asked many times before and yes I checked old posts and tried different solutions and approaches as much as I could but I'm still learning :/ (I started to GMS 4 months ago, pretty new).
I will try to explain my problem.
I'm trying to make a topdown shooter (a really bad imitation of nuclear throne).
The player movement, collision, shooting etc works without a problem.
But the enemy..
The enemy uses state machine.
I followed FriendlyCosmonaut's tutorial for that.
(It has idle, wander, alert and attack state. It's using collision circle to check if the player is near or not and behave accordingly).
But they were hugging the walls while chasing me. They needed some AI. So I searched for that and found that it is possible using grids / pathfinding.
I decided to go for mp_grid. I somehow managed to implement the grid system and did the pathfinding for the enemy. So far so good.
The problems that I'm facing are;
1 - when the enemy enters it's "alert state" and starts to chase me, it creates the path towards me but its sprite is facing always to the right side.
2 - In order to calculate the path, im using an alarm instead of the step event. While the enemy is chasing me, there isn't any problem changing its states, the problem starts when I exit its range. Then the enemy enters its "idle state" and start to slide along the path / till the end.
I really appreciate if you can help me with this.
Thank you^^
Here are my codes.
Code:
///// @description Enums
mypath = path_add();
alarm[1] = 0;
depth = 2;
counter = 0;
spd = .5;
my_dir = irandom_range(0,359);
moveX = lengthdir_x(spd, my_dir);
moveY = lengthdir_y(spd, my_dir);
//Enemy Health
max_hp = 3;
hp = max_hp;
////Enemy Hurt
flash = 0;
//Bullet cooldown
bullet_cooldown = room_speed*2;
alarm[0] = bullet_cooldown;
//Enemy states
enum estates
{
enemyidle,
enemywander,
enemyalert,
enemyattack,
enemystandattack,
enemydie,
enemyknockback,
}
state = estates.enemyidle;
states_array[estates.enemyidle] = enemy_state_idle;
states_array[estates.enemywander] = enemy_state_wander;
states_array[estates.enemyalert] = enemy_state_alert;
states_array[estates.enemyattack] = enemy_state_attack;
states_array[estates.enemystandattack] = enemy_state_stand_attack;
states_array[estates.enemydie] = enemy_state_die;
Code:
/// @description Create Grid
var cell_width = 48;
var cell_height = 48;
var hcells = room_width div cell_width;
var vcells = room_height div cell_height;
global.grid = mp_grid_create(0, 0, hcells, vcells, cell_width, cell_height);
//Add walls
mp_grid_add_instances(global.grid, o_collision, false);
Code:
/// @description update path
var tx, ty;
tx = o_player.x
ty = o_player.y
if (mp_grid_path(global.grid, mypath, x, y, tx, ty, 1))
{
path_start(mypath, 2, path_action_stop, false);
path_set_kind(mypath, 1); //Smooth path (kind = 1)
path_set_precision(mypath, 8); //Even smoother path (precision = 8)
alarm[1] = 30;
}
Code:
//Behaviour
alarm[1] = 0;
counter += 1;
//Transition Triggers
if(counter >= room_speed * 3)
{
var change = choose (0, 1);
switch(change)
{
case 0: state = estates.enemywander;
case 1: counter = 0;
break;
}
}
if instance_exists(o_player) and (collision_circle(x, y, 250, o_player, false, false))
{
state = estates.enemyalert;
}
//Die state
if (hp <= 0)
{
state = estates.enemydie;
}
//sprite
sprite_index = s_Enemy_idle;
Code:
alarm[1] = 0;
////collision
//enemy_collision();
//Behaviour
counter += 1;
x += moveX;
y += moveY;
//Transition Triggers
if(counter >= room_speed *3)
{
var change = choose(0 , 1);
switch(change)
{
case 0: state = estates.enemyidle;
case 1:
my_dir = irandom_range(0, 359);
moveX = lengthdir_x(spd, my_dir);
moveY = lengthdir_y(spd, my_dir);
counter = 0;
}
}
if instance_exists(o_player) and (collision_circle(x, y, 250, o_player, false, false))
{
state = estates.enemyalert;
}
//Die state
if (hp <= 0)
{
state = estates.enemydie;
}
//Sprite
sprite_index = s_Enemy_wander;
if(moveX != 0) image_xscale = sign(moveX);
Code:
if instance_exists(o_player)
{
alarm [1] = 1;
////collision
//enemy_collision();
//Transition Triggers
if(!collision_circle(x,y, 250, o_player, false, false))
{
state = estates.enemyidle;
}
if(collision_circle(x, y, 180, o_player, false, false))
{
state= estates.enemyattack;
}
//Die state
if (hp <= 0)
{
state = estates.enemydie;
}
//Sprite
sprite_index = s_Enemy_alert
}
Code:
if instance_exists(o_player)
{
alarm[1] = 1;
////collision
//enemy_collision();
//Enemy Shoot
if alarm[0] <= 0
{
var bullet = instance_create_layer(x, y, "projectiles", oBullet_enemy);
with (bullet)
{
direction = point_direction(x, y, o_player.x, o_player.y);
speed = 3;
}
alarm[0] = room_speed * 2; // Enemy will shoot
}
//Transition Triggers
if(image_index > image_number-1)
{
state = estates.enemyalert;
}
if(!collision_circle(x, y, 250, o_player, false, false))
{
state = estates.enemyidle;
}
if(collision_circle(x, y, 100, o_player, false, false))
{
state = estates.enemystandattack;
}
//Die state
if (hp <= 0)
{
state = estates.enemydie;
}
//Sprite
sprite_index = s_Enemy_attack;
}