public bool CollideAgainstMoveSoft(AxisAlignedRectangle rectangle, float thisMass, float otherMass, float separationVelocity) { #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 (CollideAgainst(rectangle)) { Side side = Side.Left; // set it to left first float smallest = System.Math.Abs(X + mScaleX - (rectangle.X - rectangle.mScaleX)); float currentDistance = System.Math.Abs(X - mScaleX - (rectangle.X + rectangle.mScaleX)); if (currentDistance < smallest) { smallest = currentDistance; side = Side.Right; } currentDistance = Y - mScaleY - (rectangle.Y + rectangle.mScaleY); if (currentDistance < 0) { currentDistance *= -1; } if (currentDistance < smallest) { smallest = currentDistance; side = Side.Top; } currentDistance = Y + mScaleY - (rectangle.Y - rectangle.mScaleY); if (currentDistance < 0) { currentDistance *= -1; } if (currentDistance < smallest) { smallest = currentDistance; side = Side.Bottom; } float amountToMoveThis = otherMass / (thisMass + otherMass); Vector2 movementVector = new Vector2(); switch (side) { case Side.Left: movementVector.X = rectangle.X - rectangle.mScaleX - mScaleX - X; break; case Side.Right: movementVector.X = rectangle.X + rectangle.mScaleX + mScaleX - X; break; case Side.Top: movementVector.Y = rectangle.Y + rectangle.mScaleY + mScaleY - Y; break; case Side.Bottom: movementVector.Y = rectangle.Y - rectangle.mScaleY - mScaleY - Y; break; } TopParent.XVelocity += movementVector.X * amountToMoveThis * separationVelocity * TimeManager.SecondDifference; TopParent.YVelocity += movementVector.Y * amountToMoveThis * separationVelocity * TimeManager.SecondDifference; rectangle.TopParent.XVelocity += -movementVector.X * (1 - amountToMoveThis) * separationVelocity * TimeManager.SecondDifference; rectangle.TopParent.YVelocity += -movementVector.Y * (1 - amountToMoveThis) * separationVelocity * TimeManager.SecondDifference; ForceUpdateDependencies(); rectangle.ForceUpdateDependencies(); return(true); } return(false); }
public bool CollideAgainstMove(AxisAlignedRectangle rectangle, 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 (CollideAgainst(rectangle)) { Side side = Side.Left; // set it to left first float smallest = float.PositiveInfinity; float currentDistance; if ((this.RepositionDirections & Geometry.RepositionDirections.Right) == Geometry.RepositionDirections.Right && (rectangle.RepositionDirections & Geometry.RepositionDirections.Left) == Geometry.RepositionDirections.Left) { smallest = System.Math.Abs(X + mScaleX - (rectangle.X - rectangle.mScaleX)); } if ((this.RepositionDirections & Geometry.RepositionDirections.Left) == Geometry.RepositionDirections.Left && (rectangle.RepositionDirections & Geometry.RepositionDirections.Right) == Geometry.RepositionDirections.Right) { currentDistance = System.Math.Abs(X - mScaleX - (rectangle.X + rectangle.mScaleX)); if (currentDistance < smallest) { smallest = currentDistance; side = Side.Right; } } if ((this.RepositionDirections & Geometry.RepositionDirections.Down) == Geometry.RepositionDirections.Down && (rectangle.RepositionDirections & Geometry.RepositionDirections.Up) == Geometry.RepositionDirections.Up) { currentDistance = Y - mScaleY - (rectangle.Y + rectangle.mScaleY); if (currentDistance < 0) { currentDistance *= -1; } if (currentDistance < smallest) { smallest = currentDistance; side = Side.Top; } } if ((this.RepositionDirections & Geometry.RepositionDirections.Up) == Geometry.RepositionDirections.Up && (rectangle.RepositionDirections & Geometry.RepositionDirections.Down) == Geometry.RepositionDirections.Down) { currentDistance = Y + mScaleY - (rectangle.Y - rectangle.mScaleY); if (currentDistance < 0) { currentDistance *= -1; } if (currentDistance < smallest) { smallest = currentDistance; side = Side.Bottom; } } if (float.IsPositiveInfinity(smallest) == false) { float amountToMoveThis = 1; if (!float.IsPositiveInfinity(otherMass)) { amountToMoveThis = otherMass / (thisMass + otherMass); } Vector2 movementVector = new Vector2(); // Victor Chelaru // December 26, 2016 // I'm not sure why we // have a maxMovement variable // here. It used to be set to the // sum of the two rectangles' scales // (half width), but that prevents the // rectangles from separating when using // reposition directions that cause them to // move across the entire rectangle. I'm going // to use Scale*2 for each, because I'm not sure // if I should remove the maxMovement condition yet // Update: I think this was in place for cloud collision, // so only half of the rectangle would trigger a collision. // This can cause confusing behavior, especially when creating // tile-based collision, so I'm removing maxMovement: //float maxMovement = float.PositiveInfinity; switch (side) { case Side.Left: movementVector.X = rectangle.X - rectangle.mScaleX - mScaleX - X; break; case Side.Right: movementVector.X = rectangle.X + rectangle.mScaleX + mScaleX - X; break; case Side.Top: movementVector.Y = rectangle.Y + rectangle.mScaleY + mScaleY - Y; break; case Side.Bottom: movementVector.Y = rectangle.Y - rectangle.mScaleY - mScaleY - Y; break; } mLastMoveCollisionReposition.X = movementVector.X * amountToMoveThis; mLastMoveCollisionReposition.Y = movementVector.Y * amountToMoveThis; TopParent.X += mLastMoveCollisionReposition.X; TopParent.Y += mLastMoveCollisionReposition.Y; rectangle.mLastMoveCollisionReposition.X = -movementVector.X * (1 - amountToMoveThis); rectangle.mLastMoveCollisionReposition.Y = -movementVector.Y * (1 - amountToMoveThis); rectangle.TopParent.X += rectangle.mLastMoveCollisionReposition.X; rectangle.TopParent.Y += rectangle.mLastMoveCollisionReposition.Y; ForceUpdateDependencies(); rectangle.ForceUpdateDependencies(); } return(true); } return(false); }