XNA, C # - Проверьте, пересекает ли путь Vector2 другой путь Vector2 - PullRequest
2 голосов
/ 22 декабря 2010

У меня есть вопрос XNA для тех, кто имеет больше опыта в этих вопросах, чем я (математика).

Справочная информация: у меня есть игра, в которой реализован граничный класс, в котором просто размещаются 2 объекта Vector2, старт иконечная точка.Текущая реализация грубо обрабатывает обнаружение столкновений, предполагая, что границы всегда вертикальные или горизонтальные, т. Е. Если start.x и end.x - это одна и та же проверка, я не пытаюсь передать x и т. Д.

В идеале то, что я хотел быреализовать - это метод, который принимает два параметра Vector2.Первое - это текущее местоположение, второе - запрошенное местоположение (куда я хотел бы переместить его, чтобы не было никаких возражений).Метод также принимает граничный объект.Затем метод должен сказать мне, собираюсь ли я пересечь границу в этом шаге.это может быть как бул или, в идеале, что-то, представляющее, как далеко я действительно могу двигаться.

Этот пустой метод может объяснить лучше, чем я, в словах.

        /// <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;
    }

Ответы [ 5 ]

2 голосов
/ 28 декабря 2010

После долгих исследований и более всего выяснения правильных терминов для Google у меня есть решение, которое я только что встроил в свой тестовый стенд, и оно отлично работает.

Я взял пример, найденный в сети, и проверил его, а затем изменил, чтобы удовлетворить потребности этого вопроса. Следует отметить, что с момента тестирования я внес изменения, так как на этом ноутбуке есть только виртуальная машина, на которой не могут запускаться приложения XNA, поэтому, хотя я уверен, что она должна работать, могут быть ошибки.

Все, что нам нужно сделать, это передать вектор того, где мы находимся, вектор того, где мы хотели бы быть, и границу (которая фактически является линией, состоящей из начального и конечного векторов). Метод скажет нам, пересекаются ли две линии (одна - путь между текущим местоположением и запрошенным местоположением, а другая - граница). В качестве дополнительного бонуса, если они действительно пересекаются, параметр скажет нам, где.

Это очень полезная система для создания мощного обнаружения столкновений.

        /// <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;
    }
2 голосов
/ 22 декабря 2010

Я уже предложил ответ, но вот еще один, похожий, но другой:

Я бы использовал вариант Расстояние от линии до точки, как еще раз взято из Вольфрама!http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html

Если вы возьмете уравнение 14, но уберете абсолютное значение (| |) в числителе, вы получите расстояние со знаком.Я никогда не слышал о подписанной концепции расстояния, поэтому не ожидайте, что этот термин будет точным.Итак, если расстояние между пунктом отправления и пунктом назначения отличается, это означает, что пункт назначения и пункт назначения находятся на противоположных сторонах линии:

public bool CheckMove(Vector2 current, Vector2 requested, Boundry boundry)
{
    // Assuming you got 2 points in boundry.
    float signedDistanceCurrent = GetSignedDistance(current, boundry.Vector1, boundry.Vector2);
    float signedDistanceRequested = GetSignedDistance(current, boundry.Vector1, boundry.Vector2);

    return signedDistanceRequested * signedDistanceCurrent < 0;
}

public float GetSignedDistance(Vector2 point0, Vector2 point1, Vector2 point2)
{
    // Equation 14 without the |s.
    return ((point2.X-point1.X)*(point1.Y-point0.Y)-(point2.X-point0.X)*(point2.Y-point1.Y))/((point2.X-point1.X)^2+(point2.Y-point1.Y)^2)^(0.5F);
}

Кстати, я предпочитаю этот ответ своему предыдущемуодин, но это зависит от вас.

Редактировать: Кстати, с помощью этого метода вы также можете узнать, когда произошло столкновение: Если вы сделаете это:

float timeFractionToCollision = -signedDistanceCurrent / (signedDistanceRequested - signedDistanceCurrent);

Вы получитедоля периода часть периода времени, в котором произошло столкновение.

0 голосов
/ 22 декабря 2010

Я думаю, что вы пытаетесь сделать это пересечение 2D-лучей (с выравниванием по оси). Вы можете найти много онлайн-алгоритмов для этого, включая этот: http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter3.htm

0 голосов
/ 22 декабря 2010

Для всех ваших математических потребностей я советую вам сначала попробовать MathWorld.Wolfram.Com.Вот статья о пересечении линия-линия: http://mathworld.wolfram.com/Line-LineIntersection.html

Интересующая вас часть, включая четвертое уравнение.

Используя это, вы получите координату пересечения.Затем вы можете проверить, будет ли эта координата пересекаться во время этого движения.Для этой проверки вы можете сделать что-то вроде:

public bool CheckMove(Vector2 current, Vector2 requested, Boundry boundry)
{
    // If your object doesn't move, it can't hit anything!
    if (current.X == requested.X && current.Y == requested.Y) { return false; }

    Vector2 impactPoint = /* Your code to get the impact
                            point from the link above */;

    Vector2 movement = requested - current;
    float timeToImpact = 0;
    // We checked for object movement already, so it's either moving in X, Y or both.
    // I choose to check for X first, but you could check for Y.
    if (movement.X != 0)
    {
        timeToImpact = (impactPoint.X - current.X) / movement.X;
    }
    else
    {
        timeToImpact = (impactPoint.Y - current.Y) / movement.Y;
    }

    // I don't consider a collision at 0 to be a collision since I think
    // it had to be resolved the period before.
    return timeToImpact <= 1 && timeToImpact > 0;
}
0 голосов
/ 22 декабря 2010

я думаю, что вы хотите найти их угол, так что просто сделайте X / Y и сравните, если угол одинаков, они параллельны

как это:

float radians = (float)Math.Atan2(vector.X, vector.Y);
...