GML Clever bullet

Hello everybody, i wanted to make clever bullet. The bullet, knowing the speed of the player and the direction of his movement, with the condition that the player does not change either the speed or the direction. Must calculate the angle at which it will fly out to intersect with the player
So i know, how to do it in words. But there are still some troubles with code.

The time is the same and we can write 2 formulas:
1) distance_from_object_to_intersection point(s1) / object_speed == distance_from_bullet_to_intersection point(s2) / bullet_speed;
2) distance_between_bullet_and_object(s3) = s1^2 + s2^2 - 2*s1*s2*cos(angle_between_s1_and_s2)

If we use coordinates we will have sth like this:
A(x, y) - intersection point
B(x1, y1) - initial object coordinates
C(x2, y2) - initial bullet coordinates
v - object speed
w - bullet speed
ab - distance between object and intersection point
ac - distance between bullet and intersection point
cos(ab, ac) = ( (x-x1)*(x-x2) + (y-y1)*(y-y2) ) / sqrt((x - x2)^2 + (y - y2)^2) / sqrt((x - x1)^2 + (y - y1)^2)

1) ab/v == ac/w -> sqrt((x - x1)^2 + (y - y1)^2)/v == sqrt((x - x2)^2 + (y - y2)^2)/w
2) bc^2 = ab^2 + ac^2 - 2*ab*ac*cos(ab, ac) ->
(x1 - x2)^2 + (y1 - y2)^2) = (x - x1)^2 + (y - y1)^2) + (x - x1)^2 + (y - y1)^2) - 2*sqrt((x - x2)^2 + (y - y2)^2)*sqrt((x - x1)^2 + (y - y1)^2)*( (x-x1)*(x-x2) + (y-y1)*(y-y2) ) / sqrt((x - x2)^2 + (y - y2)^2) / sqrt((x - x1)^2 + (y - y1)^2) ->
x1*x2 + y1*y2 = -x^2 + x*x1 - y^2 + y*y1 + x*x2 + y*y2 + x^2 -x*x1 - x*x2 +x1*x2 + y^2 - y*y1 - y*y2 + y1*y2 ->
0 = 0
Ugly formulas...
This way it's pretty hard to find intersection point coordinates. Is there any easier way to do what i want ?
 

eimie

Member
I didn't test this code. The idea is to anticipate the future position of the player object and check the distance to the torrent.
If the distance is equal or below the bullet_speed * future frames, the torrent will create the bullet and tells it the target coordinates.
Hope this code works and wish you good luck!

GML:
// Considering your objects are named player, torrent and bullet and the player makes use of hspeed and vspeed this code is placed in the torrent's Step event.

// define the point where the bullet should shoot at...
pointX = player.x;
pointY = player.y;

// ... but don't shoot
shoot = false;

for (var i = 1; i < 500; i++) {
    // anticipate the player's position in future turns
    pointX += player.hspeed;
    pointY += player.vspeed;

    // check the distance
    if (distance_to_point(pointX, pointY) <= bullet_speed * i) {
        shoot = true;
        break;
    }
}

if (shoot) {
    var my_bullet = instance_create_depth(x, y, depth, bullet);
    my_bullet.targetX = pointX;
    my_bullet.targetY = pointY;
}
 
