Example #1
0
        /// <summary>
        /// Redirects a cylinder sphere to be on collision course towards a point
        /// </summary>
        /// <param name="transition">The transition information for the sphere</param>
        /// <param name="checkPos">The spherical point to redirect towards</param>
        /// <param name="disp">Used for calculating the collision normal</param>
        /// <param name="radsum">The sum of the sphere and spherical point radii</param>
        /// <param name="sphereNum">Used as an offset in path.GlobalCurrCenter to determine movement</param>
        /// <returns>The TransitionState either collided or adjusted</returns>
        public TransitionState CollideWithPoint(Transition transition, Sphere checkPos, Vector3 disp, float radsum, int sphereNum)
        {
            var obj        = transition.ObjectInfo;
            var path       = transition.SpherePath;
            var collisions = transition.CollisionInfo;

            Vector3 collisionNormal;
            var     definate = CollisionNormal(transition, checkPos, disp, radsum, sphereNum, out collisionNormal);

            if (CollisionInfo.NormalizeCheckSmall(ref collisionNormal))
            {
                return(TransitionState.Collided);
            }
            if (!obj.State.HasFlag(ObjectInfoState.PerfectClip))
            {
                collisions.SetCollisionNormal(collisionNormal);
                return(TransitionState.Collided);
            }
            var globCenter = path.GlobalCurrCenter[0].Center;
            var movement   = LandDefs.GetBlockOffset(path.CurPos.ObjCellID, path.CheckPos.ObjCellID);

            movement += checkPos.Center - globCenter;
            var old_disp = globCenter - LowPoint;

            radsum += PhysicsGlobals.EPSILON;

            // this is similar to ray/sphere intersection, could be inlined...
            var     xyMoveLenSq = movement.LengthSquared2D();
            var     xyDiff = -movement.Dot2D(old_disp);
            var     diffSq = xyDiff * xyDiff - (old_disp.LengthSquared2D() - radsum * radsum) * xyMoveLenSq;
            var     diff = (float)Math.Sqrt(diffSq);
            Vector3 scaledMovement, offset;
            float   time;   // calculated below, refactor

            if (!definate)
            {
                if (Math.Abs(movement.Z) < PhysicsGlobals.EPSILON)
                {
                    return(TransitionState.Collided);
                }
                if (movement.Z > 0.0f)
                {
                    collisionNormal = new Vector3(0, 0, -1.0f);
                    time            = (movement.Z + checkPos.Radius) / movement.Z * -1.0f;
                }
                else
                {
                    collisionNormal = new Vector3(0, 0, 1.0f);
                    time            = (checkPos.Radius + Height - movement.Z) / movement.Z;
                }

                scaledMovement = movement * time;
                var scaledLenSq = (scaledMovement + old_disp).LengthSquared2D();
                if (scaledLenSq >= radsum * radsum)
                {
                    if (Math.Abs(xyMoveLenSq) < PhysicsGlobals.EPSILON)
                    {
                        return(TransitionState.Collided);
                    }

                    if (diffSq >= 0.0f && xyMoveLenSq > PhysicsGlobals.EPSILON)
                    {
                        if (xyDiff - diff < 0.0f)
                        {
                            time = (float)((diff - movement.Dot2D(old_disp)) / xyMoveLenSq);
                        }
                        else
                        {
                            time = (float)((xyDiff - diff) / xyMoveLenSq);
                        }

                        scaledMovement = movement * time;
                    }
                    collisionNormal   = (scaledMovement + globCenter - LowPoint) / radsum;
                    collisionNormal.Z = 0.0f;
                }

                if (time < 0.0f || time > 1.0f)
                {
                    return(TransitionState.Collided);
                }

                offset = globCenter - scaledMovement - checkPos.Center;
                path.AddOffsetToCheckPos(offset, checkPos.Radius);
                collisions.SetCollisionNormal(collisionNormal);

                return(TransitionState.Adjusted);
            }

            if (collisionNormal.Z != 0.0f)
            {
                if (Math.Abs(movement.Z) < PhysicsGlobals.EPSILON)
                {
                    return(TransitionState.Collided);
                }

                if (movement.Z > 0.0f)
                {
                    time = -((old_disp.Z + checkPos.Radius) / movement.Z);
                }
                else
                {
                    time = (checkPos.Radius + Height - old_disp.Z) / movement.Z;
                }

                scaledMovement = movement * time;

                if (time < 0.0f || time > 1.0f)
                {
                    return(TransitionState.Collided);
                }

                offset = globCenter + scaledMovement - checkPos.Center;
                path.AddOffsetToCheckPos(offset, checkPos.Radius);
                collisions.SetCollisionNormal(collisionNormal);

                return(TransitionState.Adjusted);
            }

            // duplicated from above, refactor...
            if (diffSq < 0.0f || xyMoveLenSq < PhysicsGlobals.EPSILON)
            {
                return(TransitionState.Collided);
            }

            if (xyDiff - diff < 0.0f)
            {
                time = (float)((diff - movement.Dot2D(old_disp)) / xyMoveLenSq);
            }
            else
            {
                time = (float)((xyDiff - diff) / xyMoveLenSq);
            }

            scaledMovement = movement * time;
            if (time < 0.0f || time > 1.0f)
            {
                return(TransitionState.Collided);
            }

            collisionNormal   = (scaledMovement + globCenter - LowPoint) / radsum;
            collisionNormal.Z = 0.0f;
            offset            = globCenter + scaledMovement - checkPos.Center;
            path.AddOffsetToCheckPos(offset, checkPos.Radius);
            collisions.SetCollisionNormal(collisionNormal);

            return(TransitionState.Adjusted);
        }
