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

Cube being able to climb every surfaces using Raycast but cannot turn...

Discussion in 'Scripting' started by eAthis, Aug 18, 2022.

  1. eAthis

    eAthis

    Joined:
    Nov 16, 2015
    Posts:
    3
    Hi All !

    I'm developing a game on which everything is slow, you take your time to reach a point, enjoy the landscape... Semi-contemplation game on which you are a snail.

    A good challenge because as a snail, you are allowed to move on almost every surfaces. I decided to start using just a cube and try to figure out the mechanics.

    I've read a lot here and there, and came up with using raycasts. So far it works great as I can climb any sort of surface with the layer tag "ground". Some empty objects are attached to the cube and oriented so their ray is oriented to the ground at different locations so I can calculate the average normal of the ground. Then I rotate the cube.
    Here is the script and what I have.

    https://drive.google.com/file/d/11Kh6iB6AKqtN3NSOKw_WwQeeVdAFFpRZ/view?usp=sharing

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class GetNormalRaycast : MonoBehaviour
    6. {
    7.     public LayerMask mask;
    8.     public float groundCheckLength = 1;
    9.     public float leftCheckLength = 1;
    10.     public float middleCheckLength = 1;
    11.     public float rightCheckLength = 1;
    12.  
    13.     public Transform groundChecker;
    14.     public Transform leftChecker;
    15.     public Transform middleChecker;
    16.     public Transform rightChecker;
    17.  
    18.     private Vector3 groundNormal;
    19.     private Vector3 MiddleNormal;
    20.  
    21.     public float speed = 1;
    22.     public float rotationSpeed = 50;
    23.  
    24.     // Update is called once per frame
    25.     void Update(){
    26.         if (Input.GetAxis("Vertical") != 0 ){
    27.  
    28.             // Ground
    29.             //Ray ray = new Ray(transform.position, transform.up * -1.0f);
    30.             Ray groundRay = new Ray(groundChecker.position, groundChecker.forward);
    31.             RaycastHit groundHitInfo;
    32.  
    33.             if (Physics.Raycast(groundRay, out groundHitInfo, groundCheckLength, mask)){
    34.  
    35.                 Debug.DrawLine(groundRay.origin, groundHitInfo.point, Color.red);
    36.  
    37.                 Quaternion surfaceRot = Quaternion.FromToRotation (Vector3.up, groundHitInfo.normal);  
    38.                 Quaternion newRot = surfaceRot * Quaternion.AngleAxis(transform.rotation.eulerAngles.y, Vector3.up);
    39.                 groundNormal = groundHitInfo.normal;
    40.                 //transform.rotation = Quaternion.Slerp(transform.rotation, newRot, 0.1f);
    41.                 //Vector3 currentPos = transform.position;
    42.                 //Vector3 newPos = groundHitInfo.point + new Vector3(0f,0.5f,0f);
    43.                 //transform.position = Vector3.Slerp(currentPos,newPos, 0.1f);
    44.                
    45.             }else{
    46.  
    47.                 Debug.DrawLine(groundRay.origin, groundRay.origin + groundRay.direction *groundCheckLength, Color.green);
    48.                 //groundCheckLength += groundCheckLength;
    49.                 groundNormal = new Vector3(0f,0f,0f);
    50.                
    51.  
    52.             }
    53.             //Middle checker
    54.             Ray MiddleRay = new Ray(middleChecker.position, middleChecker.forward);
    55.             RaycastHit middleHitInfo;
    56.  
    57.             if (Physics.Raycast(MiddleRay, out middleHitInfo, middleCheckLength, mask)){
    58.  
    59.                 Debug.DrawLine(MiddleRay.origin, middleHitInfo.point, Color.red);
    60.  
    61.                 Quaternion surfaceRot = Quaternion.FromToRotation (Vector3.up, middleHitInfo.normal);  
    62.                 Quaternion newRot = surfaceRot * Quaternion.AngleAxis(transform.rotation.eulerAngles.y, Vector3.up);
    63.                 MiddleNormal = middleHitInfo.normal;
    64.             }else{
    65.  
    66.                 Debug.DrawLine(MiddleRay.origin, MiddleRay.origin + MiddleRay.direction *middleCheckLength, Color.green);
    67.                 MiddleNormal = new Vector3(0f,0f,0f);
    68.                 //middleCheckLength += middleCheckLength;
    69.  
    70.             }
    71.  
    72.             //float horizontalData = Input.GetAxis("Horizontal");
    73.             //Vector3 horizontalforce = new Vector3(0f, horizontalData, 0f);
    74.             Vector3 averageNormal = ((groundNormal + MiddleNormal) / 2);
    75.             Quaternion targetRotation = Quaternion.FromToRotation(Vector3.up, averageNormal);
    76.             //Debug.Log("X : " + targetRotation.eulerAngles.x);
    77.             transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, 0.08f);
    78.  
    79.             //transform.Rotate(targetRotation.eulerAngles.z,targetRotation.eulerAngles.x, 0f, Space.Self);
    80.             transform.Translate(Vector3.forward * speed * Time.smoothDeltaTime, Space.Self);
    81.  
    82.         }
    83.  
    84.         if(Input.GetAxis("Horizontal") != 0){
    85.  
    86.            
    87.             transform.Rotate(0,rotationSpeed * Time.deltaTime * Input.GetAxis("Horizontal"), 0);
    88.  
    89.  
    90.         }
    91.  
    92.     }
    93. }
    94.  
    The problem is that I can only go forward, no turns allowed. Also the cube is not "touching" the ground.
    I kind of know where this happens, because I apply a rotation every time the player presses the vertical input.

    Of course the cube has to be allowed to go left and right (not backward though).

    I'm kinda stuck now, I thought I could somehow get the float value of the Horizontal input, map it to a min and max angle and construct a vector3 with it, then add the value to the Quaternion... but not to avail for now.
    Maybe I'm not taking the problem by the right end.

    If you end up having a brilliant idea for me, I would really appreciate it ^^

    Have a good day !
    Martin
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,949
    You need to modify your directional inputs to be correctly oriented to the current surface you are walking on.

    For an example of this process, check out any tutorial for walking around a globe / sphere, such as this one:

     
  3. eAthis

    eAthis

    Joined:
    Nov 16, 2015
    Posts:
    3
    Thanks for the feedback Kurt !

    Unfortunately the problem remains.

    Orienting the object and make it "stick" to whatever is not the issue.
    But Because I reorient my object to match the ground normal (average of many), it then also reorients the rotation on the Y axis, causing the object to face world Z axis, and not my object Z axis (forward).
    In these lines I calculate the average normal and orient my object according to it.

    Code (CSharp):
    1. Vector3 averageNormal = ((groundNormal + MiddleNormal) / 2);
    2. Quaternion targetRotation = Quaternion.FromToRotation(Vector3.up, averageNormal);
    3. transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, 0.08f);
    I guess the issue is here because there is no info about my left or right input, I simply use the normal.
    I would like my cube to be able to go in the direction it is facing. Not always the world Z axis.

    If any idea ?

    Cheers
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,949
    Now you should go look at the FirstPersonController script from the tutorial above. It's only one line of code that transforms the rotation before driving the Rigidbody position, and it works correctly from any orientation you happen to be standing on.
     
  5. eAthis

    eAthis

    Joined:
    Nov 16, 2015
    Posts:
    3
    Hi !
    Thanks for the feedback.

    It is still not working unfortunately ^^
    I searched a lot and came across this issue on this tutorial, he is talking about cross product.
    https://devforum.roblox.com/t/orienting-a-part-to-the-ground-normal/521902/2

    This is exactly the issue I'm having. I still think it is because I rotate my object along the normal I get under the object.
    I can't wrap my head around it...

    Here is what I have ;
    https://drive.google.com/file/d/1fv9h_JMvRcn8oxa6tQZJ_e-VWUP3iswk/view?usp=sharing

    Thanks for any help !