Beispiel #1
0
        public Vector3 AdjustOffset(Vector3 offset)
        {
            var collisionAngle = Vector3.Dot(offset, CollisionInfo.SlidingNormal);

            if (CollisionInfo.SlidingNormalValid && collisionAngle >= 0.0f)
            {
                CollisionInfo.SlidingNormalValid = false;
            }

            if (!CollisionInfo.ContactPlaneValid)
            {
                return(offset - CollisionInfo.SlidingNormal * collisionAngle);
            }

            var slideAngle = Vector3.Dot(CollisionInfo.ContactPlane.Normal, CollisionInfo.SlidingNormal);

            if (CollisionInfo.SlidingNormalValid)
            {
                var contactSlide = Vector3.Cross(CollisionInfo.ContactPlane.Normal, CollisionInfo.SlidingNormal);
                if (!CollisionInfo.NormalizeCheckSmall(ref contactSlide))
                {
                    offset = Vector3.Dot(contactSlide, offset) * contactSlide;
                }
                else
                {
                    offset = Vector3.Zero;
                }
            }
            else if (slideAngle <= 0.0f)
            {
                offset -= CollisionInfo.ContactPlane.Normal * slideAngle;
            }
            else
            {
                CollisionInfo.ContactPlane.SnapToPlane(offset);
            }

            if (CollisionInfo.ContactPlaneCellID == 0 || CollisionInfo.ContactPlaneIsWater)
            {
                return(offset);
            }

            var globSphere  = SpherePath.GlobalSphere[0];
            var blockOffset = LandDefs.GetBlockOffset(SpherePath.CheckPos.ObjCellID, CollisionInfo.ContactPlaneCellID);
            var dist        = Vector3.Dot(globSphere.Center - blockOffset, CollisionInfo.ContactPlane.Normal);

            if (dist >= globSphere.Radius - PhysicsGlobals.EPSILON)
            {
                return(offset);
            }

            var zDist = (globSphere.Radius - dist) / CollisionInfo.ContactPlane.Normal.Z;

            if (globSphere.Radius > Math.Abs(zDist))
            {
                offset = new Vector3(0.0f, 0.0f, zDist);
                SpherePath.AddOffsetToCheckPos(offset);
            }
            return(offset);
        }
Beispiel #2
0
        public TransitionState CliffSlide(Plane contactPlane)
        {
            var contactNormal = Vector3.Cross(contactPlane.Normal, CollisionInfo.LastKnownContactPlane.Normal);

            contactNormal.Z = 0.0f;

            var collideNormal = new Vector3(contactNormal.Z - contactNormal.Y, contactNormal.X - contactNormal.Z, 0);

            if (Vec.NormalizeCheckSmall(ref collideNormal))
            {
                return(TransitionState.OK);
            }

            var blockOffset = LandDefs.GetBlockOffset(SpherePath.CurPos.ObjCellID, SpherePath.CheckPos.ObjCellID);
            var offset      = SpherePath.GlobalSphere[0].Center - SpherePath.GlobalCurrCenter[0].Center;

            var angle = Vector3.Dot(collideNormal, offset + blockOffset);

            if (angle <= 0.0f)
            {
                SpherePath.AddOffsetToCheckPos(collideNormal * angle);
                CollisionInfo.SetCollisionNormal(collideNormal);
            }
            else
            {
                SpherePath.AddOffsetToCheckPos(collideNormal * -angle);
                CollisionInfo.SetCollisionNormal(-collideNormal);
            }
            return(TransitionState.Adjusted);
        }
Beispiel #3
0
        public TransitionState PrecipiceSlide(Transition transition)
        {
            var     collisions      = transition.CollisionInfo;
            Vector3 collisionNormal = Vector3.Zero;
            var     found           = Walkable.find_crossed_edge(WalkableCheckPos, WalkableUp, ref collisionNormal);

            if (!found)
            {
                Walkable = null;
                return(TransitionState.Collided);
            }

            Walkable        = null;
            StepUp          = false;
            collisionNormal = WalkablePos.Frame.LocalToGlobalVec(collisionNormal);

            var blockOffset = LandDefs.GetBlockOffset(CurPos.ObjCellID, CheckPos.ObjCellID);
            var offset      = GlobalSphere[0].Center - GlobalCurrCenter[0].Center + blockOffset;;

            if (Vector3.Dot(collisionNormal, offset) > 0.0f)
            {
                collisionNormal *= -1.0f;
            }

            return(GlobalSphere[0].SlideSphere(transition, collisionNormal, GlobalCurrCenter[0].Center));
        }
