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

Resolved Applying ground normal to movement vector

Discussion in 'Scripting' started by X1r15, Dec 23, 2021.

  1. X1r15

    X1r15

    Joined:
    Dec 19, 2019
    Posts:
    12
    Hello, I hope you are doing great.

    I am trying to make a simple FPS controller and I am stuck a little bit with handling slopes properly.
    I managed to achieve "proper sticking to slopes" by applying additional force downwords but I am not very happy with this solution.

    I think the cleanest way of handling that would be to modify the movement vector by a slope normal, however I haven't managed to do that. Any tips on how to connect those two parts to make what I would like them to do? :)

    Basically I would like to rotate the "walkVector" (from code below) to move the character taking into consideration the slope stored in _groundHit.

    Code (CSharp):
    1. //Part A:
    2. CharacterController _controller = GetComponent<CharacterController>()
    3. RaycastHit _groundHit;
    4. //...
    5. Physics.Raycast(_groundCheck.position, Vector3.down, out _groundHit, _checkRadius, _groundMask);
    6.  
    7. //Part B:
    8. var walkInput = _input.GetWalkInput();
    9. var walkVector = transform.right * walkInput.x + transform.forward * walkInput.y;
    10. _controller.Move(walkVector.normalized * _speed * Time.deltaTime);
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,971
  3. X1r15

    X1r15

    Joined:
    Dec 19, 2019
    Posts:
    12
    @Kurt-Dekker thank you! I love it. :)

    Unfortunately I wanted to actually learn how to solve my problem (I like to know how things work) rather than get ready solution! Regardless, thank you for the link, I am sure it will come handy sooner or later :).
     
  4. AnimalMan

    AnimalMan

    Joined:
    Apr 1, 2018
    Posts:
    1,164
    Are you using Unity Terrain or a Plane?

    which shape is your collider? could you get the highest point of collision and use this as your characters y vector?
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,971
    I can certainly respect that.

    Looking at other functioning code to see how they did feature X (slope walking for instance) and then putting that code aside and re-implementing it yourself can be very helpful, and helpful in two ways:

    1. you learn how to study what other code does and why (this is important because one day you will encounter your own code, written years earlier, and you will have to figure out what on earth it does all over again!)

    2. you learn how to implement a concept in your own code, which even gives you the opportunity to implement even more perfectly tailored to your exact needs.

    As far as modifying vectors based on normals and computing a reduced slope walk speed, these are all just vector operations that will gradually become second-nature as you use them more in different game contexts. It can often be helpful to draw diagrams for yourself as well.
     
  6. X1r15

    X1r15

    Joined:
    Dec 19, 2019
    Posts:
    12
    @AnimalMan, I am having a simple level created using ProBuilder. The character collider is capsule.

    @Kurt-Dekker, this is very valid point :). I will have a look into the code of the controller you provided to see if they actually implemented the feature I am interested in :)
     
  7. X1r15

    X1r15

    Joined:
    Dec 19, 2019
    Posts:
    12
    Maybe it will be useful for somebody. I managed to achieve the desired result using cross product:
    Code (CSharp):
    1.         var inputX = Input.GetAxisRaw("Horizontal")  * 3;
    2.         var inputY = Input.GetAxisRaw("Vertical")  * 3;
    3.  
    4.         var desiredVelocity = new Vector3(inputX, _rigidbody.velocity.y, inputY);
    5.         RaycastHit rh;
    6.         Physics.Raycast(_groundCheck.position, Vector3.down, out rh, 0.2f, LayerMask.GetMask("Ground"));
    7.         if (rh.normal != Vector3.zero)
    8.         {
    9.             desiredVelocity = Quaternion.AngleAxis(90, Vector3.up) * Vector3.Cross(desiredVelocity, rh.normal);
    10.         }
    11.  
    12.         _rigidbody.velocity = desiredVelocity;