using UnityEngine; using UnityEngine.Events; namespace Pink.Mechanics { public class CharacterKinematics : MonoBehaviour { [SerializeField] private float m_JumpForce = 400f; // Amount of force added when the player jumps. [SerializeField] private float m_DoubleJumpForce = 13f; // Amount of force added when the player double jumps. //[Range(0, 1)] [SerializeField] private float m_CrouchSpeed = .36f; // Amount of maxSpeed applied to crouching movement. 1 = 100% [Range(0, .3f)] [SerializeField] private float m_MovementSmoothing = .05f; // How much to smooth out the movement [SerializeField] private bool m_AirControl = false; // Whether or not a player can steer while jumping; [SerializeField] private LayerMask m_WhatIsGround; // A mask determining what is ground to the character [SerializeField] private Transform m_GroundCheck; // A position marking where to check if the player is grounded. [SerializeField] private Transform m_CeilingCheck; // A position marking where to check for ceilings [SerializeField] private Collider2D m_CrouchDisableCollider; // A collider that will be disabled when crouching public Animator animator; const float k_GroundedRadius = .2f; // Radius of the overlap circle to determine if grounded private bool m_Grounded; // Whether or not the player is grounded. const float k_CeilingRadius = .2f; // Radius of the overlap circle to determine if the player can stand up private Rigidbody2D m_Rigidbody2D; private bool m_FacingRight = true; // For determining which way the player is currently facing. private Vector3 m_Velocity = Vector3.zero; private bool m_hasDoubleJumped = false; [Header("Events")] [Space] public UnityEvent OnLandEvent; [System.Serializable] public class BoolEvent : UnityEvent { } private void Awake() { m_Rigidbody2D = GetComponent(); if (OnLandEvent == null) OnLandEvent = new UnityEvent(); } private void FixedUpdate() { bool wasGrounded = m_Grounded; m_Grounded = false; // The player is grounded if a circlecast to the groundcheck position hits anything designated as ground // This can be done using layers instead but Sample Assets will not overwrite your project settings. Collider2D[] colliders = Physics2D.OverlapCircleAll(m_GroundCheck.position, k_GroundedRadius, m_WhatIsGround); for (int i = 0; i < colliders.Length; i++) { if (colliders[i].gameObject != gameObject) { m_Grounded = true; if (!wasGrounded) { m_hasDoubleJumped = false; OnLandEvent.Invoke(); } } } } public void Move(float move, bool crouch, bool jump) { //only control the player if grounded or airControl is turned on if (m_Grounded || m_AirControl) { // Move the character by finding the target velocity Vector3 targetVelocity = new Vector2(move * 10f, m_Rigidbody2D.velocity.y); // And then smoothing it out and applying it to the character m_Rigidbody2D.velocity = Vector3.SmoothDamp(m_Rigidbody2D.velocity, targetVelocity, ref m_Velocity, m_MovementSmoothing); // If the input is moving the player right and the player is facing left... if (move > 0 && !m_FacingRight) { // ... flip the player. Flip(); } // Otherwise if the input is moving the player left and the player is facing right... else if (move < 0 && m_FacingRight) { // ... flip the player. Flip(); } } // If the player should jump... if (m_Grounded && jump) { // Add a vertical force to the player. m_Grounded = false; m_hasDoubleJumped = false; m_Rigidbody2D.AddForce(new Vector2(0f, m_JumpForce)); } else if (!m_Grounded && jump && !m_hasDoubleJumped) { m_hasDoubleJumped = true; //Vector3 targetVelocity = new Vector2(move * 10f, m_DoubleJumpForce); m_Rigidbody2D.velocity = new Vector2(move * 10f, m_DoubleJumpForce); // And then smoothing it out and applying it to the character //m_Rigidbody2D.velocity = Vector3.SmoothDamp(m_Rigidbody2D.velocity, targetVelocity, ref m_Velocity, m_MovementSmoothing); //m_Rigidbody2D.AddForce(new Vector2(0f, m_DoubleJumpForce)); animator.SetTrigger("doubleJump"); } animator.SetBool("grounded", m_Grounded); animator.SetFloat("velocityX", Mathf.Abs(m_Rigidbody2D.velocity.x)); animator.SetFloat("velocityY", m_Rigidbody2D.velocity.y); } public void Teleport(Vector3 position) { m_Rigidbody2D.position = position; m_Velocity *= 0; m_Rigidbody2D.velocity *= 0; } public void Bounce() { Bounce(0.8f); } public void Bounce(float multiplier) { m_Rigidbody2D.velocity *= multiplier * -1; } private void Flip() { // Switch the way the player is labelled as facing. m_FacingRight = !m_FacingRight; // Multiply the player's x local scale by -1. Vector3 theScale = transform.localScale; theScale.x *= -1; transform.localScale = theScale; } } }