• 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!

Legacy GM Problems with AI Object Animation and Collision

M

MagusMori

Guest
Hey everyone, I'm pretty new to using Gamemaker and coding in general. More of an artist but I'm trying to learn how to make games and put my skills to use!

Anyway, I've been looking through a lot of posts and tutorial videos and managed to get myself a working player character in a pixel platformer style setting. But now I want to add an AI animal that wanders around but doesn't attack the player. I got the wandering working really well, but it isn't animated and doesn't collide when it is supposed to. All the examples I've found of tutorials don't seem to go into the animation of non-player walking objects. From what I have learned so far I tried to write some code for it based off my player characters animations and collisions, but it isn't working. Any help to understand the issue and get this working would be much appreciated!

tldr;
I'm working on adding in a 'friendly' animal AI that wanders around. The wandering part is working great, but I can't figure out how to add collisions and animation when he moves for some reason. Can anyone help me understand why it doesn't use the codes I wrote and how I could better write it to get it working?

Here is the 'create' event:
Code:
/// Initialize Gooy AI

image_speed = 0.08
hsp = 0;           
vsp = 0; 
grav = 0.2; 
movespeed = 1;

// wander ai
direction_choose=choose(0,180); //random direction
 rand_timer=random_range(room_speed,room_speed * 2); //random interval
 rand_dis=random_range(32,64); //random distance
 move_speed=0.5;
 destX=x;
 destY=y;
Here is the 'step' event:
Code:
/// Control Gooy AI

// took this from my player walk script to try to apply it here, doesn't appear to work
move = (hsp!=0)
hsp = move * movespeed;
if (vsp < 10) vsp += grav;


// wander ai (this works!)
if (rand_timer>0)
 {
      //move to the place, tick down the timer
      rand_timer--;
      direction=direction_choose;
      if (distance_to_point(destX,destY)<=0) {speed=0;} else {speed=move_speed;}
 }
 else
 {
      //direction and distance
      direction_choose=choose(0,180);
      rand_dis=random_range(32,64);

      //destination
      //choose spot that it isn't off limits (how???)
      destX= x+lengthdir_x(rand_dis,direction_choose);
      destY= y+lengthdir_y(rand_dis,direction_choose);

      //reset the timer
      rand_timer=random_range(room_speed * 8 ,room_speed * 15);

}

// gooy flip, collision and animation

//face the sprite's current walking direction (this works!)
if(direction>89 && direction<271)
then
{
image_xscale=-1;
}
else
{
image_xscale=1;
}

// horizonal collision (not working, taken from player walk script)
if (place_meeting(x + hsp, y, obj_wall))
{
    while (!place_meeting(x+sign(hsp),y,obj_wall))
    {
        x += sign(hsp);
    }
    hsp = 0;
}
x += hsp;

// animate (not working, taken from player walk script)
if (place_meeting(x,y+1,obj_wall)) //on the floor?
{
    if (move!=0) sprite_index = spr_gooy_run;
    else sprite_index = spr_gooy_idle; 
}
 

TheouAegis

Member
If you want to be and I made it you have to set the image_speed.

move = (hsp!=0)
hsp = move * movespeed;

You need to consider the logic of the codes you write.

y = f(x)
x = f(y)

In other words, in the end

hsp = hsp


However, that move= line is useful for animating, kinda.

if hsp!=0 {
image_speed = 1/4;
}
else {
image_index = 0
image_speed = 0
}

In other words, if you are moving, animate the Sprite, otherwise change it so the animal is still and not animated.
 
M

MagusMori

Guest
If you want to be and I made it you have to set the image_speed.

move = (hsp!=0)
hsp = move * movespeed;

You need to consider the logic of the codes you write.

y = f(x)
x = f(y)

In other words, in the end

hsp = hsp


However, that move= line is useful for animating, kinda.

if hsp!=0 {
image_speed = 1/4;
}
else {
image_index = 0
image_speed = 0
}

In other words, if you are moving, animate the Sprite, otherwise change it so the animal is still and not animated.
Hey, thanks so much for the reply. I'm trying to wrap my head around this, so I hope I can ask for clarification. I understand the logic of the "if you are moving, animate the sprite" and I think I see how that works in the code you included.

if hsp!=0 {
image_speed = 1/4;
}
else {
image_index = 0
image_speed = 0
}

I tried to added it and what ended up happening was that the idle animation that plays as default quit playing and the sprite didn't animate at all, regardless of if it was idling or wandering. I'm guessing I didn't incorporate it correctly.

How would I fix this hsp = hsp issue? How would I change this code to work with the example you showed me with the image_speed and image_index?

move = (hsp!=0)
hsp = move * movespeed;
 

TheouAegis

Member
Ok, I was misreading parts of your code. So I went back over it and made some notes.


image_speed = 0.08

Ok, your sprite should already be animated once it starts

hsp = 0;
vsp = 0;
grav = 0.2;
movespeed = 1;

Your code makes use of vsp, but currently it doesn't use hsp. So unless you plan on implementing conveyors that gooy can ride, there is no point in having hsp and movespeed in your code. Also, if you do keep them in for conveyors, then movespeed will need to be changed by the conveyor that gooy is on.

