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

Need guidance on a method for wall-interraction for player control

Discussion in 'Scripting' started by Carl_Slate, Jun 3, 2020.

  1. Carl_Slate

    Carl_Slate

    Joined:
    May 27, 2020
    Posts:
    12
    Hello Unity forum users. I'm a beginner with unity, putting together a player control script for my first time, and I am stumped with figuring out how to get wall-interactions. I have a character that can run around and jump and it's all wonderful until I walk through a wall and do a face-palm.

    Rays work beautifully for floors and gravity, but I've had no success using them for walls. I need a way to make the player push back from the wall relative to the angle of the surface of the wall, but how can I get that angle?

    I've tried using rayhit.normal/.point/.barycentricCoordinate to work out some surface-normal-like rotation, but I haven't found anything that results in an effective angle/rotation to achieve this. I've tried cleverly using 2 rayhit.points side-by-side to get a horizontal angle of the face to translate by, but that doesn't work either (which frankly has me baffled).

    Does anyone have a strategy for wall interactions (ie so the player can't walk through walls) that they would be willing to share or suggest? I'm developing a 3rd person RPG-type control system with a character that can run around and go nuts hopping about its environment. FYI (although I'm sure I've already made it obvious) I am inexperienced with both coding and math. Eager to learn, but still, keep than in mind, as I may not be able to follow anything too complex. Thank you in advance for anyone who contributes!
     
  2. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,890
    CharacterController Move/SimpleMove are for moving with collisions. Just put your movement vector as the parameter and you will not walk through colliders.

    Code (csharp):
    1. private CharacterController _cc;
    2.  
    3. void Awake
    4. {
    5.     _cc = GetComponent<CharacterController>();
    6. }
    7.  
    8. void Update()
    9. {
    10.     //...your code, input, final movement vector, etc
    11.  
    12.     _cc.Move(movementVector);
    13. }
    For more complex controllers most people seem to attempt using the physics system by setting the velocity. This allows you to 'push' physics objects you bump into, but is harder to control.

    You can also do custom raycasts, but I have no idea about that.
     
  3. Carl_Slate

    Carl_Slate

    Joined:
    May 27, 2020
    Posts:
    12
    Oh wow, I can see the obvious benefits of this. It automatically handles almost everything I have been working on from scratch for the last couple weeks with raycasts, but + more. Why don't any of the tutorials point to this?? There is truly no replacement for the kind of help I've been getting on this forum.

    But, it seems character controller is incapable of respecting an object's rotation, it can only make movement in global coordinates (fixed-forward, orientation never changes). That makes it quite useless for 3rd-person controls, where the character runs in the direction it is facing. Oh, and I guess 1st-person controls as well, since they work the same. Maybe that's why none of the unity youtubers suggest it...
     
    Last edited: Jun 3, 2020
    Kurt-Dekker likes this.
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,971
    I think good old CC was trying to solve a lot of problems in a way that helped most people. I was just reading the discussion at the bottom of this page:

    https://docs.unity3d.com/Manual/class-CharacterController.html

    For-wall-running mechanics, perhaps you want to make your own invisible wall-walking agent and then when in wall run mode drive that controller and tell the CC to just follow it? I haven't thought much on it beyond that but it might work.
     
  5. Carl_Slate

    Carl_Slate

    Joined:
    May 27, 2020
    Posts:
    12
    Yeah, after a few more hours of fiddling with it, I'd say CharacterController is definitely much more complicated/difficult to use than just simulating collisions with rays. With some more kajiggering, I figured out how to make the CharacterController.Move work relative to the player, but when the input goes back to 0/0 (release the controls), it only springs back to the center of the world. I haven't figured out a way to get ordinary/free/consistent control out of it.

    I love the way it automatically collides with walls (and everything else?), but I'm thinking getting charactercontroller properly hammered out to a practical state is probably going to be a lot more work than just, for example, getting the normal vector of a face which the player has collided with (problem is I just don't know how to do that :().
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,971
    I'm thinking the easiest approach would be to have some kind of special collider type for walls so you can recognize when you leap towards one and need to run along it, then switch your logic to a different wall-run logic until you come off it... I'm sure there are wall run tutorials out there on the YooToobs but I've not checked personally.
     
  7. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,890
    I don't think I understood the original post. You wanted to walk on walls? If not, the CC should be able to do everything easily. It's much easier than a custom solution.

    The going back to center suggests you are just inserting input as the Move parameter. Input goes back to zero when not pressed.

    Here is the most barebones FPS controller I can think of.
    - Mouse X rotates the player left/right.
    - Mouse Y rotates the camera up/down.
    - WASD moves the player where they are facing.
    Code (csharp):
    1. [Header("Settings")]
    2. public float moveSpeed = 5f;
    3.  
    4. [Header("References")]
    5. public CharacterController cc; // On same GameObject, make Center (0, 1, 0), Height 2
    6. public Transform cameraT; // Camera is child object at position (0, 1.7, 0)
    7.  
    8. void Update()
    9. {
    10.     // WASD / Mouse input numbers
    11.     var h = Input.GetAxis("Horizontal");
    12.     var v = Input.GetAxis("Vertical");
    13.     var mouseX = Input.GetAxis("Mouse X");
    14.     var mouseY = Input.GetAxis("Mouse Y");
    15.  
    16.     // Relative movement
    17.     var forward = transform.forward * v; // Forward/back direction based on player's current facing
    18.     var right = transform.right * h; // Right/left direction based on player's current facing
    19.     var finalMoveDirection = right + forward;
    20.  
    21.     // Move player with collisions
    22.     cc.Move(finalMoveDirection * moveSpeed * Time.deltaTime);
    23.  
    24.     // Rotate player root using mouse left/right
    25.     transform.Rotate(new Vector3(0f, mouseX, 0f);
    26.  
    27.     // Rotate camera using mouse up/down
    28.     cameraT.Rotate(new Vector3(mouseY, 0f, 0f));
    29. }
    In the actual world, I would split this code into seperate movement/look components.

    For third-person, I would seperate the camera to be its own GameObject/component and make it follow the player. There are a few ways to make the character turn - child-only turning, or turn the entire GameObject, like with the FPS example above. I can maybe post some code for that later.