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

SOLVED Modifying accurate aim script to account for walls?

Roastedzerg

Member
Edit 2: Heres the work around solution i used to check for nearby walls to decide if the enemy should aim ahead of his target or directly at them. Its not perfect but it worked well for my game.
GML:
    var _p=1/projectile_speed;
    var _x=my_target.x;
    var _y=my_target.y-my_target.hurtbox_height;
    var _u=my_target.x_speed;
    var _v=my_target.y_speed;
    //Determine the distance and time it takes for projectile to reach target, each iteration increases accuracy
    var _d=point_distance(x,y-height,_x,_y);
    var _t=_d*_p;
    var _d=point_distance(x,y-height,_x+_u*_t,_y+_v*_t);
    var _t=_d*_p;
    var _d=point_distance(x,y-height,_x+_u*_t,_y+_v*_t);
    var _t=_d*_p;
    var box_buff=200;
    if(!collision_rectangle(bbox_left-box_buff,bbox_top-box_buff,bbox_right+box_buff,bbox_bottom+box_buff,obj_block_bullet,0,1))
    {
        aim_x=_u*_t;
        aim_y=_v*_t;
    }
    else
    {
        aim_x=0;
        aim_y=0;
    }
Hey guys, I'm using a script that makes the shooting enemies in our game aim ahead of their targets and so far its working relatively well. However they have no way to know if there is a wall in the direction they're aiming or not so they end up trying to shoot ahead of the player only to shoot the wall beside themselves. How can i adjust the following script to incorporate walls so they will stop adjusting if they aim towards one?

GML:
    var _p=1/projectile_speed;
    var _x=my_target.x;
    var _y=my_target.y-my_target.hurtbox_height;
    var _u=my_target.x_speed;
    var _v=my_target.y_speed;
    //Determine the distance and time it takes for projectile to reach target, each iteration increases accuracy
    var _d=point_distance(x,y-height,_x,_y);
    var _t=_d*_p
    var _d=point_distance(x,y-height,_x+_u*_t,_y+_v*_t);
    var _t=_d*_p
    var _d=point_distance(x,y-height,_x+_u*_t,_y+_v*_t);
    var _t=_d*_p
    aim_x=_u*_t;
    aim_y=_v*_t;
    aim_dir=point_direction(x,y-height,my_target.x+aim_x,my_target.y-my_target.hurtbox_height+aim_y);

Edit 1: the variable _t is determining the time it takes based on the distance from enemy to target multiplied by the projectile speed. Also i know i need something like collision_line in there to find a wall that could be intersecting with our aiming line, but dont know where i should put it and how i should modify the calculations to incorporate this collision detection.
I'm not looking for anyone to just hand out the answer, though i would appreciate it if they do, but even a simple suggestion would be enough to help. Thank you


Screencaps for more details:
2021-02-03 (5).png
In the above screenshot the target is the white rectangle and the enemy shooting is the green square to the left. The red line between them represents the aiming which is straight forward as the target is not moving. The green circle is the projectile.

2021-02-03 (4).png
In the next screenshot the target (white rectangle) is moving downwards and the enemy (now a dark blue to represent hes in the aiming state) is trying to compensate by aiming down to where the target will be compared to both of their x and y speeds and coordinates. What im trying to do is make the enemy who is aiming stop compensating when he has aimed a few pixels away from the wall. Right now as you can see he aims as if there were no wall between himself and his target.
 
Last edited:
What would you want to happen if the compensation aims at a wall? Should the enemy just stop trying to shoot, or somehow shoot the bullet faster so it reaches the player before they're past the wall? I can think of one thing to do, but it would be quite tricky. Cast rays to the corners of tiles near the distance the player is at, to make a kind of vision cone. Like a metal gear solid kinda thing. Then you would have a range of angles to do math with. Then you could clamp the compensated aim to those angles, so it would always fire right at corners, and not into the walls. That's my best guess at what you're trying to achieve.
 

Roastedzerg

Member
That last part sounds about right, i'm trying to make them stop adjusting aim ahead of player/target when that adjustment line hits a wall. Preferable a few pixels away from the wall. Im working something out right now using collision_line but havent found anything that works quite yet. Though i am getting closer to a solution. Ill see if using clamp will work out.
 
You could probably use collision_line in a loop. Test the aim before firing to see if it's colliding. If it is, enter a while loop where you keep angling the aim more and more towards the player until it's not colliding with the wall. Maybe 2 degree steps. Then when it's no colliding, commit to that angle. It's a bit inefficient, but it should be fine.
 

Roastedzerg

