Search Unity

Preventing player from falling using raycast, but acting like a collider

Discussion in 'Physics' started by niknakgames, Oct 28, 2018.

  1. niknakgames

    niknakgames

    Joined:
    Aug 7, 2015
    Posts:
    25
    Hey everyone,

    I have a lot of floor tiles my player runs across. I don't want to create walls or invisible walls because these maps can get pretty big and some other reasons for future game play.

    What I'm doing now is raycasting slightly in front of the player and if there is nothing in front of the player it changes the vector to zero.This stops the player dead in his tracks and looks a little strange and doesn't feel quite right.
    https://imgur.com/AYNSkGN


    Is there a way to make it work more like a collider / wall and sort of slide along the edge? A little stumped on the math that would take or how to best achieve this effect and obviously setting the vector to zero is not good.

    Here is the code.
    Code (CSharp):
    1.         var horizontal = Input.GetAxis("Horizontal");
    2.         var vertical = Input.GetAxis("Vertical");
    3.         moveDirection = new Vector3(horizontal, 0, vertical);
    4.         moveDirection *= moveSpeed;
    5.         moveDirection.y = moveDirection.y - (gravity * Time.deltaTime);
    6.  
    7.         //Rotate
    8.         if (horizontal != 0.0f || vertical != 0.0f)
    9.         {
    10.             var rotationDirection = new Vector3(horizontal, 0, vertical);
    11.             transform.rotation = Quaternion.LookRotation(rotationDirection, Vector3.up);
    12.         }
    13.  
    14.         RaycastHit groundCheck;
    15.         if (!Physics.Raycast(transform.position + (transform.forward / 6), Vector3.down, out groundCheck, 3))
    16.         {
    17.             Debug.Log("NO GROUND");
    18.             Debug.DrawRay(transform.position + (transform.forward / 6), (Vector3.down), Color.red);
    19.             moveDirection = Vector3.zero;
    20.         }
    21.  
    22.         controller.Move(moveDirection * Time.deltaTime);
     
  2. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    maybe make it more of a drop off so the closer the player get's to the edge the slower he can go, by inverse sqr or some kind of log.

    kinda acts like a force field
     
  3. niknakgames

    niknakgames

    Joined:
    Aug 7, 2015
    Posts:
    25
    I actually got it half working.It works going up and down on the left and right sides of tiles but only works if you hit the top and bottom at a perfect angle. Anything else and it falls off. I'm close, but any insight would be appreciated.
    Here are the results:
    https://i.imgur.com/3iXblKa.gif


    Code (CSharp):
    1.           if (rotationDirection.x !=0)
    2.                 moveDirection.x = 0;
    3.             else if (rotationDirection.z != 0)
    4.                 moveDirection.z = 0;

    Edit:
    I'm stumped. I've tried many variations of this, but no luck.
     
    Last edited: Oct 29, 2018
  4. niknakgames

    niknakgames

    Joined:
    Aug 7, 2015
    Posts:
    25
    I made the following chart for movement directions.
    tile.png

    The problem comes in when traveling at an angle. If at 0,0/1,1/-1-1/1-1. I can't clamp left or right / up or down because the player could be traveling either direction and the values would be the same in both scenarios (see chart)

    I feel like there has to be a better way to solve this, but i'm definitely struggling. :(
     
  5. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    i think you boxing your self in there, how is this supposes to solve the problem?

    i think that's a good way, i don't understand why it's not working though.

    why are you dividing by 6? i'd try using the collider extends +.01 to avoid detecting the player with the cast.

    i think this should lead you in the right direction as to whats going wrong

    Code (CSharp):
    1.      
    2.  
    3.         Vector3 position = transform.position + (transform.forward / 6);
    4.         RaycastHit groundCheck;
    5.         if (!Physics.Raycast(position, Vector3.down, out groundCheck, 3) {
    6.  
    7.             Debug.Log("No ground found");
    8.             Debug.DrawRay(position, (Vector3.down), Color.red);
    9.             moveDirection = Vector3.zero;
    10.  
    11.         } else{
    12.          
    13.             Debug.Log("Ground found");
    14.             Debug.DrawRay(position, (Vector3.down), Color.blue);
    15.         }
    16.  
    also, you're not actually using the hit info so i'd suggest something like this (you need the ground tagged though

    Code (CSharp):
    1.      
    2.  
    3.         Vector3 position = transform.position + (transform.forward / 6);
    4.         RaycastHit groundCheck;
    5.         if (!Physics.Raycast(position, Vector3.down, out groundCheck, 3) && groundCheck.collider.comparTag("Ground"){
    6.  
    7.             Debug.Log("No ground found");
    8.             Debug.DrawRay(position, (Vector3.down), Color.red);
    9.             moveDirection = Vector3.zero;
    10.  
    11.         } else{
    12.          
    13.             Debug.Log("Ground found");
    14.             Debug.DrawRay(position, (Vector3.down), Color.blue);
    15.         }
    16.  
     
    Last edited: Oct 31, 2018
  6. LamestarGames

    LamestarGames

    Joined:
    Aug 7, 2017
    Posts:
    4
    This is an old thread but I would like to offer one possible solution. I will say I just ripped this out of the game I'm working on so there may be some errors I'm not catching.

    The general idea:
    Every frame check if we are on the ground with a Ray
    If we are store that new position in a private Vector3
    If we are not use the last recorded position to move the player

    It could be optimized a bit, and I would like if it didn't "stick" while running along the wall, but that could easily be achieved by adding a small impulse force on the player in the direction from where they fell minus their last recorded grounded position.

    Code (CSharp):
    1. private Vector3 lastGroundedPosition;
    2.  
    3. private void Update()
    4.     {
    5.         Ray ray = new Ray(this.transform.position + Vector3.up * 0.25f, Vector3.down);
    6.         if (Physics.Raycast(ray, out RaycastHit hit, 0.3f))
    7.         {
    8.             lastGroundedPosition = this.transform.position;
    9.         }
    10.         else
    11.         {
    12.             //Debug.Log("Player Fell off the Map");
    13.             this.transform.position = lastGroundedPosition;
    14.         }
    15.     }
    16.