Hi there, I am a beginner and studied only for a week up to this point, I love Rick’s class, he is so amazing and made every step so clear and easy to follow. I am an artist, and my OCD drove me to make everything visually perfect, so I have googled and youtubed a lot to solve this Ladder issue, this is the code I figured, if there any better or simpler way to write it, please let me know, thanks, hope this help! Here are some key notes:
-
On the ladder because there is 0 Gravity while Climbing, we need to set gravity back to default while performing the jumping action, otherwise the player will keep going up;
-first, add this under OnJump:
if (!myFeetCollider.IsTouchingLayers(LayerMask.GetMask(“Ground”)) && !myFeetCollider.IsTouchingLayers(LayerMask.GetMask(“Climb”)))
then return;
-second, set gravity to default when jump is pressed on ladder,
if (myRigidbody.velocity.y > Mathf.Epsilon && myFeetCollider.IsTouchingLayers(LayerMask.GetMask(“Climb”)))
then {myRigidbody.gravityScale = gravityScaleAtStart;} -
(Then when jumping on the ladder and reaching the highest point, then the player will start falling down if gravity is the default, I want the player to catch on the ladder instead of falling back down to the ground, so I need to set the gravity to 0 when reaches the highest jump point while the platyer is touching the ladder, this will ONLY HAPPEN/NEEDED when the ladder is LONGER than the JUMP HEIGHT.)
So this is the condition
if (myRigidbody.velocity.y < Mathf.Epsilon && isJumping && myFeetCollider.IsTouchingLayers(LayerMask.GetMask(“Climb”)))
(myRigidbody.velocity.y < Mathf.Epsilon ) is when speed is 0, when speed is 0 in a jump action, it means the player reaches the highest jump point and will start falling down due to gravity. that’s why we are setting gravity to 0 at this point so the player will land on the ladder. -
remember to reactivate the climbing input again or you might not be able to move up and down after the jump if u landed back on the ladder.
-
For the Animation part, I make the player switch back to The Idle Animation while not moving on the Ladder, and switch to Running Animation when Jump Off the Ladder.
public class PlayerMovement : MonoBehaviour
{
[SerializeField] float runSpeed = 7f;
[SerializeField] float jumpSpeed = 20f;
[SerializeField] float climbSpeed = 4f;
Vector2 moveInput;
Rigidbody2D myRigidbody;
Animator myAnimator;
CapsuleCollider2D myBodyCollider;
BoxCollider2D myFeetCollider;
float gravityScaleAtStart;
bool isJumping;
//bool isClimbing;
void Start()
{
myRigidbody = GetComponent<Rigidbody2D>();
myAnimator = GetComponent<Animator>();
myBodyCollider = GetComponent<CapsuleCollider2D>();
myFeetCollider = GetComponent<BoxCollider2D>();
gravityScaleAtStart = myRigidbody.gravityScale;
}
void Update()
{
Run();
FlipSprite();
ClimbLadder();
if(Mathf.Abs(myRigidbody.velocity.x) < Mathf.Epsilon)
{
myAnimator.SetBool("isRuning", false);
}
}
void OnMove(InputValue value)
{
moveInput = value.Get<Vector2>();
}
void OnJump(InputValue value)
{
if (!myFeetCollider.IsTouchingLayers(LayerMask.GetMask("Ground")) && !myFeetCollider.IsTouchingLayers(LayerMask.GetMask("Climb")))
{
return;
}
if(value.isPressed)
//if(Input.GetButtonDown("Jump"))
{
myRigidbody.velocity += new Vector2 (0f, jumpSpeed);
isJumping = true;
myAnimator.SetBool("isClimbing", false);
}
if(myRigidbody.velocity.y > Mathf.Epsilon && myFeetCollider.IsTouchingLayers(LayerMask.GetMask("Climb")))
{
myRigidbody.gravityScale = gravityScaleAtStart;
myAnimator.SetBool("isClimbing", false);
}
if(myFeetCollider.IsTouchingLayers(LayerMask.GetMask("Climb")))
{
myAnimator.SetBool("isClimbing", true);
}
//if(myRigidbody.velocity.sqrMagnitude > maxSpeed * maxSpeed)
//{
//Vector2 movement = new Vector2 (runSpeed, jumpSpeed);
//movement.Normalize();
//myRigidbody.MovePosition(myRigidbody.position + movement * maxSpeed * Time.fixedDeltaTime);
//myRigidbody.velocity = Vector2.ClampMagnitude(myRigidbody.velocity, maxSpeed);
//}
}
//clamp the speed (magnitude of the velocity vector).sqrMagnitude.
//If the sqrMagnitude is higher than the squared maxSpeed (which you define),
//normalise your vector, and multiply the normalised vector with maxSpeed.
void Run()
{
Vector2 playerVelocity = new Vector2(moveInput.x * runSpeed, myRigidbody.velocity.y);
myRigidbody.velocity = playerVelocity;
myAnimator.SetBool("isRuning", true);
//bool playerHasHorizontalSpeed
}
void FlipSprite()
{
bool playerHasHorizontalSpeed = Mathf.Abs(myRigidbody.velocity.x) > Mathf.Epsilon;
if (playerHasHorizontalSpeed)
{
transform.localScale = new Vector2 (Mathf.Sign(myRigidbody.velocity.x), 1f);
}
}
void ClimbLadder()
{
if (!myFeetCollider.IsTouchingLayers(LayerMask.GetMask("Climb")))
{
isJumping = false;
myRigidbody.gravityScale = gravityScaleAtStart;
myAnimator.SetBool("isClimbing", false);
myAnimator.SetBool("isRuning", true);
myAnimator.enabled = true;
return;
}
// When exit Ladder
if (!isJumping && myFeetCollider.IsTouchingLayers(LayerMask.GetMask("Climb")))
{
//isClimbing = true;
myAnimator.SetBool("isClimbing", true);
Vector2 climbVelocity = new Vector2(myRigidbody.velocity.x, moveInput.y * climbSpeed);
myRigidbody.velocity = climbVelocity;
myRigidbody.gravityScale = 0f;
}
// if on ladder and not jumping, then climb
//bool playerHasVerticalSpeed = Mathf.Abs(myRigidbody.velocity.y) > Mathf.Epsilon;
//myAnimator.enabled = true;
//myAnimator.SetBool("isClimbing", playerHasVerticalSpeed);
// When on ladder climbing & not jumping
if(Mathf.Abs(myRigidbody.velocity.y) < Mathf.Epsilon)
{
myAnimator.SetBool("isClimbing", false);
}
//if(!isClimbing && myFeetCollider.IsTouchingLayers(LayerMask.GetMask("Climb")))
//{
//myAnimator.enabled = false;
//}
// Stop Animation when the player stop movement on Ladder
if (myRigidbody.velocity.y < Mathf.Epsilon && isJumping && myFeetCollider.IsTouchingLayers(LayerMask.GetMask("Climb")))
{
//isClimbing = true;
// myAnimator.SetBool("isClimbing", false);
isJumping = false;
Vector2 climbVelocity = new Vector2(myRigidbody.velocity.x, moveInput.y * climbSpeed);
myRigidbody.velocity = climbVelocity;
myRigidbody.gravityScale = 0;
}
// if falling in jumping action while on ladder, cancel jumping , activate climbing, set gravity to 0
//if (Input.GetButton("Jump"))
//{
// myRigidbody.gravityScale = 0f;
//myRigidbody.velocity += new Vector2 (0f, jumpSpeed);
//isJumping = true;
//}
// myRigidbody.gravityScale = gravityScaleAtStart;
// myRigidbody.AddForce(transform.up * thrust);
// myRigidbody.AddForce(transform.up * thrust, ForceMode2D.Impulse);
// isJumping = false;
//}
}
}