Search Unity

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

Discussion in 'Scripting' 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.?

    [UPDATE: 6/29/2021] I solved my first problem, but now I have another one: How do I implement skidding when the player changes direction? In my current set-up, the player stops sliding whenever they change direction or at the slightest nudge of the gamepad's control stick.
     
    Last edited: Jun 30, 2021
  2. GroZZleR

    GroZZleR

    Joined:
    Feb 1, 2015
    Posts:
    3,201
    Instead of setting the velocity to 0 on no input, decay it towards 0 with something like Mathf.MoveTowards.
     
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,689
    Exactly what Grozzler says above... and here is how I typically do this sort of thing:

    Smoothing movement between any two particular values:

    https://forum.unity.com/threads/beginner-need-help-with-smoothdamp.988959/#post-6430100

    You have currentQuantity and desiredQuantity.
    - only set desiredQuantity
    - the code always moves currentQuantity towards desiredQuantity
    - read currentQuantity for the smoothed value

    Works for floats, Vectors, Colors, Quaternions, anything continuous or lerp-able.

    The code: https://gist.github.com/kurtdekker/fb3c33ec6911a1d9bfcb23e9f62adac4
     
  4. ChronoSynth

    ChronoSynth

    Joined:
    Nov 20, 2020
    Posts:
    36
    At which line?
     
  5. ChronoSynth

    ChronoSynth

    Joined:
    Nov 20, 2020
    Posts:
    36
    Never mind. I figured it out. Thank you, GroZZleR!
     
  6. ChronoSynth

    ChronoSynth

    Joined:
    Nov 20, 2020
    Posts:
    36
    Follow-up: How do I implement skidding when the player changes direction? In my current set-up, the player stops sliding whenever they change direction or at the slightest nudge of the gamepad's control stick.
     
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,689
    Usually skidding is just an illusion: you were moving +10 units to the right and you stop.

    Stopping sets the desired speed to zero but your actual speed takes a moment to ease down to zero.

    During that time an animation component would observe those two values being different and choose which kind of a skid animation to show. Same goes for cartoon running crazily in place as you start moving.
     
  8. GroZZleR

    GroZZleR

    Joined:
    Feb 1, 2015
    Posts:
    3,201
    Skidding is the opposite of what you just did. Instead of setting their velocity to max speed instantly, you ramp up towards it instead. So if they change direction, the velocity takes 0.x seconds to flip from +max speed to -max speed and change direction.