I have two problems. The first one is that if my character walks off a platform it will not play the falling animation and instead of play the animation it’s currently doing instead of the falling.
The second one is if my character jumps instead of doing the jumping animation it will instantly go to the falling animation I think I know why it’s happening but I’m not sure how to stop it from happening.
Here is my script for animations:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Anim : MonoBehaviour
{
Animator animator;
[SerializeField] private ThirdPersonMovement script;
float waitTime = 2.0f;
// Start is called before the first frame update
void Start()
{
Debug.Log(script.grounded);
animator = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
bool isWalking = animator.GetBool("Walking");
bool isRunning = animator.GetBool("Running");
bool walking = Input.GetKey("w");
bool runPressed = Input.GetKey("left shift");
if (!isWalking && walking && script.grounded)
{
animator.SetBool("Walking", true);
}
if (isWalking &!walking && script.grounded)
{
animator.SetBool("Walking", false);
}
if (!isRunning && (walking && runPressed))
{
animator.SetBool("Running", true);
}
if (isRunning && (!walking || !runPressed))
{
animator.SetBool("Running", false);
}
if (!isRunning && script.grounded && script.readyToJump)
{
if (Input.GetKey("space") )
{
animator.SetBool("Jumping", true);
animator.SetBool("Falling", false);
StartCoroutine(WaitAfterLanding());
}
}
if (!script.grounded) // Character is not grounded (jumping or falling)
{
animator.SetBool("Falling", true);
}
if (script.grounded)
{
animator.SetBool("Falling", false);
}
}
IEnumerator WaitAfterLanding()
{
// Wait for specified time
yield return new WaitForSeconds(waitTime);
}
}
and for basic movement:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class ThirdPersonMovement : MonoBehaviour
{
[Header("Movement")]
private float moveSpeed;
public float walkSpeed;
public float sprintSpeed;
public float dashSpeed;
public float dashSpeedChangeFactor;
public float maxYSpeed;
public float groundDrag;
[Header("Jumping")]
public float jumpForce;
public float jumpCooldown;
public float airMultiplier;
public bool readyToJump;
[Header("Crouching")]
public float crouchSpeed;
public float crouchYScale;
private float startYScale;
[Header("Keybinds")]
public KeyCode jumpKey = KeyCode.Space;
public KeyCode sprintKey = KeyCode.LeftShift;
public KeyCode crouchKey = KeyCode.LeftControl;
[Header("Ground Check")]
public float playerHeight;
public LayerMask whatIsGround;
public bool grounded;
[Header("Slope Handling")]
public float maxSlopeAngle;
private RaycastHit slopeHit;
private bool exitingSlope;
public Transform orientation;
float horizontalInput;
float verticalInput;
Vector3 moveDirection;
Rigidbody rb;
private bool lockRotation = false;
public MovementState state;
public enum MovementState
{
walking,
sprinting,
crouching,
dashing,
air
}
public bool dashing;
private ThirdPersonCam thirdPersonCam;
private void Start()
{
rb = GetComponent<Rigidbody>();
rb.freezeRotation = true;
readyToJump = true;
startYScale = transform.localScale.y;
thirdPersonCam = Camera.main.GetComponent<ThirdPersonCam>();
}
private void Update()
{
// ground check
grounded = Physics.Raycast(transform.position, Vector3.down, playerHeight * 0.5f + 0.2f, whatIsGround);
MyInput();
SpeedControl();
StateHandler();
// handle drag
if (state == MovementState.walking || state == MovementState.sprinting || state == MovementState.crouching)
rb.drag = groundDrag;
else
rb.drag = 0;
TextStuff();
if (Input.GetButton("Fire1"))
{
lockRotation = true;
}else{
lockRotation = false;
}
thirdPersonCam.isShooting = dashing || Input.GetButton("Fire1");
}
private void FixedUpdate()
{
MovePlayer();
}
private void MyInput()
{
horizontalInput = Input.GetAxisRaw("Horizontal");
verticalInput = Input.GetAxisRaw("Vertical");
// when to jump
if (Input.GetKey(jumpKey) && readyToJump && grounded)
{
readyToJump = false;
Jump();
Invoke(nameof(ResetJump), jumpCooldown);
}
// start crouch
if (Input.GetKeyDown(crouchKey))
{
transform.localScale = new Vector3(transform.localScale.x, crouchYScale, transform.localScale.z);
rb.AddForce(Vector3.down * 5f, ForceMode.Impulse);
}
// stop crouch
if (Input.GetKeyUp(crouchKey))
{
transform.localScale = new Vector3(transform.localScale.x, startYScale, transform.localScale.z);
}
}
private float desiredMoveSpeed;
private float lastDesiredMoveSpeed;
private MovementState lastState;
private bool keepMomentum;
private void StateHandler()
{
// Mode - Dashing
if (dashing)
{
state = MovementState.dashing;
desiredMoveSpeed = dashSpeed;
speedChangeFactor = dashSpeedChangeFactor;
}
// Mode - Crouching
else if (Input.GetKey(crouchKey))
{
state = MovementState.crouching;
desiredMoveSpeed = crouchSpeed;
}
// Mode - Sprinting
else if (grounded && Input.GetKey(sprintKey))
{
state = MovementState.sprinting;
desiredMoveSpeed = sprintSpeed;
}
// Mode - Walking
else if (grounded)
{
state = MovementState.walking;
desiredMoveSpeed = walkSpeed;
}
// Mode - Air
else
{
state = MovementState.air;
if (desiredMoveSpeed < sprintSpeed)
desiredMoveSpeed = walkSpeed;
else
desiredMoveSpeed = sprintSpeed;
}
bool desiredMoveSpeedHasChanged = desiredMoveSpeed != lastDesiredMoveSpeed;
if (lastState == MovementState.dashing) keepMomentum = true;
if (desiredMoveSpeedHasChanged)
{
if (keepMomentum)
{
StopAllCoroutines();
StartCoroutine(SmoothlyLerpMoveSpeed());
}
else
{
StopAllCoroutines();
moveSpeed = desiredMoveSpeed;
}
}
lastDesiredMoveSpeed = desiredMoveSpeed;
lastState = state;
}
private float speedChangeFactor;
private IEnumerator SmoothlyLerpMoveSpeed()
{
// smoothly lerp movementSpeed to desired value
float time = 0;
float difference = Mathf.Abs(desiredMoveSpeed - moveSpeed);
float startValue = moveSpeed;
float boostFactor = speedChangeFactor;
while (time < difference)
{
moveSpeed = Mathf.Lerp(startValue, desiredMoveSpeed, time / difference);
time += Time.deltaTime * boostFactor;
yield return null;
}
moveSpeed = desiredMoveSpeed;
speedChangeFactor = 1f;
keepMomentum = false;
}
private void MovePlayer()
{
if (state == MovementState.dashing) return;
// calculate movement direction
moveDirection = orientation.forward * verticalInput + orientation.right * horizontalInput;
// on slope
if (OnSlope() && !exitingSlope)
{
rb.AddForce(GetSlopeMoveDirection() * moveSpeed * 20f, ForceMode.Force);
if (rb.velocity.y > 0)
rb.AddForce(Vector3.down * 80f, ForceMode.Force);
}
// on ground
else if (grounded)
rb.AddForce(moveDirection.normalized * moveSpeed * 10f, ForceMode.Force);
// in air
else if (!grounded)
rb.AddForce(moveDirection.normalized * moveSpeed * 10f * airMultiplier, ForceMode.Force);
// turn gravity off while on slope
rb.useGravity = !OnSlope();
if (lockRotation)
{
Vector3 newRotation = transform.rotation.eulerAngles;
newRotation.y = 0f; // Lock rotation on X-axis
transform.rotation = Quaternion.Euler(newRotation);
}
}
private void SpeedControl()
{
// limiting speed on slope
if (OnSlope() && !exitingSlope)
{
if (rb.velocity.magnitude > moveSpeed)
rb.velocity = rb.velocity.normalized * moveSpeed;
}
// limiting speed on ground or in air
else
{
Vector3 flatVel = new Vector3(rb.velocity.x, 0f, rb.velocity.z);
// limit velocity if needed
if (flatVel.magnitude > moveSpeed)
{
Vector3 limitedVel = flatVel.normalized * moveSpeed;
rb.velocity = new Vector3(limitedVel.x, rb.velocity.y, limitedVel.z);
}
}
// limit y vel
if (maxYSpeed != 0 && rb.velocity.y > maxYSpeed)
rb.velocity = new Vector3(rb.velocity.x, maxYSpeed, rb.velocity.z);
}
private void Jump()
{
exitingSlope = true;
// reset y velocity
rb.velocity = new Vector3(rb.velocity.x, 0f, rb.velocity.z);
rb.AddForce(transform.up * jumpForce, ForceMode.Impulse);
}
private void ResetJump()
{
readyToJump = true;
exitingSlope = false;
}
private bool OnSlope()
{
if (Physics.Raycast(transform.position, Vector3.down, out slopeHit, playerHeight * 0.5f + 0.3f))
{
float angle = Vector3.Angle(Vector3.up, slopeHit.normal);
return angle < maxSlopeAngle && angle != 0;
}
return false;
}
private Vector3 GetSlopeMoveDirection()
{
return Vector3.ProjectOnPlane(moveDirection, slopeHit.normal).normalized;
}
public TextMeshProUGUI text_speed;
public TextMeshProUGUI text_ySpeed;
public TextMeshProUGUI text_mode;
private void TextStuff()
{
Vector3 flatVel = new Vector3(rb.velocity.x, 0f, rb.velocity.z);
if (OnSlope())
text_speed.SetText("Speed: " + Round(rb.velocity.magnitude, 1) + " / " + Round(moveSpeed, 1));
else
text_speed.SetText("Speed: " + Round(flatVel.magnitude, 1) + " / " + Round(moveSpeed, 1));
//float yVel = rb.velocity.y;
//float yMax = maxYSpeed == 0 ? 0 : maxYSpeed;
//text_ySpeed.SetText("YSpeed: " + Round(yVel, 0) + " / " + yMax);
text_mode.SetText(state.ToString());
}
public static float Round(float value, int digits)
{
float mult = Mathf.Pow(10.0f, (float)digits);
return Mathf.Round(value * mult) / mult;
}
}