/** * <summary> * Fully animates a jump of a player using the spring. * </summary> * <remarks> * The player object will undergo several adjustments during the jump, to avoid interaction with other map objects * during the jump. * <list type="bullet"> * <item><description><see cref="PlayerController.PhysicsEffects"/> will be disabled</description></item> * <item><description>The rigidbody will be disabled.</description></item> * <item><description>The layer will be changed</description></item> * <item><description>...</description></item> * </list> * </remarks> */ private IEnumerator AnimateSpringJump(PlayerController player) { // === 0. While in use, no other player shall use this Spring === _interactive.enabled = false; // === 1. Adjust the player object so that it will not interact with other objects during the jump === player.PhysicsEffects.enabled = false; player.PhysicsEffects.rigidbody2D.simulated = false; var originalLayer = player.gameObject.layer; player.gameObject.layer = LayerMask.NameToLayer("Carried"); player.InteractorCollider.CanInteract = false; // Ensure the player is rendered above everything else var originalSortingOrder = player.spriteRenderer.sortingOrder; player.spriteRenderer.sortingOrder = 999; // === 2. Move player linearly to the start point. === var playerTransform = player.transform; var currentPosition = (Vector2)playerTransform.position; while (currentPosition != (Vector2)springJumpStartPoint.transform.position) { player.transform.position = VectorExtensions.Assign2D( currentPosition, Vector2.MoveTowards( currentPosition, springJumpStartPoint.transform.position, Time.deltaTime * jumpOnSpringSpeed ) ); currentPosition = playerTransform.position; // wait one frame yield return(0); } // === 3. Animate Jump === // Animate the spring to tense up _animator.SetBool(UnderTensionAnimatorProperty, true); yield return(new WaitForSeconds(underTensionTime)); // Release spring and play sound _animator.SetBool(UnderTensionAnimatorProperty, false); _audioSource.Play(); // Inform player object to use a jump sprite player.SetSpringJumpMode(true); // Calculate, how far the player will jump var jumpDistance = ((Vector2)springJumpDestination.transform.position - (Vector2)player.transform.position).magnitude; // We store how far we have travelled this distance here var traveledDistance = 0.0f; // We introduce a temporary parent object to scale the player while jumping. // This way, other components adjusting the player scaling can not interfere with us. var scalingParent = new GameObject(); var originalParent = player.transform.parent; scalingParent.transform.position = player.transform.position; player.transform.position = Vector3.zero; player.transform.SetParent(scalingParent.transform, false); var maxScale = jumpMaxScale * Vector3.one; // Move the parent to the target location. This will also move the player currentPosition = (Vector2)scalingParent.transform.position; while (currentPosition != (Vector2)springJumpDestination.transform.position) { // Compute how far we can move in this frame depending on the passed time var distanceDelta = Time.deltaTime * jumpSpeed; // Accumulate the distance we moved so far. We will use this to adjust the scaling traveledDistance += distanceDelta; scalingParent.transform.position = VectorExtensions.Assign2D( currentPosition, Vector2.MoveTowards( currentPosition, springJumpDestination.transform.position, distanceDelta ) ); currentPosition = scalingParent.transform.position; // Animate the scaling of the player // They shall appear bigger towards the middle of the travel distance, to give the illusion of a high jump // If we have not reached half the travel distance yet... if (traveledDistance < jumpDistance / 2) { // ...linearly interpolate the scale so that the maximum is reached at half the travel distance scalingParent.transform.localScale = VectorExtensions.Assign2D( scalingParent.transform.localScale, Vector2.Lerp(Vector2.one, maxScale, 2 * traveledDistance / jumpDistance) ); } // Otherwise... else { // ...linearly interpolate the scale starting at the maximum so that the minimum is reached at the full travel distance scalingParent.transform.localScale = VectorExtensions.Assign2D( scalingParent.transform.localScale, Vector2.Lerp(maxScale, Vector2.one, 2 * traveledDistance / jumpDistance - 1) ); } // wait one frame yield return(0); } // === 4. Remove all adjustments to the player object === player.InteractorCollider.CanInteract = true; player.transform.SetParent(originalParent); player.transform.position = scalingParent.transform.position; Destroy(scalingParent); player.spriteRenderer.sortingOrder = originalSortingOrder; player.SetSpringJumpMode(false); player.PhysicsEffects.enabled = true; player.PhysicsEffects.rigidbody2D.simulated = true; player.gameObject.layer = originalLayer; // === 5. reenable interactions with this spring === _interactive.enabled = true; }