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); }
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); }
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)); }
/// <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); }
public void AdjustCheckPos(int cellID) { if (cellID < 100) // ? { var offset = LandDefs.GetBlockOffset(cellID, CheckPos.ObjCellID); CacheGlobalSphere(offset); CheckPos.Frame.Origin += offset; } CheckPos.ObjCellID = cellID; }
/// <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); }
/// <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); } }
/// <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); }
public Vector3 GetCurPosCheckPosBlockOffset() { return(LandDefs.GetBlockOffset(CurPos.ObjCellID, CheckPos.ObjCellID)); }