0

I have a 2d space with multiple objects(Lets call them B). Lets say object A our automated actor, he moves in a specific path and he has to shoot only the objects it can destroy. The other objects might or might not move.

I need to find the direction that I should fire the bullet that will collide with the object B. The bullet is moving with a different speed that object A and it has a specific lifetime.

Diagram

I've tried to solve it with Quadratic but I always get infinity, is this a wrong approach?

                Vector3 vectorFromVictim = bullet.Position - victim.Position;
                float distanceToVictim = vectorFromVictim.Length();
                double victimSpeed = victim.Position.Length();               

                double a = bulletSpeed * bulletSpeed - victimSpeed * victimSpeed;
                double b = 2 * vectorFromVictim.Dot(victim.LinearVelocity);
                double c = -distanceToVictim * distanceToVictim;

                float t = (QuadraticSolver(a, b, c));
                if (float.IsInfinity(t))
                {
                    return;
                }

                interceptionPosition = victim.Position + victim.LinearVelocity * t;

                if (t <= bulletLifetime)
                {
                    ShootAtDirection(interceptionPosition);
                }

Edit: My QuadraticSolver is this

            double d = Math.Pow(b, 2) - (4 * a * c);
            
            if (d < 0)
            {
                return float.PositiveInfinity;
            }

            float t;
            if (d == 0)
            {
                t = (float) (-b / (2 * a));
                if (float.IsNaN(t))
                {
                    return float.PositiveInfinity;
                }
                return t;
            }

            t = (float) ((-b - Math.Sqrt(d)) / (2 * a));
            float t2 = (float) ((-b + Math.Sqrt(d)) / (2 * a));
            if (t < t2)
            {
                return t < 0 ? float.PositiveInfinity : t;
            }
            
            return t2 < 0 ? float.PositiveInfinity : t2;
Spektre
  • 49,595
  • 11
  • 110
  • 380
  • it looks there is a trivial error in your code. `double victimSpeed = victim.Position.Length();` should be `double victimSpeed = victim.LinearVelocity.Length();`. – ardget Jun 25 '22 at 18:05
  • see [Projectile Aim Prediction with Target Acceleration and Bullet Deceleration Varying with Angle](https://stackoverflow.com/a/71817221/2521214) and [C++ intersection time of 2 bullets](https://stackoverflow.com/a/71808916/2521214) – Spektre Jun 26 '22 at 07:28

1 Answers1

0

B (target) coordinates are

bx + ux * t, by + uy * t

where ux, uy are components of B velocity vector

Bullet coordinates are

ax + v * cos(f) * t, ay + v * sin(f) * t

where v is bullet speed, f is directional angle (unknown yet)

ax + v * cos(f) * t = bx + ux * t
ay + v * sin(f) * t = y + uy * t

t * (v * cos(f) - ux) = bx - ax = dx 
t * (v * sin(f) - uy) = bx - ax = dy
    dx, dy is position difference, negated your vectorFromVictim

exclude t

dy *  (v * cos(f) - ux) = dx * (v * sin(f) - uy) 
dy * v * cos(f) - dy * ux = dx * v * sin(f) - dx * uy 
v * (dy*cos(f) - dx*sin(f)) = dy * ux - dx * uy 

let

g = atan2(dy, dx)   
L = vectorFromVictim.Length

so

v * sin(g - f) = L * (dy * ux - dx * uy)
sin(g - f) = L/v * (dy * ux - dx * uy) 
g - f = arcsin(L/v * (dy * ux - dx * uy) ) 

and finally

f = g - arcsin(L/v * (dy * ux - dx * uy) ) 

Quiclk Python test

import math
def aiming(ax, ay, bx, by, ux, uy, v):
    dx = bx - ax
    dy = by - ay
    g = math.atan2(dy, dx)
    L = math.hypot(dy, dx)
    if (v * math.cos(ang) - ux):
        t = dx / (v * math.cos(ang) - ux)
    elif (v * math.sin(ang) - uy):
        t = dy / (v * math.sin(ang) - uy)
    else:
        return None 
    coll_x = bx + ux * t
    coll_y = by + uy * t
    return ang, coll_x, coll_y

print(aiming(0, 0, 0, 1, 1, 0, 1.4142))

gives correct value 0.7854 = Pi/4 radians = 45 degrees, and point (1,1)

MBo
  • 77,366
  • 5
  • 53
  • 86
  • 1. I don't take in account the radius of the bullet nor the object B, I should probably change that. 2. I tried it with the way you suggested in the other answer, but I don't have the velocity of the bullet before I fire it, that is why I tried a different approach. 3. Ok I will change that. – Ioannis Kiaras Jun 25 '22 at 14:13
  • [I found my answer to alike question](https://stackoverflow.com/questions/65695029) for circles with Python and JS code for reference – MBo Jun 25 '22 at 14:20
  • I will study it now. Thank you once again! – Ioannis Kiaras Jun 25 '22 at 14:23
  • How can I calculate the direction that the bullet should be fired though? I need to calculate if the bullet will hit the object based on the position B will have in the future – Ioannis Kiaras Jun 25 '22 at 14:31
  • Emm.. Sorry, I've already forgotten that you need `direction` to fire bullet to hit the target, so my answer is not quite suitable here. Will elaborate some later. – MBo Jun 25 '22 at 14:55
  • OK, answer is rewritten – MBo Jun 25 '22 at 15:22
  • I found the direction as you said with this "Vector3 shootDirection = new Vector3((float) Math.Sin(degrees), -(float) Math.Cos(degrees), b.Position.Z);" (Its pseudo 3D) I calculate the distance with the position of collision with this "size = shootDirection.Length() - b.BoundingRadius + bulletRadius;" (I evaluate also the radius of the object and the bullet) And then I check this "if (size <= bulletLifetime) {Shoot(shootDirection);}" Though it shoots at seemingly random direction and slows down the performance heavily, it runs every second for every enemy on the world. – Ioannis Kiaras Jun 25 '22 at 17:35
  • For normal coodinate system should be `shootDirection = (Cos(radians), Sin(radians), 0)`. I added meeting point also (without radii) – MBo Jun 25 '22 at 18:24