Пример #1
0
    public static DVector2 PredictShot(DVector2 origin, DReal projectileSpeed, DVector2 targetPosition, DVector2 targetVelocity)
    {
        var dp = targetPosition - origin;

        // Try to lead the target.
        var a = DVector2.Dot(targetVelocity, targetVelocity) - projectileSpeed * projectileSpeed;
        var b = 2 * DVector2.Dot(targetVelocity, dp);
        var c = DVector2.Dot(dp, dp);

        var p = -b / (2 * a);

        var discriminant = b * b - 4 * a * c;

        if (discriminant <= 0)
        {
            return(targetPosition);
        }

        DReal q;

        try {
            q = DReal.Sqrt(discriminant) / (2 * a);
        } catch (System.ArithmeticException) {
            return(targetPosition);
        }

        var   t1 = p - q;
        var   t2 = p + q;
        DReal t;

        if (t1 > t2 && t2 > 0)
        {
            t = t2;
        }
        else if (t1 > 0)
        {
            t = t1;
        }
        else
        {
            return(targetPosition);
        }

        return(targetPosition + targetVelocity * t);
    }
Пример #2
0
        public static bool IntersectLineCircle(DVector2 circleOrigin, DReal radius, DVector2 lineStart, DVector2 lineEnd, out DVector2 outIp)
        {
            var d = lineEnd - lineStart;      // ray direction.
            var f = lineStart - circleOrigin; // Vector from circle centre to ray start.

            var a = DVector2.Dot(d, d);
            var b = 2 * DVector2.Dot(f, d);
            var c = DVector2.Dot(f, f) - radius * radius;

            if (a == 0)
            {
                // start & end are close enough that distance = 0. Degrade to point/circle test.
                outIp = lineStart;
                return((lineStart - circleOrigin).sqrMagnitude < radius * radius);
            }

            var discriminant = b * b - 4 * a * c;

            if (discriminant < 0)
            {
                outIp = new DVector2();
                return(false);
            }

            // ray didn't totally miss sphere,
            // so there is a solution to
            // the equation.
            discriminant = DReal.Sqrt(discriminant);

            // either solution may be on or off the ray so need to test both
            // t1 is always the smaller value, because BOTH discriminant and
            // a are nonnegative.
            var t1 = (-b - discriminant) / (2 * a);
            var t2 = (-b + discriminant) / (2 * a);

            // 3x HIT cases:
            //          -o->             --|-->  |            |  --|->
            // Impale(t1 hit,t2 hit), Poke(t1 hit,t2>1), ExitWound(t1<0, t2 hit),

            // 3x MISS cases:
            //       ->  o                     o ->              | -> |
            // FallShort (t1>1,t2>1), Past (t1<0,t2<0), CompletelyInside(t1<0, t2>1)
            if (t1 >= 0 && t1 <= 1)
            {
                // t1 is the intersection, and it's closer than t2
                // (since t1 uses -b - discriminant)
                // Impale, Poke
                outIp = circleOrigin + d.normalized * -radius;
                return(true);
            }

            // here t1 didn't intersect so we are either started
            // inside the sphere or completely past it
            if (t2 >= 0 && t2 <= 1)
            {
                // ExitWound
                outIp = circleOrigin + d.normalized * radius;
                return(true);
            }

            // actually completely inside counts as a hit too.
            var startSqrDist = (lineStart - circleOrigin).sqrMagnitude;
            var endSqrDist   = (lineEnd - circleOrigin).sqrMagnitude;
            var sqrRadius    = radius * radius;

            if (startSqrDist < sqrRadius && endSqrDist < sqrRadius)
            {
                outIp = lineStart;
                return(true);
            }

            // no intn: FallShort, Past, CompletelyInside
            outIp = new DVector2();
            return(false);
        }