Beispiel #4
0
        /// <summary>
        /// Attempts to slide the sphere from a collision
        /// </summary>
        public TransitionState SlideSphere(Transition transition, Vector3 disp, float radsum, int sphereNum)
        {
            var path       = transition.SpherePath;
            var collisions = transition.CollisionInfo;

            var globSphere = path.GlobalSphere[sphereNum];

            var collisionNormal = path.GlobalCurrCenter[sphereNum].Center - Center;

            if (Vec.NormalizeCheckSmall(ref collisionNormal))
            {
                return(TransitionState.Collided);
            }

            collisions.SetCollisionNormal(collisionNormal);

            var contactPlane = collisions.ContactPlaneValid ? collisions.ContactPlane : collisions.LastKnownContactPlane;
            var skid_dir     = contactPlane.Normal;
            //var direction = Vector3.Cross(skid_dir, collisionNormal);
            var direction = Vector3.Cross(collisionNormal, skid_dir);

            var blockOffset = LandDefs.GetBlockOffset(path.CurPos.ObjCellID, path.CheckPos.ObjCellID);
            var globOffset  = globSphere.Center - path.GlobalCurrCenter[sphereNum].Center + blockOffset;
            var dirLenSq    = direction.LengthSquared();

            if (dirLenSq >= PhysicsGlobals.EPSILON)
            {
                skid_dir = Vector3.Dot(globOffset, direction) * direction;

                var invDirLenSq = 1.0f / dirLenSq;

                //skid_dir *= invDirLenSq * invDirLenSq;
                skid_dir *= invDirLenSq;
                direction = skid_dir;

                // only x?
                //if (direction.X * direction.X < PhysicsGlobals.EPSILON)
                if (direction.LengthSquared() < PhysicsGlobals.EPSILON)
                {
                    return(TransitionState.Collided);
                }

                direction -= globOffset;

                path.AddOffsetToCheckPos(direction, globSphere.Radius);
                return(TransitionState.Slid);
            }

            if (Vector3.Dot(skid_dir, disp) < 0.0f)
            {
                return(TransitionState.Collided);
            }

            direction = -Vector3.Dot(globOffset, collisionNormal) * collisionNormal;
            path.AddOffsetToCheckPos(direction, globSphere.Radius);
            return(TransitionState.Slid);
        }
Beispiel #5
0
 public void AdjustCheckPos(int cellID)
 {
     if (cellID < 100)   // ?
     {
         var offset = LandDefs.GetBlockOffset(cellID, CheckPos.ObjCellID);
         CacheGlobalSphere(offset);
         CheckPos.Frame.Origin += offset;
     }
     CheckPos.ObjCellID = cellID;
 }
Beispiel #6
0
        /// <summary>
        /// Attempts to slide a sphere from a collision
        /// </summary>
        public TransitionState SlideSphere(Transition transition, ref Vector3 collisionNormal, Vector3 currPos)
        {
            var path       = transition.SpherePath;
            var collisions = transition.CollisionInfo;

            if (collisionNormal.Equals(Vector3.Zero))
            {
                var halfOffset = (currPos - Center) * 0.5f;
                path.AddOffsetToCheckPos(halfOffset, Radius);
                return(TransitionState.Adjusted);
            }

            collisions.SetCollisionNormal(collisionNormal);

            var blockOffset = LandDefs.GetBlockOffset(path.CurPos.ObjCellID, path.CheckPos.ObjCellID);
            var gDelta      = blockOffset + (Center - currPos);

            var contactPlane = collisions.ContactPlaneValid ? collisions.ContactPlane : collisions.LastKnownContactPlane;
            var direction    = Vector3.Cross(collisionNormal, contactPlane.Normal);
            var dirLenSq     = direction.LengthSquared();

            if (dirLenSq >= PhysicsGlobals.EPSILON)
            {
                var diff        = Vector3.Dot(direction, gDelta);
                var invDirLenSq = 1.0f / dirLenSq;
                var offset      = direction * diff * invDirLenSq;
                if (offset.LengthSquared() < PhysicsGlobals.EPSILON)
                {
                    return(TransitionState.Collided);
                }

                offset -= gDelta;
                path.AddOffsetToCheckPos(offset, Radius);
                return(TransitionState.Slid);
            }

            if (Vector3.Dot(collisionNormal, contactPlane.Normal) >= 0.0f)
            {
                var diff   = Vector3.Dot(collisionNormal, gDelta);
                var offset = -collisionNormal * diff;
                path.AddOffsetToCheckPos(offset, Radius);
                return(TransitionState.Slid);
            }

            collisionNormal = -gDelta;
            if (!Vec.NormalizeCheckSmall(ref collisionNormal))
            {
                collisions.SetCollisionNormal(collisionNormal);
            }

            return(TransitionState.OK);
        }
Beispiel #7
0
        /// <summary>
        /// Redirects a 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">Currently doesn't seem to be used?</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;

            var gCenter      = path.GlobalCurrCenter[sphereNum].Center;
            var globalOffset = gCenter - Center;

            // if set to PerfectClip, does a more precise check
            if (obj.State.HasFlag(ObjectInfoState.PerfectClip))
            {
                var blockOffset   = LandDefs.GetBlockOffset(path.CurPos.ObjCellID, path.CheckPos.ObjCellID);
                var checkOffset   = checkPos.Center - gCenter + blockOffset;
                var collisionTime = FindTimeOfCollision(checkOffset, globalOffset, radsum + PhysicsGlobals.EPSILON);
                if (collisionTime < PhysicsGlobals.EPSILON || collisionTime > 1.0f)
                {
                    return(TransitionState.Collided);
                }
                else
                {
                    var collisionOffset  = checkOffset * (float)collisionTime - checkOffset;
                    var old_disp         = collisionOffset + checkPos.Center - Center;
                    var invRad           = 1.0f / radsum;
                    var collision_normal = old_disp * invRad;
                    collisions.SetCollisionNormal(collision_normal);
                    path.AddOffsetToCheckPos(old_disp, checkPos.Radius);
                    return(TransitionState.Adjusted);
                }
            }
            else
            {
                if (!Vec.NormalizeCheckSmall(ref globalOffset))
                {
                    collisions.SetCollisionNormal(globalOffset);
                }

                return(TransitionState.Collided);
            }
        }
Beispiel #8
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 (Vec.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);
        }
Beispiel #9
0
 public Vector3 GetCurPosCheckPosBlockOffset()
 {
     return(LandDefs.GetBlockOffset(CurPos.ObjCellID, CheckPos.ObjCellID));
 }