/// <summary> /// Returns whether this instance collides against the argument Capsule2D. /// </summary> /// <param name="capsule">The Capsule2D to test collision against.</param> /// <returns>Whether collision has occurred.</returns> public bool CollideAgainst(Capsule2D capsule) { UpdateDependencies(TimeManager.CurrentTime); capsule.UpdateDependencies(TimeManager.CurrentTime); Circle circle = Capsule2D.CollisionCircle; circle.Position = capsule.Endpoint1Position; circle.Radius = capsule.EndpointRadius; bool collision = circle.CollideAgainst(this); if (collision) { return(true); } circle.Position = capsule.Endpoint2Position; collision = circle.CollideAgainst(this); if (collision) { return(true); } Polygon polygon = Capsule2D.CollisionPolygon; float right = capsule.Scale - capsule.EndpointRadius; float top = capsule.EndpointRadius; polygon.SetPoint(0, -right, top); polygon.SetPoint(1, right, top); polygon.SetPoint(2, right, -top); polygon.SetPoint(3, -right, -top); polygon.SetPoint(4, -right, top); polygon.Position = capsule.Position; polygon.RotationMatrix = capsule.RotationMatrix; polygon.UpdateDependencies(TimeManager.CurrentTime); return(this.CollideAgainst(polygon)); }
public bool CollideAgainstMove(Circle circle, float thisMass, float otherMass) { #if DEBUG if (thisMass == 0 && otherMass == 0) { throw new ArgumentException("Both masses cannot be 0. For equal masses pick a non-zero value"); } #endif if (circle.CollideAgainst(this)) { Point circleCenter = new Point(circle.X, circle.Y); if (IsPointOnOrInside(ref circleCenter)) { double xDistanceToMoveCircle = 0; double yDistanceToMoveCircle = 0; float smallestDistance = float.PositiveInfinity; if ((this.RepositionDirections & Geometry.RepositionDirections.Right) == Geometry.RepositionDirections.Right) { smallestDistance = Right - circle.X; xDistanceToMoveCircle = smallestDistance + circle.Radius; } if ((this.RepositionDirections & Geometry.RepositionDirections.Left) == Geometry.RepositionDirections.Left && circle.X - Left < smallestDistance) { smallestDistance = circle.X - Left; xDistanceToMoveCircle = -smallestDistance - circle.Radius; } if ((this.RepositionDirections & Geometry.RepositionDirections.Up) == Geometry.RepositionDirections.Up && Top - circle.Y < smallestDistance) { smallestDistance = Top - circle.Y; xDistanceToMoveCircle = 0; yDistanceToMoveCircle = smallestDistance + circle.Radius; } if ((this.RepositionDirections & Geometry.RepositionDirections.Down) == Geometry.RepositionDirections.Down && circle.Y - Bottom < smallestDistance) { smallestDistance = circle.Y - Bottom; xDistanceToMoveCircle = 0; yDistanceToMoveCircle = -smallestDistance - circle.Radius; } float amountToMoveThis = otherMass / (thisMass + otherMass); mLastMoveCollisionReposition.X = (float)(-xDistanceToMoveCircle * amountToMoveThis); mLastMoveCollisionReposition.Y = (float)(-yDistanceToMoveCircle * amountToMoveThis); TopParent.X += mLastMoveCollisionReposition.X; TopParent.Y += mLastMoveCollisionReposition.Y; circle.LastMoveCollisionReposition.X = (float)(xDistanceToMoveCircle * (1 - amountToMoveThis)); circle.LastMoveCollisionReposition.Y = (float)(yDistanceToMoveCircle * (1 - amountToMoveThis)); circle.mLastCollisionTangent = new Point(circle.LastMoveCollisionReposition.Y, -circle.LastMoveCollisionReposition.X); circle.TopParent.Position.X += circle.LastMoveCollisionReposition.X; circle.TopParent.Position.Y += circle.LastMoveCollisionReposition.Y; ForceUpdateDependencies(); circle.ForceUpdateDependencies(); return(true); } else { Segment collisionSegment = new Segment(); // top Segment edge = new Segment(); float smallestDistance = float.PositiveInfinity; #if FRB_MDX Vector2 amountToMove = Vector2.Empty; #else Vector2 amountToMove = Vector2.Zero; #endif bool isAmountToMoveSet = false; if ((this.RepositionDirections & Geometry.RepositionDirections.Up) == Geometry.RepositionDirections.Up) { bool shouldUseInfiniteSegment = (circleCenter.X < Position.X && (this.RepositionDirections & Geometry.RepositionDirections.Left) != Geometry.RepositionDirections.Left) || (circleCenter.X > Position.X && (this.RepositionDirections & Geometry.RepositionDirections.Right) != Geometry.RepositionDirections.Right); if (shouldUseInfiniteSegment) { smallestDistance = Top + circle.Radius - circle.Position.Y; isAmountToMoveSet = true; amountToMove.X = 0; amountToMove.Y = -smallestDistance; } else { // Maybe we can save by not calling "new" edge = new Segment( new Point(this.Left, this.Top), new Point(this.Right, this.Top)); smallestDistance = edge.DistanceTo(circleCenter, out collisionSegment); } } if ((this.RepositionDirections & Geometry.RepositionDirections.Down) == Geometry.RepositionDirections.Down) { bool shouldUseInfiniteSegment = (circleCenter.X < Position.X && (this.RepositionDirections & Geometry.RepositionDirections.Left) != Geometry.RepositionDirections.Left) || (circleCenter.X > Position.X && (this.RepositionDirections & Geometry.RepositionDirections.Right) != Geometry.RepositionDirections.Right); if (shouldUseInfiniteSegment) { float candidate = Bottom - circle.Radius - circle.Position.Y; if (System.Math.Abs(candidate) < System.Math.Abs(smallestDistance)) { smallestDistance = candidate; isAmountToMoveSet = true; amountToMove.X = 0; amountToMove.Y = -smallestDistance; } } else { // bottom edge = new Segment( new Point(Left, Bottom), new Point(Right, Bottom)); if (edge.DistanceTo(circleCenter) < smallestDistance) { smallestDistance = (float)edge.DistanceTo(circleCenter, out collisionSegment); } } } if ((this.RepositionDirections & Geometry.RepositionDirections.Left) == Geometry.RepositionDirections.Left) { bool shouldUseInfiniteSegment = (circleCenter.Y < Position.Y && (this.RepositionDirections & Geometry.RepositionDirections.Down) != Geometry.RepositionDirections.Down) || (circleCenter.Y > Position.Y && (this.RepositionDirections & Geometry.RepositionDirections.Up) != Geometry.RepositionDirections.Up); if (shouldUseInfiniteSegment) { float candidate = Left - circle.Radius - circle.Position.X; if (System.Math.Abs(candidate) < System.Math.Abs(smallestDistance)) { smallestDistance = candidate; isAmountToMoveSet = true; amountToMove.Y = 0; amountToMove.X = -smallestDistance; } } else { // left edge = new Segment( new Point(Left, Top), new Point(Left, Bottom)); if (edge.DistanceTo(circleCenter) < smallestDistance) { smallestDistance = (float)edge.DistanceTo(circleCenter, out collisionSegment); } } } if ((this.RepositionDirections & Geometry.RepositionDirections.Right) == Geometry.RepositionDirections.Right) { bool shouldUseInfiniteSegment = (circleCenter.Y < Position.Y && (this.RepositionDirections & Geometry.RepositionDirections.Down) != Geometry.RepositionDirections.Down) || (circleCenter.Y > Position.Y && (this.RepositionDirections & Geometry.RepositionDirections.Up) != Geometry.RepositionDirections.Up); if (shouldUseInfiniteSegment) { float candidate = Right + circle.Radius - circle.Position.X; if (System.Math.Abs(candidate) < System.Math.Abs(smallestDistance)) { smallestDistance = candidate; isAmountToMoveSet = true; amountToMove.Y = 0; amountToMove.X = -smallestDistance; } } else { // right edge = new Segment( new Point(Right, Top), new Point(Right, Bottom)); if (edge.DistanceTo(circleCenter) < smallestDistance) { smallestDistance = (float)edge.DistanceTo(circleCenter, out collisionSegment); // edgeClosestTo = "right"; } } } if (smallestDistance <= circle.Radius) { float remainingDistance = (float)circle.Radius - smallestDistance; if (!isAmountToMoveSet) { amountToMove = new Vector2((float)(collisionSegment.Point2.X - collisionSegment.Point1.X), (float)(collisionSegment.Point2.Y - collisionSegment.Point1.Y)); amountToMove.Normalize(); amountToMove = amountToMove * remainingDistance; } float amountToMoveThis = otherMass / (thisMass + otherMass); mLastMoveCollisionReposition.X = amountToMove.X * amountToMoveThis; mLastMoveCollisionReposition.Y = amountToMove.Y * amountToMoveThis; TopParent.X += mLastMoveCollisionReposition.X; TopParent.Y += mLastMoveCollisionReposition.Y; circle.LastMoveCollisionReposition.X = -amountToMove.X * (1 - amountToMoveThis); circle.LastMoveCollisionReposition.Y = -amountToMove.Y * (1 - amountToMoveThis); circle.TopParent.Position.X += circle.LastMoveCollisionReposition.X; circle.TopParent.Position.Y += circle.LastMoveCollisionReposition.Y; ForceUpdateDependencies(); circle.ForceUpdateDependencies(); return(true); } else { return(false); } } } return(false); }
/// <summary> /// Returns whether this instance collides against the argument Circle. /// </summary> /// <param name="circle">The Circle to test collision against.</param> /// <returns>Whether collision has occurred.</returns> public bool CollideAgainst(Circle circle) { return(circle.CollideAgainst(this)); }