protected void ApplyGravity() { Rectangle futurePosition = new Rectangle(CollisionBox.X, CollisionBox.Y - VelocityY, CollisionBox.Width, CollisionBox.Height); Collision.LineSegment intersectedPlatform = CollisionUtils.IntersectsWithSlopedPlatforms(futurePosition) ?? CollisionUtils.IntersectsWithAxisAlignedPlatforms(futurePosition); if (intersectedPlatform == null) { SetCollisionBoxY(CollisionBox.Y - VelocityY); IsGrounded = false; IsFalling = true; } else { if (intersectedPlatform.IsSloped) { do { // Set the incline angle if ((intersectedPlatform.IsAscending && CollisionBox.Y + CollisionBox.Height < intersectedPlatform.PointB.Y) || (!intersectedPlatform.IsAscending && CollisionBox.Y + CollisionBox.Height < intersectedPlatform.PointA.Y)) { // Don't apply incline angle if we are completely above the platform InclineAngle = 0; } else { InclineAngle = intersectedPlatform.IsAscending ? Maths.DegreesToRadians(360) - intersectedPlatform.InclineAngleWithX : intersectedPlatform.InclineAngleWithX; } // Check for collision a little higher futurePosition.Y -= Math.Abs(StartingVelocityY * 0.1f); intersectedPlatform = CollisionUtils.IntersectsWithSlopedPlatforms(futurePosition); }while (intersectedPlatform != null); SetCollisionBoxY(futurePosition.Y); } else { InclineAngle = 0; float distanceToPlatform = intersectedPlatform.PointA.Y - (CollisionBox.Y + CollisionBox.Height) - 1; SetCollisionBoxY(CollisionBox.Y + distanceToPlatform); } IsGrounded = true; IsFalling = false; } }
protected void ManageHorizontalMovement(Rectangle futurePosition) { Collision.LineSegment intersectedPlatform = CollisionUtils.IntersectsWithPlatforms(futurePosition); if (intersectedPlatform == null) { SetCollisionBoxX(futurePosition.X); InclineAngle = 0; } else { if (intersectedPlatform.IsSloped) { do { // Set the incline angle InclineAngle = intersectedPlatform.InclineAngleWithX; // Check for collision a little higher futurePosition.Y -= 3; intersectedPlatform = CollisionUtils.IntersectsWithSlopedPlatforms(futurePosition); }while (intersectedPlatform != null); // Proceed forward and climb the slope SetCollisionBoxX(futurePosition.X); SetCollisionBoxY(futurePosition.Y); } else { // If there is a step smaller than your horizontal velocity, climb it if ((CollisionBox.Y + CollisionBox.Height) - intersectedPlatform.PointA.Y - 1 <= Math.Abs(VelocityX)) { SetCollisionBoxX(futurePosition.X); SetCollisionBoxY(intersectedPlatform.PointA.Y - CollisionBox.Height - 1); } // Else don't move, because the movement is invalid } } }
/// <summary> /// The main logic for the Traverse Magic Flow action. /// When triggered, if Midori is colliding with the first or last segment of a Magic Flow, she will start traversing it. /// While traversing, Midori becomes a small pink sphere and is uncontrollable. /// The pink sphere is in the center of Midori's CollisionBox. /// When she reaches the end of the flow she turns back to normal and the player regains control. /// </summary> public void Action_TraverseMagicFlow() { Collision.LineSegment currentSegment = CurrentMagicFlow.Segments[CurrentMagicFlowSegmentIndex]; Vector2 sourcePoint; Vector2 destinationPoint; if (CurrentMagicFlow.TraverseFirstToLast) { sourcePoint = currentSegment.PointA; destinationPoint = currentSegment.PointB; } else { sourcePoint = currentSegment.PointB; destinationPoint = currentSegment.PointA; } // Solution with vectors //Vector2 v = destinationPoint - CollisionBox.Center; //float vLength = (float) Math.Sqrt(Math.Pow(v.X, 2) + Math.Pow(v.Y, 2)); //Vector2 u = v / vLength; //Vector2 newCenterPosition = CollisionBox.Center + (_magicFlowVelocity * u); // Solution with distance percentage // t = distanceWeWantToTraverseOnTheSegment / totalDistanceOfThatSegment float t = _magicFlowVelocity / currentSegment.Length; // Add up the t values for the current segment MagicFlowCurrentSegmentProgress += t; // A value of 1 means 100% of the line will be traversed so we make sure it's not more if (MagicFlowCurrentSegmentProgress > 1) { MagicFlowCurrentSegmentProgress = 1; } // The new position for the center of the CollisionBox Vector2 newCenterPosition = new Vector2( ((1 - MagicFlowCurrentSegmentProgress) * sourcePoint.X) + (MagicFlowCurrentSegmentProgress * destinationPoint.X), ((1 - MagicFlowCurrentSegmentProgress) * sourcePoint.Y) + (MagicFlowCurrentSegmentProgress * destinationPoint.Y) ); // Debug print //Collision.LineSegment debugSegment = new Collision.LineSegment( // CurrentMagicFlow.TraverseFirstToLast ? currentSegment.PointA : currentSegment.PointB, // newCenterPosition //); //Console.WriteLine($"Delta from source point {debugSegment.Length}; t = {MagicFlowCurrentSegmentProgress}; Distance = {currentSegment.Length}"); // If the destination is reached if (newCenterPosition.X == destinationPoint.X && newCenterPosition.Y == destinationPoint.Y) { // If there are more lines, go to the next one if (CurrentMagicFlow.TraverseFirstToLast && CurrentMagicFlowSegmentIndex + 1 < CurrentMagicFlow.Segments.Count) { CurrentMagicFlowSegmentIndex += 1; } else if (!CurrentMagicFlow.TraverseFirstToLast && CurrentMagicFlowSegmentIndex > 0) { CurrentMagicFlowSegmentIndex -= 1; } // If not, end the Magic Flow sequence else { CurrentMagicFlow = null; IsMagicFlowActive = false; IsUnableToMove = false; } MagicFlowCurrentSegmentProgress = 0; } SetCollisionBoxX(newCenterPosition.X - (CollisionBox.Width / 2)); SetCollisionBoxY(newCenterPosition.Y - (CollisionBox.Height / 2)); }
protected void ManageMovement() { if (IsUnableToMove) { return; } Room currentRoom = GameContext.Scene.LoadedRoom; float newVelocity = VelocityX * RunTimer.Progress; if (IsMovingLeft) { // Make sure movement is within the room borders if (CollisionBox.X > 0 + newVelocity) { Rectangle futurePosition = new Rectangle(CollisionBox.X - newVelocity, CollisionBox.Y, CollisionBox.Width, CollisionBox.Height); ManageHorizontalMovement(futurePosition); } else { SetCollisionBoxX(0); IsMovingLeft = false; IsIdle = true; } } if (IsMovingRight) { // Make sure movement is within the room borders if (CollisionBox.X + CollisionBox.Width < currentRoom.Size.X - newVelocity) { Rectangle futurePosition = new Rectangle(CollisionBox.X + newVelocity, CollisionBox.Y, CollisionBox.Width, CollisionBox.Height); ManageHorizontalMovement(futurePosition); } else { SetCollisionBoxX(currentRoom.Size.X - CollisionBox.Width); IsMovingRight = false; IsIdle = true; } } if (IsJumping) { if (JumpTimer.Finished && !IsFalling) { IsFalling = true; JumpTimer.GoNormal(); } if (IsFalling) { VelocityY = StartingVelocityY; } Rectangle futurePosition = new Rectangle(CollisionBox.X, CollisionBox.Y - (JumpTimer.Progress * VelocityY), CollisionBox.Width, CollisionBox.Height); Collision.LineSegment intersectedPlatform = CollisionUtils.IntersectsWithPlatforms(futurePosition); if (intersectedPlatform == null) { SetCollisionBoxY(CollisionBox.Y - JumpTimer.Progress * VelocityY); } else { IsJumping = false; IsFalling = false; IsGrounded = true; JumpTimer.End(); //Y = 580; } } else { VelocityY = StartingVelocityY; ApplyGravity(); } }
/// <summary> /// Adds the given segment to the list of segments and updates the total length. /// </summary> /// <param name="segment"></param> public void AddSegment(Collision.LineSegment segment) { Segments.Add(segment); Length += segment.Length; }