Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Problem with Physics Character Controller

Discussion in 'Scripting' started by AYFukushima, Sep 28, 2016.

  1. AYFukushima

    AYFukushima

    Joined:
    Feb 4, 2013
    Posts:
    12
    Hi!

    I've implemented a character controller using physics but when I apply a force in a slope (see the gif), there is a force applied in the Y axis everytime and I have no ideia where it came from.

    (GIF showing the problem)
    http://gph.is/2dl0C1K

    The white line represent the inversed force applied. The red lines shows the rigidbody velocity.

    (To draw the lines I'm using this asset, it´s awesome)
    https://www.assetstore.unity3d.com/en/#!/content/11396

    I'm using the code below:

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class PhysicsCharacterController : MonoBehaviour
    5. {
    6.     Rigidbody cachedRigidbody;
    7.  
    8.     Vector3 movementForce;
    9.     Vector3 gravityForce = new Vector3(0, -10f, 0);
    10.  
    11.     public float maxMovementSpeed = 5;
    12.     public float jumpHeight = 8000;
    13.  
    14.     public bool normalizeToGround;
    15.  
    16.     public Rigidbody CachedRigidbody
    17.     {
    18.         get
    19.         {
    20.             if (cachedRigidbody == null)
    21.                 cachedRigidbody = GetComponent<Rigidbody> ();
    22.  
    23.             return cachedRigidbody;
    24.         }
    25.     }
    26.  
    27.     void Update()
    28.     {
    29.         movementForce.x = Input.GetAxis("Horizontal");
    30.         movementForce.y = 0f;
    31.         movementForce.z = Input.GetAxis("Vertical");
    32.  
    33.         if(normalizeToGround)
    34.         {
    35.             RaycastHit hit;
    36.             Ray ray = new Ray(transform.position, Vector3.down);
    37.  
    38.             if(Physics.Raycast (ray, out hit, 10f))
    39.                 movementForce = Vector3.ProjectOnPlane (movementForce, hit.normal);
    40.         }
    41.  
    42.         DebugExtension.DebugArrow (transform.position + transform.up, movementForce);
    43.  
    44. //        movementForce = transform.TransformDirection (movementForce);
    45.         movementForce = movementForce.normalized * maxMovementSpeed;
    46.  
    47.         if (movementForce != Vector3.zero)
    48.         {
    49.             Vector3 lookDirection = movementForce;
    50.             lookDirection.y = 0f;
    51.  
    52.             transform.rotation = Quaternion.Lerp (transform.rotation, Quaternion.LookRotation (lookDirection), Time.deltaTime * 20f);
    53.         }
    54.  
    55.         if (Input.GetKeyDown (KeyCode.Space))
    56.             ApplyJumpForce ();
    57.  
    58.         if (Input.GetKeyDown (KeyCode.F))
    59.         {
    60.             Vector3 force = Vector3.zero;
    61.  
    62.             if(normalizeToGround)
    63.             {
    64.                 RaycastHit hit;
    65.                 Ray ray = new Ray(transform.position, Vector3.down);
    66.  
    67.                 if(Physics.Raycast (ray, out hit, 10f))
    68.                     force = Vector3.ProjectOnPlane (transform.forward, hit.normal);
    69.             }
    70.  
    71.             DebugExtension.DebugArrow (transform.position, force * 10f, 0.3f, 2f);
    72.  
    73.             AddImpulseForce (force * -40);
    74.         }
    75.  
    76.         DebugExtension.DebugArrow(transform.position + transform.up, CachedRigidbody.velocity, Color.red, 0.2f, 2f);
    77.     }
    78.  
    79.     void FixedUpdate()
    80.     {
    81.         ApplyMovementForce ();
    82.         ApplyGravityForce ();
    83.     }
    84.  
    85.     public void ApplyMovementForce()
    86.     {
    87.         Vector3 velocity = CachedRigidbody.velocity;
    88.         Vector3 velocityChange = movementForce - velocity;
    89.  
    90.         velocityChange.x = Mathf.Clamp (velocityChange.x, -maxMovementSpeed, maxMovementSpeed);
    91.         velocityChange.z = Mathf.Clamp (velocityChange.z, -maxMovementSpeed, maxMovementSpeed);
    92.         velocityChange.y = 0f;
    93.  
    94.         CachedRigidbody.AddForce (velocityChange, ForceMode.VelocityChange);
    95.     }
    96.  
    97.     public void ApplyGravityForce()
    98.     {
    99.         CachedRigidbody.AddForce (gravityForce);
    100.     }
    101.  
    102.     public void ApplyJumpForce()
    103.     {
    104.         CachedRigidbody.AddForce (new Vector3(0f, Mathf.Sqrt (2f * jumpHeight * -gravityForce.y), 0f));
    105.     }
    106.  
    107.     public void AddImpulseForce(Vector3 pForce)
    108.     {
    109.         CachedRigidbody.AddForce (pForce, ForceMode.Impulse);
    110.     }
    111.  
    112.     void OnGUI()
    113.     {
    114.         GUILayout.Box ("Speed: " + CachedRigidbody.velocity.magnitude.ToString ("0.000"));
    115.     }
    116. }
    117.  
    Thanks a lot!

    (And sorry for my bad english).
     
  2. CloudKid

    CloudKid

    Joined:
    Dec 13, 2015
    Posts:
    207
    k, so you I don't think you need to apply gravity force. Unity apply that automaticly. So in your example gravity is actually 19.7f

    If you defined bounciness for your colliders it might bounce on touching the ground. Especially with that gravity.

    Now, if that is not the problem, when is the strange behavior happening? When you are not pressing anything, on when you are pressing "F". When you are pressing F, you are sending a ray from your player position directly into the ground. If the ray touches anything you are projecting transform.forward into the ground. That makes 0 sense to me. Just why? Are you trying to move your player forwards taking into account slopes? And why are you multiplying this obtain direction with -40? That means you will go in the opposite direction of transform.forward... Add an debug at line 108 and see what is the actual value of pForce.
     
  3. AYFukushima

    AYFukushima

    Joined:
    Feb 4, 2013
    Posts:
    12
    Hi! Thanks for the reply.

    I prefer to apply the gravity manually because I have a better control in some situations (like the jump time and speed), in this example the UseGravity in rigidbody is disabled.

    About the bounciness, I use a custom PhysicsMaterial, with no friction and no bounciness in my player.

    The problem happens when I press the "F" key. I send the ray to know the ground normal, so I can apply a force relative to the ground, not based on the player direction (Image below) or angle, but even if I set the boolean "normalizeToGround" to false, the problem continues to happen.

    Example.png

    The value I multiply for -40 is the force applied when the F is pressed. I'm doing this to simulate a external force (like a Push received from a enemy).

    I've added the Debug on line 108 and the force is 40.

    Thanks.