Member
So what im trying to do right now thats almost what i want is to check if there is wall collision on each axis seperately before setting aim_x or aim_y, and if there is to set itself to 0 so the enemy will aim that axis directly to the target. Example:
GML:
if(!collision_line(x,y-height,_u*_t,_y,obj_block_bullet,0,1))
{
    aim_x=_u*_t;
}
else
{
    aim_x=0;//Dont adjust ahead on x axis, instead aim directly at target x coordinates
}
if(!collision_line(x,y-height,_x,_v*_t,obj_block_bullet,0,1))
{
    aim_y=_v*_t;
}
else
{
    aim_y=0;//Dont adjust ahead on y axis, instead aim directly at target y coordinates
}
Of course this doesnt work because im checking both x and y collision for aim_x and aim_y so he will always aim directly at his target. What i want to do is separately check if the collision on the x axis hits a wall and then adjust only the aim_x and vice versa for the y axis. Let me know if this makes sense.

Edit: hmm not sure this is working.
 
Last edited:

Roastedzerg

Member
How could i go about using clamps to keep the adjustments to the x and y axis between walls using the code in the 1st post?
 

Roastedzerg

Member
Its a bit of a cop out, but i think i can get the results im looking for by checking a collision box around the enemy before adjusting aim to check if there is a wall nearby and directly aiming at the target if there is, and aim ahead of the target if there isnt a wall in the collision box. For this game i think something simple like that will do. Though it would be cool to see if anyone can show how they might handle this kind of aim adjustment another way in code. It might be helpful for me or anyone else who sees this thread in the future. Thank you for the feedback @Octopus_Tophat!
 
How could i go about using clamps to keep the adjustments to the x and y axis between walls using the code in the 1st post?
Clamps would be used if using the harder "vision cone" method.
I'm not that good at math unless I'm working with the code myself so I'm sorry that it's a bit hard for me to help.
Are the aim_x and aim_y speed vectors for the bullet? Or is that the target's coordinates?
Using collision_line for seperate axis's will definitely not work. You have to test collisions with the actual compensated aiming line, but I guess you aren't really working with angles so it takes a little extra work.
Assuming the aim_x and aim_y are the target's coordinates, I think it would be something like:
GML:
var _p=1/projectile_speed;
var _x=my_target.x;
var _y=my_target.y-my_target.hurtbox_height;
var _u=my_target.x_speed;
var _v=my_target.y_speed;
//Determine the distance and time it takes for projectile to reach target, each iteration increases accuracy
var _d=point_distance(x,y-height,_x,_y);
var _t=_d*_p
var _d=point_distance(x,y-height,_x+_u*_t,_y+_v*_t);
var _t=_d*_p
var _d=point_distance(x,y-height,_x+_u*_t,_y+_v*_t);
var _t=_d*_p
aim_x=_u*_t;
aim_y=_v*_t;
aim_dir=point_direction(x,y-height,my_target.x+aim_x,my_target.y-my_target.hurtbox_height+aim_y);

if (collision_line(x,y-height,aim_x,aim_y,obj_block_bullet,0,1))
{
   var angleChange = 2;
   var test_x;
   var test_y;
   var dist = point_distance(x,y-height,my_target.x+aim_x,my_target.y-my_target.hurtbox_height+aim_y);

   while (true) {
       // Not super good with vector math, but basically here we are nudging the angle of the aim counterclockwise to try to get it out of the wall
       test_x = dcos(aim_dir+ angleChange) * dist;
       test_y = -dsin(aim_dir+ angleChange) * dist;
       if !collision_line(x,y-height,test_x ,test_y ,obj_block_bullet,0,1)
       {
             // There is no collision, so we are out of the wall now
             // Also, maybe add some padding here so the aim will not be right at the corner, but a little bit out
             test_x = dcos(aim_dir+ angleChange + 5) * dist;
             test_y = -dsin(aim_dir+ angleChange + 5) * dist;
             break;
       }

       // Now we also test if moving the aim clockwise works
       test_x = dcos(aim_dir- angleChange) * dist;
       test_y = -dsin(aim_dir- angleChange) * dist;
       if !collision_line(x,y-height,test_x ,test_y ,obj_block_bullet,0,1)
       {
             // There is no collision, so we are out of the wall now
             // Also, maybe add some padding here so the aim will not be right at the corner, but a little bit out
             test_x = dcos(aim_dir- angleChange - 5) * dist;
             test_y = -dsin(aim_dir- angleChange - 5) * dist;
             break;
       }
       angleChange += 2;

       // Angle change is too high, it can't find a way out of the wall
       // This is basically the error state, where it can't find anywhere to shoot. You'll probably need some other code here depending on what you want the enemy to do.
       // Here it just defaults to where it was going to aim before all of this code
       if (angleChange >= 180)
       {
            test_x = aim_x;
            test_y = aim_y;
            break;
       }
   }

   // Once we exit the while loop, we have found a working aim coordinate
   aim_x = test_x;
   aim_y = test_t;
   aim_dir=point_direction(x,y-height,my_target.x+aim_x,my_target.y-my_target.hurtbox_height+aim_y);
}
This is untested code so you'll probably need to do some tweaking. Let me know what problems you face :)
 
Top