Legacy GM [Solved] Making an AI that avoids the edges of the room using Objects

I

Irishes

Guest
I'm attempting to write an AI that moves until it gets close to the edge of the room. I added obj_boundary objects around the edge of the room. Every Ship creates a collision line 100 px in front of the ship. For some reason, when approaching the border from the right, the algorithm seems to work, but when approaching from the left, the ship takes longer to switch states.
 

Attachments

NightFrost

Member
Without seeing any code, and using the scientific instrument of "just eyeballing it," the behavior looks as if the collision is always sensed from the right end of your collision line. So, a ship approaching the left boundary won't detect it before on top of it.

EDIT: are you running some vector math scripts? Because it could be your code is confused about which end of the vector your ship is at.
 
Last edited:
N

newtinn

Guest
So Irishes if you want it just to go side to side you can just do this code:
Code:
// Collision with the right side
if (place_meeting,x+1,y,obj_boundary) {
    hspeed = -10;
}
// Collision with the left side
if (place_meeting,x-1,y,obj_boundary) {
    hspeed = 10;
}
 

Murzy

Member
It's hard to tell what is wrong with your code without seeing it first. Could you post it here so we could take a look?
 
I

Irishes

Guest
forwardCollisionLine = collision_line(x, y, direction+300, y, obj_boundary, false, false);

if(forwardCollisionLine != noone){

state = scr_ship_turn_left;
}

if(forwardCollisionLine == noone){

state = scr_ship_fly;
}

I switched to this instead and it seems to work. Previously I had the ships change speed to their Minimum Speed before changing state. Ships still sometimes fly off the map if they cant make the turn.
 

Murzy

Member
Ah, I see. The problem here is that the collision_line -function takes the following arguments:

Code:
 collision_line( x1, y1, x2, y2, obj, prec, notme );
However your x2, y2 aren't exactly what they are supposed to be. To make a line to 300px in front of the ship (i.e. pointing at the direction of the ship) you should do something like this:

Code:
var forward_look_distance = 300;
var forward_x = x + lengthdir_x(forward_look_distance, direction);
var forward_y = y + lengthdir_y(forward_look_distance, direction);

forwardCollisionLine = collision_line(x, y, forward_x, forward_y, obj_boundary, false, false);

if(forwardCollisionLine != noone){
    state = scr_ship_turn_left;
}

else if(forwardCollisionLine == noone){
    state = scr_ship_fly;
}
The lengthdir_x/y -functions are pretty well explained in the manual, I suggest that you look them up. They are very useful in a lot of things.

Also, when debugging something like this, it usually is a good idea to visualize the problem. If you would have drawn a line using the values you put into your original collision_line(x1, y1, x2, y2) call, and had a similar draw_line(x1, y1, x2, y2) call in the draw event, you would have spotted that the line isn't where it is supposed to be.
 
I

Irishes

Guest
Ohhhhhh, that makes sense. What is direction+300 returning?
 

Murzy

Member
The direction variable contains the heading of the ship (the angle) 0-360 in degrees. So adding the length of 300px to that doesn't really make any sense as even the units aren't the same! The collision_line function needs 2 positions to do the comparison against, so we need a way to convert the heading of the ship to an actual x,y position in front of it. That's what the solution above does.

The point of the lengthdir -functions is to convert a given length, at a given angle, to a distance using the axis provided (x or y). I recommend checking out the manual page for this. There is a more detailed explanation in there.
 
Murzy is offering useful advice - though I think if you're ship is only travelling left or right, then it can be simplified. The lengthdir commands are good for objects that move in any direction, as it takes that direction and figures a point at whatever distance ahead.

But with only two directions its perhaps somewhat unnecessary to use it. I think you could do:
Code:
var side=sign(hspeed);
switch (side)
{
case -1:
   forward_x = x - forward_look_distance;
   break;
case 1:
  forward_x = x + forward_look_distance;
  break
;}
forwardCollisionLine = collision_line(x, y, forward_x, forward_y, obj_boundary, false, false);
followed by the rest of your code etc.

Because you're only moving left or right (if I've understood correctly) you only need to find out which direction the ship is heading in. The variable 'hspeed' gets a minus when going left, and is a positive number when going right - using sign before a variable gets whether its positive, or negative, and so is a simple way to know whether 'forward_look_distance' should be added or subtracted from x. There is a switch statement which will set 'forward_x' to the appropriate amount.

'Forward_x' will be either 0 degress or 180 degrees from the objects origin. I may be wrong, but I think doing it this way would be faster to process than using lengthdir commands in your situation.
 
Top