It sounds like you might be able to make use of https://www.gmlscripts.com/script/intercept_course
This code is pretty simple, because here player calculate everything with his eyes and brain. So i can write it by myself, I need something more specific.
The enemy, which will shoot at the player, after some misses must understand where the player (we think that player don't change his direction and speed) will move. And with knowing the speed of his bullet, he must shoot at the point, where player would be.

I didn't test this code. The idea is to anticipate the future position of the player object and check the distance to the torrent.
If the distance is equal or below the bullet_speed * future frames, the torrent will create the bullet and tells it the target coordinates.
Hope this code works and wish you good luck!

GML:
// Considering your objects are named player, torrent and bullet and the player makes use of hspeed and vspeed this code is placed in the torrent's Step event.

// define the point where the bullet should shoot at...
pointX = player.x;
pointY = player.y;

// ... but don't shoot
shoot = false;

for (var i = 1; i < 500; i++) {
    // anticipate the player's position in future turns
    pointX += player.hspeed;
    pointY += player.vspeed;

    // check the distance
    if (distance_to_point(pointX, pointY) <= bullet_speed * i) {
        shoot = true;
        break;
    }
}

if (shoot) {
    var my_bullet = instance_create_depth(x, y, depth, bullet);
    my_bullet.targetX = pointX;
    my_bullet.targetY = pointY;
}
Thanks for idea, i think i can adjust this to myself. I just realized that enemy moves too (hence the bullet), so i'll have to do some work with vectors, but i hope that everything will be fine.
 

chamaeleon

Member
This code is pretty simple, because here player calculate everything with his eyes and brain. So i can write it by myself, I need something more specific.
The enemy, which will shoot at the player, after some misses must understand where the player (we think that player don't change his direction and speed) will move. And with knowing the speed of his bullet, he must shoot at the point, where player would be.
What makes you think the player is calculating anything?
 
What makes you think the player is calculating anything?
Sorry, there was a demo and I thought that it reflects the entire code (because i thought that i control the cursor and as it turned out, it wasn't me who was so accurate, but the cursor itself moved in the calculated direction), so I didn't look at it much. I apologize for such hasty conclusions
 
Last edited:

chamaeleon

Member
Sorry, there was a demo and I thought that it reflects the entire code, so I didn't look at it much. I apologize for such hasty conclusions
The demo works to show automatic angle calculation like you asked for. Just click in the same location every the time, without trying to aim yourself, and you'll see the aiming line being calculated automatically towards a target.
 
The demo works to show automatic angle calculation like you asked for. Just click in the same location every the time, without trying to aim yourself, and you'll see the aiming line being calculated automatically towards a target.
Yeah i got it, sorry mate i didn't sleep well so i ignored a lot of information at the morning, thank you for helping
 
It sounds like you might be able to make use of https://www.gmlscripts.com/script/intercept_course
I tried to understand what happening in his formula and still didn't get it this beta = alpha * sin(phi); makes me confused.
I tried to make my own formula and it looks a lil bit bigger than in your example, but still (i hope) works fine.

GML:
// so we got 3 points with their coordinates
// A(x0, y0); B(x1, y1); C(x, y)   
// A - is a target, B - is the object that shoots,
// C - is the meeting point of bullet and target
// target has vertical and horisontal speed (Vv0, Vh0)
// target has vertical and horisontal speed (Vv1, Vh1)
// we don't know them, but we know bullet speed (Sp)
// and we know that (Sp)^2 = (Vv1)^2 + (Vh1)^2
// so let's write 5 equations with 5 unknown elements:

// var x,y,x0,y0,x1,y1,Sp,Vv0,Vv1,Vh0,Vh1

x = x0 + Vh0*t; // here we write that the final coordinate of the target
                //on the X-axis (x) is equal to the initial coordinate of
                //the target on the X-axis (x0) + the speed of the target
                //on the X-axis multiplied by time
x = x1 + Vh1*t; // same
y = y0 + Vv0*t;
y = y1 + Vv1*t;
(Sp)^2 = (Vv1)^2 + (Vh1)^2;           

// let's get rid of x and y:

x1 + Vh1*t = x0 + Vh0*t;
y1 + Vv1*t = y0 + Vv0*t;
(Sp)^2 = (Vv1)^2 + (Vh1)^2;    // forget about it for some time   

// now we got only 3 formulas, calm down (and we don't know: t, Vv1, Vh1)
//  let's get rid of time now:

x1 - x0 = (Vh0 - Vh1)*t;
y1 - y0 = (Vv0 - Vv1)*t;

(x1 - x0)/(Vh0 - Vh1) = t;
(y1 - y0)/(Vv0 - Vv1) = t;

(x1 - x0)/(Vh0 - Vh1) = (y1 - y0)/(Vv0 - Vv1);
// so we get this:
(x1 - x0)/(y1 - y0) = (Vh0 - Vh1)/(Vv0 - Vv1);

// (x1 - x0)/(y1 - y0) - this part is equal to ctg(alpha),
// alpha = point_direction(x1, y1, x0, y0); // and we know it
// (x1 - x0)/(y1 - y0) = ctg(point_direction(x1, y1, x0, y0)); // you can use 1/tg();
// next, I will write ctg(a) instead of ctg(point_direction(x1, y1, x0, y0))

ctg(a) = (Vh0 - Vh1)/(Vv0 - Vv1);
ctg(a) = (Vh1 - Vh0)/(Vv1 - Vv0); // nothing changes
ctg(a)*(Vv1 - Vv0) = (Vh1 - Vh0); // remember (Sp)^2 = (Vv1)^2 + (Vh1)^2;
ctg(a)*(Vv1 - Vv0) = sqrt( (Sp)^2 - (Vv1)^2 ) - Vh0;

// now the worst part, we have to square it up, but before we do this
ctg(a)*(Vv1 - Vv0) + Vh0= sqrt( (Sp)^2 - (Vv1)^2 );

//let's start: (a+b)^2 = a^2 + 2*a*b + b^2
(ctg(a))^2 * ( (Vv1)^2 - 2*(Vv1)*(Vv0) + (Vv0)^2 ) + // a^2
2*ctg(a)*(Vv1)*(Vh0) - 2*ctg(a)*(Vv0)*(Vh0) + // 2*a*b
(Vh0)^2 = // b^2
(Sp)^2 - (Vv1)^2;

// same inline code
(ctg(a))^2 * ( (Vv1)^2 - 2*(Vv1)*(Vv0) + (Vv0)^2 ) + 2*ctg(a)*(Vv1)*(Vh0) - 2*ctg(a)*(Vv0)*(Vh0) + (Vh0)^2 = (Sp)^2 - (Vv1)^2;

// I think that we can change ctg(a) to C (const)
//                                  Sp to S (const)
//                                 Vv1 to x (unknown element)
//                                 Vv0 to A (const)
//                                 Vh0 to B (const)
// Okay ? I hope so

// var C = ctg(point_direction(x1, y1, x0, y0)),
// S = Sp, x = Vv1, A = Vv0, B = Vh0;

C^2 * (x^2 - 2*x*A + A^2) + 2*C*x*B - 2*C*A*B + B^2 = S^2 - x^2;
C^2*x^2 - 2*C^2*A*x + C^2*A^2 + 2*C*x*B - 2*C*A*B + B^2 = S^2 - x^2;

//here we got _x^2 + _x + _ = 0
(1 + C^2)*x^2 + 2*C*(B - C*A)*x + C^2*A^2 - 2*C*A*B + B^2 - S^2 = 0;

// we need to get at least one solution -> D >= 0 (we'll check this later)
D = (2*C*(B - C*A))^2 - 4*(1 + C^2)*(C^2*A^2 - 2*C*A*B + B^2 - S^2);
D = 4*C^2*(B^2 - 2*B*A*C + C^2*A^2) + (- 4*C^2*A^2 + 8*C*A*B - 4*B^2 + 4*S^2) + (- 4*C^4*A^2 + 8*C^3*A*B - 4*C^2*B^2 + 4*C^2*S^2);
D = 4*C^2*B^2 - 8*B*A*C^3 + 4*C^4*A^2 - 4*C^2*A^2 + 8*C*A*B - 4*B^2 + 4*S^2 - 4*C^4*A^2 + 8*C^3*A*B - 4*C^2*B^2 + 4*C^2*S^2;
D = (4*C^2*B^2 - 4*C^2*B^2) + (- 8*B*A*C^3 + 8*C^3*A*B) + (4*C^4*A^2 - 4*C^4*A^2) + 8*C*A*B - 4*B^2 + 4*S^2 - 4*C^2*A^2 + 4*C^2*S^2;
D = 8*C*A*B - 4*B^2 + 4*S^2 - 4*C^2*A^2 + 4*C^2*S^2;
D = 2*C*A*B - B^2 + S^2 - C^2*A^2 + C^2*S^2;
D = S^2*(1 + C^2) - (B - A*C)^2; // >= 0

// 1 + C^2 == 1 + (ctg(a))^2 == 1/(sin(a))^2
// and we got a^2 - b^2 >= 0
// the solution will be:
// a = S/sin(a)
// b = B - A*C
// (a-b > 0 && a+b > 0) || (a-b < 0 && a+b < 0) || (a-b == 0) || (a+b == 0)
// (a > b && a > -b) || (a < b && a < -b) || (a == b) || (a == -b)
if (S/sin(a) + A*C > B && S/sin(a) + B > A*C) ||
   (S/sin(a) + A*C < B && S/sin(a) + B < A*C) ||
   (S/sin(a) + A*C == B) || (S/sin(a) + B == A*C)
(then your shoot will be possible (this is the whole range of it))

Your x = (-b +-sqrt(D))/2a ->
Vv1 = x = ( 2*C*(C*A - B) +- sqrt(S^2*(1 + C^2) - (B - A*C)^2) )/(2*(1 + C^2))
Vh1 = sqrt(S^2 - x^2) = sqrt(Sp^2 - Vv1^2)

// If there is any way to make your speed const
// and be able to change horizontal and vertical speed
// it will be enough to change one of them
 
Top