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