Search Unity

Question How to implement friction in movement controlled by setting the velocity? (SSB-like physics?)

Discussion in 'Physics' started by ChronoSynth, Jun 29, 2021.

  1. ChronoSynth

    ChronoSynth

    Joined:
    Nov 20, 2020
    Posts:
    36
    I am making a party game with Super Smash Bros-like physics. For example, I want the player to slide when they release the Move key.

    Here is the code for my player controller:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.InputSystem;
    5.  
    6. public class PlayerBehavior : MonoBehaviour
    7. {
    8.     float movementValue = 0f;
    9.     [SerializeField] float maxSpeed = 10f;
    10.     public Rigidbody2D rb;
    11.     CapsuleCollider2D playerCollider;
    12.     [SerializeField] float jumpForce = 125f;
    13.     [SerializeField] float airControl = 5f;
    14.     bool isGrounded;
    15.     bool isMoving;
    16.     [SerializeField] float groundCheckDistance = 2f;
    17.     enum MovementCodeOptions { Default, Simple, Alternate };
    18.     [SerializeField] MovementCodeOptions movementCode = MovementCodeOptions.Default;
    19.     bool isFacingRight = true;
    20.     [SerializeField] float maxDecceleration = 2f;
    21.     private void Awake()
    22.     {
    23.         rb = gameObject.GetComponent<Rigidbody2D>();
    24.         playerCollider = gameObject.GetComponent<CapsuleCollider2D>();
    25.     }
    26.  
    27.     private void FixedUpdate()
    28.     {
    29.         Vector3 debugEndPos = transform.position;
    30.         debugEndPos.y -= groundCheckDistance;
    31.         Debug.DrawLine(transform.position, debugEndPos, Color.green);
    32.         if(Physics2D.Raycast(gameObject.transform.position, Vector2.down, groundCheckDistance, 1 << 3))
    33.         {
    34.             if (!isGrounded)
    35.                 isGrounded = true;
    36.             Debug.Log("Player is grounded");
    37.         }
    38.         else
    39.         {
    40.             if (isGrounded)
    41.                 isGrounded = false;
    42.         }
    43.         rb.velocity = new Vector2(movementValue * maxSpeed, rb.velocity.y);
    44.         if (movementValue == 0 && rb.velocity.magnitude != 0)
    45.         {
    46.             rb.velocity = new Vector2(rb.velocity.x + (isFacingRight ? -maxDecceleration : maxDecceleration), rb.velocity.y);
    47.         }
    48.        
    49.  
    50.         if (movementValue < 0 && isFacingRight)
    51.             Flip();
    52.         else if (movementValue > 0 && !isFacingRight)
    53.             Flip();
    54.  
    55.         /*if (rb.velocity.magnitude < maxSpeed)
    56.         {
    57.             rb.AddForce(new Vector2(movementValue * acceleration * Time.deltaTime * 50f, rb.velocity.y));
    58.         }*/
    59.     }
    60.  
    61.     void OnMove(InputValue value)
    62.     {
    63.         movementValue = value.Get<float>();
    64.     }
    65.  
    66.     public void Flip()
    67.     {
    68.         isFacingRight = !isFacingRight;
    69.         transform.localScale = new Vector3(transform.localScale.x * -1, transform.localScale.y, transform.localScale.z);
    70.     }
    71.  
    72.     void OnJump()
    73.     {
    74.         rb.AddForce(new Vector2(rb.velocity.x, jumpForce), ForceMode2D.Impulse);
    75.     }
    76.  
    77. }
    78.  
    TL;DR: On line 43, the controller moves the player by setting its rigidbody's velocity directly instead of using AddForce. Therefore, when the player stops moving, it comes to a complete stop instead of sliding to a stop. I don't want to use AddForce because the player accelerates from zero to its max speed instead of instantly starting in its max speed. I just want the player to decelerate when it stops moving. Does anyone know how to do this?
    While we're on the subject, how can I make my mid-air movement more like Super Smash Bros.?
     
  2. Papum20

    Papum20

    Joined:
    Feb 15, 2021
    Posts:
    10
    Maybe you can use Mathf.Lerp.


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class beanController : MonoBehaviour
    6. {
    7.  
    8.     Rigidbody2D RB;
    9.  
    10.     float horizontalInput = 0f;
    11.     [SerializeField] float speed = 20f;
    12.     [SerializeField] float damperTime = 0.5f;
    13.     float timer = 0f;
    14.  
    15.  
    16.  
    17.     private void Start()
    18.     {
    19.         RB = GetComponent<Rigidbody2D>();
    20.     }
    21.  
    22.     private void Update()
    23.     {
    24.         horizontalInput = Input.GetAxisRaw("Horizontal");
    25.     }
    26.  
    27.     private void FixedUpdate()
    28.     {
    29.  
    30.         if (horizontalInput != 0f)
    31.         {
    32.             RB.velocity = new Vector2(horizontalInput * speed, 0f);
    33.             timer = 0f;
    34.         }
    35.         else if(RB.velocity.x != 0f)
    36.         {
    37.             timer += Time.fixedDeltaTime;
    38.  
    39.             float newSpeed = Mathf.Lerp(speed, 0f, timer / damperTime);
    40.             if (RB.velocity.x < 0)
    41.                 newSpeed = -newSpeed;
    42.  
    43.             RB.velocity = new Vector2(newSpeed, 0f);
    44.         }
    45.  
    46.     }
    47.  
    48.  
    49. }
    50.  

    Lerp takes 3 parameters a, b and t and returns the value "situated" at a point t between a and b (t must be between 0 and 1, so if it's 0 lerp returns a, if it's 1 lerp returns b). Therefore in my script, as soon as the player stops giving an input a timer starts and with Lerp the velocity goes from a, that is the speed given with the input, and b, that is 0, the final speed: timer / damperTime equals 0 at the beginning, when timer is 0, and 1 at the end, when the timer equals the damperTime, that thus is the duration of the deceleration.
     
  3. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,456
    You already cross-posted this here.