Search code examples
c#xnacollision-detection

XNA, C# - Check if a Vector2 path crosses another Vector2 path


I have an XNA question for those with more experience in these matters than myself (maths).

Background: I have a game that implements a boundary class, this simply hosts 2 Vector2 objects, a start and an end point. The current implementation crudely handles collision detection by assuming boundaries are always vertical or horizontal, i.e. if start.x and end.x are the same check I am not trying to pass x etc.

Ideally what I would like to implement is a method that accepts two Vector2 parameters. The first being a current location, the second being a requested location (where I would like to move it to assuming no objections). The method would also accept a boundary object. What the method should then do is tell me if I am going to cross the boundry in this move. this could be a bool or ideally something representing how far I can actually move.

This empty method might explain better than I can in words.

        /// <summary>
    /// Checks the move.
    /// </summary>
    /// <param name="current">The current.</param>
    /// <param name="requested">The requested.</param>
    /// <param name="boundry">The boundry.</param>
    /// <returns></returns>
    public bool CheckMove(Vector2 current, Vector2 requested, Boundry boundry)
    { 
        //return a bool that indicated if the suggested move will cross the boundry.
        return true;
    }

Solution

  • After a fair bit of research and more than anything finding out the right terms to google I have a solution that I have just built into my test bed and it works perfectly.

    I have taken an example found on the net and tested it, then changed it to meet the needs of this question. It should be noted I have made changes since testing this as I only have a VM on this laptop that cannot run XNA apps so while I am confident it should work there may be mistakes.

    All we need to do is pass in a vector of where we are, a vector of where we would like to be and the boundary (which is effectively a line made up of a start and end vector). The method will tell tell us if the two lines (one being the path between the current location and the requested location and the other being the boundary) cross. As an added bonus if they do cross and out parameter will tell us where.

    This is a very useful system for creating powerful collision detection.

            /// <summary>
        /// Based on the 2d line intersection method from "comp.graphics.algorithms Frequently Asked Questions"
        /// </summary>
        /// <param name="currentLocation">The current location.</param>
        /// <param name="requestedLocation">The requested location.</param>
        /// <param name="boundary">The boundary.</param>
        /// <param name="collisionVector">The collision vector.</param>
        /// <returns></returns>
        public static bool Intersects(Vector2 currentLocation, Vector2 requestedLocation, Boundary boundary, ref Vector2 collisionVector)
        {
            float q = (currentLocation.Y - boundary.Start.Y) * (boundary.End.X - boundary.Start.X) - (currentLocation.X - boundary.Start.X) * (boundary.End.Y - boundary.Start.Y);
            float d = (requestedLocation.X - currentLocation.X) * (boundary.End.Y - boundary.Start.Y) - (requestedLocation.Y - currentLocation.Y) * (boundary.End.X - boundary.Start.X);
    
            if (d == 0) 
            {
                return false;
            }
    
            float r = q / d;
    
            q = (currentLocation.Y - boundary.Start.Y) * (requestedLocation.X - currentLocation.X) - (currentLocation.X - boundary.Start.X) * (requestedLocation.Y - currentLocation.Y);
            float s = q / d;
    
            if (r < 0 || r > 1 || s < 0 || s > 1)
            {
                return false;
            }
    
            collisionVector.X = currentLocation.X + (int)(0.5f + r * (requestedLocation.X - currentLocation.X));
            collisionVector.Y = currentLocation.Y + (int)(0.5f + r * (requestedLocation.Y - currentLocation.Y));
            return true;
        }