direction_choose=choose(0,180); //random direction
rand_timer=random_range(room_speed,room_speed * 2); //random interval
rand_dis=random_range(32,64); //random distance
move_speed=0.5;
destX=x;
destY=y;

Make sure you use irandom_range, not random_range, especially when working with coordinates (which is what rand_dis is doing. rand_timer should be set using irandom_range as well since all lines pertaining to it are about integer values.

move = (hsp!=0)
hsp = move * movespeed;

If you don't use conveyors that gooy can ride on, then you don't need this part of the code.

if (vsp < 10) vsp += grav;
This is fine to use if you're going to use it, but I don't see you actually using it anywhere, so you could probably get rid of it.

if (rand_timer>0)
{
//move to the place, tick down the timer
rand_timer--;

direction=direction_choose;
if (distance_to_point(destX,destY)<=0) {speed=0;} else {speed=move_speed;}
}

But after you move using vsp, then the distance to destX,destY could potentially never be 0. This is fine insofar as it will keep the slime moving but it could move into a wall that you hadn't considered. I would personally change this to
Code:
if abs(destX-x) < 1 {speed = 0;}
It would stop above/below its destination, but you don't have code anywhere that makes it actually go TO its destination, so that's not much of a concern. Furthermore, you don't need to constantly set speed every step. You set it once and then leave it. You aren't changing move_speed anywhere. However, if you do implement a mechanic where move_speed gets changed by external sources, then go ahead keep the else part in.

else

{
//direction and distance
direction_choose=choose(0,180);
rand_dis=random_range(32,64);

//destination
//choose spot that it isn't off limits (how???)
destX= x+lengthdir_x(rand_dis,direction_choose);
destY= y+lengthdir_y(rand_dis,direction_choose);

//reset the timer
rand_timer=random_range(room_speed * 8 ,room_speed * 15);
}

Ok, a couple things here. First, again, make sure you use irandom_range, not random_range. Very important when working with coordinates.
Second, you're obviously only working in 1D with the slime, so you can simplify this quite a bit.
Code:
if direction_choose {destX = x - rand_dis;} else {destX = x + rand_dis;}
destY = y;
Much faster and more logical. But preventing it from going to someplace off limits is a bit more complicated.
Code:
if (destX < 16 || destX > room_width-16)
{
    direction_choose = (direction_choose + 180) mod 360;
    if direction_choose { destX = x - rand_dis;} else {destX = x + rand_dis;}
}
That's a simple "if my destination is out of the room, turn around" scenario. Preventing it from targeting walled-off areas is trickier and I feel you should just ignore that concern, since it's just a slime (i'm guessing), so probably not very intelligent. But if you really wanted to concern yourself with it, you'd have to do something slow like
Code:
var dir = !direction_choose - 1 | 1;
var flips = 0;
for(var i=0; i<rand_dis; i++)
{
    if place_meeting(x + i * dir, y, obj_wall) {rand_dis--};
    if rand_dis < 1 
    {
        if flips
        { rand_dis = 0; break; }
        else
        {
            rand_dis = irandom_range(32,64);
            direction_choose = (direction_choose + 180) mod 360;
            dir = !direction_choose -1 | 1;
            flips = 1;
        }
    }
}
if direction_choose {destX = x - rand_dis;} else {destX = x + rand_dis;}
destY = y;
//face the sprite's current walking direction (this works!)
if(direction>89 && direction<271)
then
{
image_xscale=-1;
}
else
{
image_xscale=1;
}

Your gooy is a 1-dimensional character in a 2-dimensional world, so this code is needlessly complex.
Code:
if direction image_xscale = -1 else image_xscale = 1;
// horizonal collision (not working, taken from player walk script)
if (place_meeting(x + hsp, y, obj_wall))
{
while (!place_meeting(x+sign(hsp),y,obj_wall))
{
x += sign(hsp);
}
hsp = 0;
}
x += hsp;

This code works just fine. The rest of your code is what doesn't work. You aren't using hsp to move, you're using speed. This code will work just fine once you start using hsp for conveyors. Since you're not using hsp for anything right now, though, this code has no visible effect.

// animate (not working, taken from player walk script)
if (place_meeting(x,y+1,obj_wall)) //on the floor?
{
if (move!=0) sprite_index = spr_gooy_run;
else sprite_index = spr_gooy_idle;
}

You're not using move (because you're not using conveyors), so this has no visible effect. And now I'll also give code to animate it, since I had misread your code before.
Code:
if place_meeting(x,y+1,obj_wall)
{
    if speed { sprite_index = spr_gooy_run; }
    else {sprite_index = spr_gooy_idle;}
}
You already set the image_speed in the create event, so all you need to change here is checking speed instead of move.


Like I said, your script is fine in most places, if not needlessly wasteful. All codes pertaining to hsp, vsp, movespeed (not move_speed), and move are fine if you ever actually need to use them. The problem is your gooy doesn't use them at all.
 
Top