Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Why doesn't code make rigidbody Capsule instantly snap to ground?

Discussion in 'Scripting' started by ynm11, Jan 26, 2022.

  1. ynm11

    ynm11

    Joined:
    Jul 6, 2021
    Posts:
    57
    Trying to make rigidbody Capsule snap to ground when leaving a ramp, rather than flying in the air.
    This does seem to snap it to the ground, but not instantly. It bounces a bit and then goes down.

    Gif of Ramp bounce: https://i.imgur.com/4HrywFH.mp4

    What might be changed to make the snap more instant?
    Thank you.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class FreshMove : MonoBehaviour
    6. {
    7.     public Rigidbody r;
    8.  
    9.     //Base Movement
    10.     public float horizontalInput;
    11.     public float verticalInput;
    12.     public Vector3 movDirection;
    13.     public float speed = 20f;
    14.  
    15.     //Ground Check
    16.     public bool isGrounded = true;
    17.     public Transform groundCheckTransform;
    18.     public float groundCheckRadius = 0.25f;
    19.     public LayerMask groundLayerMask;
    20.  
    21.     //Jump
    22.     public float jumpForce = 10f;
    23.     public bool isJumping;
    24.  
    25.     //Snapping
    26.     public int stepsSinceLastGrounded;
    27.     public int stepsSinceLastJump;
    28.  
    29.     void Awake()
    30.     {
    31.         groundLayerMask = LayerMask.GetMask("Ground");
    32.         r = this.GetComponent<Rigidbody>();
    33.     }
    34.  
    35.     void Update()
    36.     {
    37.         horizontalInput = Input.GetAxis("Horizontal");
    38.         verticalInput = Input.GetAxis("Vertical");
    39.         movDirection = new Vector3(horizontalInput, 0.0f, verticalInput).normalized;
    40.  
    41.         if (!isGrounded)
    42.         {
    43.             print("Not Grounded");
    44.             this.GetComponent<Renderer>().material.SetColor("_Color", Color.cyan);
    45.         }
    46.         else
    47.         {
    48.             this.GetComponent<Renderer>().material.SetColor("_Color", Color.white);
    49.         }
    50.  
    51.         if (Input.GetKeyDown(KeyCode.Space))
    52.         {
    53.             isJumping = true;
    54.         }
    55.     }
    56.  
    57.     public void FixedUpdate()
    58.     {
    59.         r.AddForce(movDirection * (speed + 10f), ForceMode.Force);
    60.  
    61.         if (isJumping == true)
    62.         {
    63.             Jump();
    64.         }
    65.  
    66.         GroundCheck();
    67.         UpdateState();
    68.     }
    69.  
    70.     void UpdateState()
    71.     {
    72.         stepsSinceLastGrounded += 1;
    73.         stepsSinceLastJump += 1;
    74.  
    75.         if (isGrounded || GroundSnap())
    76.         {
    77.             stepsSinceLastGrounded = 0;
    78.         }
    79.     }
    80.  
    81.     public void GroundCheck()
    82.     {
    83.         isGrounded = Physics.CheckSphere(groundCheckTransform.position, groundCheckRadius, groundLayerMask);
    84.     }
    85.  
    86.     void Jump()
    87.     {
    88.         stepsSinceLastJump = 0;
    89.         if (isGrounded)
    90.         {
    91.             r.AddForce(new Vector3(0f, jumpForce, 0f), ForceMode.Impulse);
    92.         }
    93.         isJumping = false;
    94.     }
    95.  
    96.     bool GroundSnap()
    97.     {
    98.         if (stepsSinceLastGrounded > 1 || stepsSinceLastJump <= 2)
    99.         {
    100.             return false;
    101.         }
    102.  
    103.         if (!Physics.Raycast(r.position, Vector3.down, out RaycastHit hit))
    104.         {
    105.             return false;
    106.         }
    107.  
    108.         speed = r.velocity.magnitude;
    109.         float dot = Vector3.Dot(r.velocity, hit.normal);
    110.         if (dot > 0f)
    111.         {
    112.             r.velocity = (r.velocity - hit.normal * dot).normalized * speed;
    113.         }
    114.         print("Snap");
    115.         return true;
    116.     }
    117. }
    Code is loosely based on the Surface Contact tutorial from CatLikeCoding.
     
    Last edited: Jan 26, 2022
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,517
    "Snapping" something generally means setting its position so that it instantly goes where you want.

    With Rigidbody always use .MovePosition() to directly set their positions.

    I don't see you doing anything like that above.

    I see computations on line 112 that set velocity with something complicated that is computed from the difference between a velocity (dx/dt) and a point in worldspace (x). That cannot possibly be right except by accident.

    Have you tried just setting the position to what you get from the hit.point?
     
    ynm11 likes this.