Example #2
0
        /// <summary>
        /// Determines if this sphere collides with anything during its transition
        /// </summary>
        /// <param name="transition">The transition path for this sphere</param>
        /// <param name="isCreature">Flag indicates if this sphere is a player / monster</param>
        /// <returns>The collision result for this transition path</returns>
        public TransitionState IntersectsSphere(Transition transition, bool isCreature)
        {
            var globSphere = transition.SpherePath.GlobalSphere[0];
            var disp       = globSphere.Center - Center;

            Sphere  globSphere_ = null;
            Vector3 disp_       = Vector3.Zero;

            if (transition.SpherePath.NumSphere > 1)
            {
                globSphere_ = transition.SpherePath.GlobalSphere[1];
                disp_       = globSphere_.Center - Center;
            }

            var radsum = globSphere.Radius + Radius - PhysicsGlobals.EPSILON;

            if (transition.SpherePath.ObstructionEthereal || transition.SpherePath.InsertType == InsertType.Placement)
            {
                if (disp.LengthSquared() <= radsum)
                {
                    return(TransitionState.Collided);
                }

                if (transition.SpherePath.NumSphere > 1)
                {
                    if (CollidesWithSphere(disp_, radsum))
                    {
                        return(TransitionState.Collided);
                    }
                }
                return(TransitionState.OK);
            }

            if (!transition.SpherePath.StepDown)
            {
                if (transition.SpherePath.CheckWalkable)
                {
                    if (CollidesWithSphere(disp, radsum))
                    {
                        return(TransitionState.Collided);
                    }

                    if (transition.SpherePath.NumSphere > 1)
                    {
                        if (CollidesWithSphere(disp_, radsum))
                        {
                            return(TransitionState.Collided);
                        }
                    }
                    return(TransitionState.OK);
                }
                if (transition.SpherePath.StepUp)
                {
                    if (transition.ObjectInfo.State.HasFlag(ObjectInfoState.Contact) ||
                        transition.ObjectInfo.State.HasFlag(ObjectInfoState.OnWalkable))
                    {
                        if (CollidesWithSphere(disp, radsum))
                        {
                            return(StepSphereUp(transition, globSphere, disp, radsum));
                        }

                        if (transition.SpherePath.NumSphere > 1)
                        {
                            if (CollidesWithSphere(disp_, radsum))
                            {
                                return(SlideSphere(transition, globSphere_, disp_, radsum, 1));
                            }
                        }
                    }
                    else if (transition.ObjectInfo.State.HasFlag(ObjectInfoState.PathClipped))
                    {
                        if (CollidesWithSphere(disp, radsum))
                        {
                            return(CollideWithPoint(transition, globSphere, disp, radsum, 0));
                        }
                    }
                    else
                    {
                        if (CollidesWithSphere(disp, radsum))
                        {
                            return(LandOnSphere(transition, globSphere, disp, radsum));
                        }

                        if (transition.SpherePath.NumSphere > 1)
                        {
                            if (CollidesWithSphere(disp_, radsum))
                            {
                                return(CollideWithPoint(transition, globSphere_, disp_, radsum, 1));
                            }
                        }
                    }
                    return(TransitionState.OK);
                }

                if (isCreature)
                {
                    return(TransitionState.OK);
                }

                // handles movement interpolation
                if (CollidesWithSphere(disp, radsum) || (transition.SpherePath.NumSphere > 1 && CollidesWithSphere(disp_, radsum)))
                {
                    var blockOffset = transition.SpherePath.GetCurPosCheckPosBlockOffset();
                    var movement    = transition.SpherePath.GlobalCurrCenter[1].Center - globSphere.Center - blockOffset;   // verify offset 14
                    radsum += PhysicsGlobals.EPSILON;
                    var lenSq = movement.LengthSquared();
                    var diff  = -Vector3.Dot(movement, disp);
                    if (Math.Abs(lenSq) < PhysicsGlobals.EPSILON)
                    {
                        return(TransitionState.Collided);
                    }

                    var t = Math.Sqrt(diff * diff - (disp.LengthSquared() - radsum * radsum) * lenSq) + diff;   // solve for t
                    if (t > 1)
                    {
                        t = diff * 2 - diff;
                    }
                    var time      = diff / lenSq;
                    var timecheck = (1 - time) * transition.SpherePath.WalkInterp;
                    if (timecheck < transition.SpherePath.WalkableAllowance && timecheck < -0.1f)
                    {
                        return(TransitionState.Collided);
                    }

                    movement *= time;
                    disp      = (disp + movement) / radsum;

                    if (!transition.SpherePath.IsWalkableAllowable(disp.Z))
                    {
                        return(TransitionState.OK);                                                              // ??
                    }
                    var contactPlane = new Plane(disp, (globSphere.Center - disp * globSphere.Radius).Length()); // verify, convert normal
                    transition.CollisionInfo.SetContactPlane(contactPlane, true);
                    transition.CollisionInfo.ContactPlaneCellID = transition.SpherePath.CheckPos.ObjCellID;
                    transition.SpherePath.WalkInterp            = timecheck;
                    transition.SpherePath.AddOffsetToCheckPos(movement, globSphere.Radius);
                    return(TransitionState.Adjusted);
                }

                return(TransitionState.OK);
            }

            if (!isCreature)
            {
                return(StepSphereDown(transition, globSphere, disp, radsum));
            }

            return(TransitionState.OK);
        }
