0

I've been scratching my head for a couple of days on this one.

In my 2D top down game I have an array of FloatRects which represents walls. I want to shoot a bullet represented by a point at X distance from the player (X being the weapon's range).

What I want to do is to check if there is a wall on the bullet's trajectory and if there is set the new bullet target to the collision point.

To do this I've tried to check if a side of a rectangle intersects with my bullet's trajectory line using this solution: https://stackoverflow.com/a/1968345/10546991

I've used the program linked above but it gives me strange results, when the target is higher than the player the bullet just shoot behind.

Take a look at the following example :

Note : In SFML the Y axis points down

A is the player

B is the bullet's impact point or target, call it however you want.

C is the rectangle's Top Left side

D is the rectangle's Top Right side

(2500,2000) = a

(2500, 1300) = b

(2400, 2500) = c

(2600, 2500) = d

S1 = (0, -700)
S2 = (200, 0)

numeratorS = 700 * -100
numeratorT = 200 * -500

denominator = -200 * 700

s = 700 * - 100 / -200 * 700 = -70 000 / -140 000 = 7/14 = 1/2
t = -100 000 / -140 000 = 10 / 14 = 5 / 7

intersectionPoint.x = 2500 + (1/2 * 0) = 2500
intersectionPoint.y = 2000 + (1/2 * -700) = 1650

intersectionPoint (2500,1650)

So as you can see when testing if there is an intersection between the line between the player and the bullet's impact point and the top side of the rectangle (which is below the player) the program finds an intersection in between the player and the bullet!

I'm also providing a part of the code I use to detect collisions

    Vector2f intersectionPoint = target;

    //Check if bullet hits a wall and calculate new target
    for (int i = 0; i < arraySize; i++)
    {
        float intersectionPointMagnitude = sqrt(intersectionPoint.x * intersectionPoint.x + intersectionPoint.y * intersectionPoint.y);

        //Storing rect corner positions
        Vector2f rectTopLeft;
        rectTopLeft.x = collisions[i].left;
        rectTopLeft.y = collisions[i].top;

        Vector2f rectBottomLeft;
        rectBottomLeft.x = collisions[i].left;
        rectBottomLeft.y = collisions[i].top + collisions[i].height;

        Vector2f rectBottomRight;
        rectBottomRight.x = collisions[i].left + collisions[i].width;
        rectBottomRight.y = collisions[i].top + collisions[i].height;

        Vector2f rectTopRight;
        rectTopRight.x = collisions[i].left + collisions[i].width;
        rectTopRight.y = collisions[i].top;


        Vector2f intersectionLeft = intersectionPoint;
        if (Maths::vectorsIntersect(start, target, rectTopLeft, rectBottomLeft, intersectionLeft))
        {
            //We want to set a new target only if the detected collision is closer than the previous one
            intersectionLeft = intersectionLeft - start;
            float intersectionLeftMagnitude = sqrt(intersectionLeft.x * intersectionLeft.x +      intersectionLeft.y * intersectionLeft.y);

            if (intersectionLeftMagnitude < intersectionPointMagnitude)
            {
                intersectionPoint = intersectionLeft;
                target = start + intersectionPoint;
            }
        }

I just can't understand where the issue is coming from so if anyone could help me out it'll be greatly appreciated.

Edit : Here is Maths::vectorsIntersect which is really similar to the function in the link above

 bool vectorsIntersect(Vector2f A, Vector2f B, Vector2f C, Vector2f D, Vector2f& intersectionPoint)
 {
  Vector2f S1 = B - A;
  Vector2f S2 = D - C;
  
  //Calculate scalar parameters
  float denominator = (S1.x * S2.y - S1.y * S2.x);

  //We can't divide by 0!
  if (denominator == 0.0f)
   return false;

  //S & T have the same denominator
  float numeratorS = (S1.x * (A.y - C.y) - S1.y * (A.x - C.x));

  float numeratorT = (S2.x * (A.y - C.y) - S2.y * (A.x - C.x));

  float s, t;
  s = numeratorS / denominator;
  t = numeratorT / denominator;

  //Check for intersection point
  if (abs(s) > 0.0f && abs(s) < 1.0f && abs(t) > 0.0f && abs(t) < 1.0f)
  {
   //Return intersection point
   intersectionPoint.x = A.x + (t * S1.x);
   intersectionPoint.y = A.y + (t * S1.y);
   return true;
  }

  return false;
 }

EDIT 2 : Alright I feel stupid now, in my Maths::vectorIntersect function I was checking if the absolute values of both s and t are between 0 and 1, which is why when the scalar parameters where between -0 and -1 the function returned true and led to unexpected behaviors.

Problem solved thank you for the help

  • If `Maths::vectorsIntersect` is your own function, please show it. – Max Langhof Nov 22 '18 at 16:25
  • In any case, you need to distinguish more between points and vectors. You are initially calculating the magnitude of the target _point_ (which makes little sense) and later compare it with the magnitude of the distance from start to intersection point (a vector). If the target point is sufficiently close to the origin (_not_ the start point) you will never accept any collision. – Max Langhof Nov 22 '18 at 16:27
  • Hi, Maths::vectorsIntersect is the same function as the one I linked in my original post, sorry for not being precise. Also, you are right I didn't see I was calculating intersectionPoint's magnitude and not the distance between the start and the intersection point, that being said my problem still persists –  Nov 22 '18 at 16:42
  • 1
    In my understanding, the functions provided in the reference detect if the _line segments_ and not the _lines_ intersect. Your two segments (A,B) and (C,D) do not intersect, and the function (I just tested the function `vectorsIntersect`) returns 'no detection'. In this scenario, the value of the intersection point is undefined. – Damien Nov 22 '18 at 17:08

0 Answers0