Example #3
0
        /// <summary>
        /// Determines if this CylSphere collides with anything during its transition
        /// </summary>
        /// <param name="transition">The transition path for this cylinder sphere</param>
        /// <returns>The collision result for this transition path</returns>
        public TransitionState IntersectsSphere(Transition transition)
        {
            var obj  = transition.ObjectInfo;
            var path = transition.SpherePath;

            var globSphere = path.GlobalSphere[0];
            var disp       = globSphere.Center - LowPoint;

            Sphere  globSphere_ = null;
            Vector3 disp_       = Vector3.Zero;

            if (path.NumSphere > 1)
            {
                globSphere_ = path.GlobalSphere[1];
                disp_       = globSphere_.Center - LowPoint;
            }

            var radsum = Radius - PhysicsGlobals.EPSILON + globSphere.Radius;

            if (path.InsertType == InsertType.Placement || path.ObstructionEthereal)
            {
                if (CollidesWithSphere(globSphere, disp, radsum))
                {
                    return(TransitionState.Collided);
                }

                if (path.NumSphere > 1 && CollidesWithSphere(globSphere_, disp_, radsum))
                {
                    return(TransitionState.Collided);
                }

                return(TransitionState.OK);
            }
            else
            {
                if (path.StepDown)
                {
                    return(StepSphereDown(transition, globSphere, disp, radsum));
                }

                if (path.CheckWalkable)
                {
                    if (CollidesWithSphere(globSphere, disp, radsum))
                    {
                        return(TransitionState.Collided);
                    }

                    if (path.NumSphere > 1)
                    {
                        if (CollidesWithSphere(globSphere_, disp_, radsum))
                        {
                            return(TransitionState.Collided);
                        }
                    }
                    return(TransitionState.OK);
                }

                if (!path.Collide)
                {
                    if (obj.State.HasFlag(ObjectInfoState.Contact) || obj.State.HasFlag(ObjectInfoState.OnWalkable))
                    {
                        if (CollidesWithSphere(globSphere, disp, radsum))
                        {
                            return(StepSphereUp(transition, globSphere, disp, radsum));
                        }

                        if (path.NumSphere > 1)
                        {
                            if (CollidesWithSphere(globSphere_, disp_, radsum))
                            {
                                return(SlideSphere(transition, globSphere_, disp, radsum, 1));
                            }
                        }
                    }
                    else if (obj.State.HasFlag(ObjectInfoState.PathClipped))
                    {
                        if (CollidesWithSphere(globSphere, disp, radsum))
                        {
                            return(CollideWithPoint(transition, globSphere, disp, radsum, 0));
                        }
                    }
                    else
                    {
                        if (CollidesWithSphere(globSphere, disp, radsum))
                        {
                            return(LandOnCylinder(transition, globSphere, disp, radsum));
                        }

                        if (path.NumSphere > 1)
                        {
                            if (CollidesWithSphere(globSphere_, disp_, radsum))
                            {
                                return(CollideWithPoint(transition, globSphere_, disp_, radsum, 1));
                            }
                        }
                    }
                    return(TransitionState.OK);
                }

                if (CollidesWithSphere(globSphere, disp, radsum) || path.NumSphere > 1 && CollidesWithSphere(globSphere_, disp_, radsum))
                {
                    var blockOffset = path.GetCurPosCheckPosBlockOffset();
                    var movement    = path.GlobalCurrCenter[0].Center - globSphere.Center - blockOffset;

                    // what is v39 pointing to before this?
                    var distSq = movement.LengthSquared();
                    //var diff = -Vector3.Dot(movement, disp);
                    var diff = movement.Z * disp.Z - movement.Dot2D(disp);

                    if (Math.Abs(distSq) < PhysicsGlobals.EPSILON)
                    {
                        return(TransitionState.Collided);
                    }

                    radsum += PhysicsGlobals.EPSILON;
                    var t = Math.Sqrt(diff * diff - (disp.LengthSquared() - radsum * radsum) * distSq) + diff;   // solve for t, no division?
                    if (t > 1)
                    {
                        t = diff * 2 - diff;
                    }
                    var time      = diff / distSq;
                    var timecheck = (1 - time) * transition.SpherePath.WalkInterp;
                    if (timecheck >= transition.SpherePath.WalkInterp || timecheck < -0.1f)
                    {
                        return(TransitionState.Collided);
                    }

                    movement *= time;
                    disp      = (disp + movement) / radsum;

                    if (!transition.SpherePath.IsWalkableAllowable(disp.Z))
                    {
                        return(TransitionState.OK);
                    }

                    var pDist        = -Vector3.Dot(disp, globSphere.Center - disp * globSphere.Radius);
                    var contactPlane = new Plane(disp, pDist);
                    transition.CollisionInfo.SetContactPlane(contactPlane, true);
                    transition.CollisionInfo.ContactPlaneCellID = transition.SpherePath.CheckPos.ObjCellID;
                    transition.SpherePath.WalkInterp            = timecheck;
                    transition.SpherePath.AddOffsetToCheckPos(movement, globSphere.Radius);
                    return(TransitionState.Adjusted);
                }
            }

            return(TransitionState.OK);
        }