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. Dismiss Notice

Collision conditionally not working on blender import

Discussion in 'Editor & General Support' started by XsebX, Jan 9, 2021.

  1. XsebX

    XsebX

    Joined:
    Nov 25, 2018
    Posts:
    6
    Hi there,


    I'm running into an issue with collision detection between a from blender imported object and a standard cube. Allow me to outline the issue:

    1. I have created a map element in Blender which I broke down into one part for the visual and one part for the collider

    visual.png collider.png

    2. After importing the object into unity, I deactivated the mess render on the collider and added a mesh collider.

    3. I added a player which at this point is just a cube, which has a box collider and a rigidbody component. Just for scale:

    ratio.png

    4. To the player is controlled via the joystick in the bottom right corner and lastly I added the following player controller script:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Cinemachine;
    5.  
    6. public class PlayerController : MonoBehaviour
    7. {
    8.     public float speed;
    9.     public Joystick joystick;
    10.     public Cinemachine.CinemachineVirtualCamera cvc;
    11.     private CinemachineFramingTransposer cft;
    12.  
    13.     private Rigidbody body;
    14.     private Vector3 moveVelocity;
    15.     public float moveDirection;
    16.     public float rotation;
    17.     public float rotationQuotient;
    18.     private float moveIntensity = 0;
    19.     public float moveIntensityIncrease;
    20.     private float moveIntensityIncreaseAdapted;
    21.     public float moveIntensityDecay;
    22.     public float minCamHeight;
    23.     public float maxCamHeight;
    24.  
    25.     private float keepInInterval(float value, float min, float max)
    26.     {
    27.         float step = max - min;
    28.         while (value < min) value += step;
    29.         while (value > max) value -= step;
    30.         return value;
    31.     }
    32.  
    33.     // Start is called before the first frame update
    34.     void Start()
    35.     {
    36.         body = GetComponent<Rigidbody>();
    37.  
    38.         CinemachineComponentBase componentBase = cvc.GetCinemachineComponent(CinemachineCore.Stage.Body);
    39.         if (componentBase is CinemachineFramingTransposer)
    40.             cft = (componentBase as CinemachineFramingTransposer);
    41.  
    42.         body.rotation = Quaternion.Euler(0, rotation, 0);
    43.     }
    44.  
    45.     // Update is called once per frame
    46.     void Update()
    47.     {
    48.         Vector2 moveInput = new Vector2(joystick.Horizontal, joystick.Vertical);
    49.         moveVelocity.x = moveInput.x * speed;
    50.         moveVelocity.z = moveInput.y * speed;
    51.  
    52.         if (moveInput.SqrMagnitude() > 0.01)
    53.         {
    54.             float inputDirectionInRadian = Mathf.Atan2(moveInput.x, moveInput.y);
    55.             float inputDirectionInDegree = inputDirectionInRadian * 180.0f / Mathf.PI + 180;
    56.             moveDirection = inputDirectionInDegree;
    57.         }
    58.  
    59.         moveIntensityIncreaseAdapted = (moveIntensityIncrease + moveIntensityDecay) * moveInput.SqrMagnitude() - moveIntensityDecay;
    60.     }
    61.  
    62.     private void FixedUpdate()
    63.     {
    64.         moveIntensity += moveIntensityIncreaseAdapted;
    65.         if (moveIntensity > 1)
    66.             moveIntensity = 1;
    67.         if (moveIntensity < 0)
    68.             moveIntensity = 0;
    69.  
    70.         float curCamHeight = minCamHeight + (maxCamHeight - minCamHeight) * moveIntensity;
    71.         cft.m_CameraDistance = curCamHeight;
    72.  
    73.         body.MovePosition(body.position + moveVelocity * Time.fixedDeltaTime);
    74.         float bodyRoation = keepInInterval(rotation, 0, 360);
    75.         float deltaRotation = moveDirection - bodyRoation;
    76.         deltaRotation = keepInInterval(deltaRotation, -180, 180);
    77.         float rotationStep = deltaRotation / rotationQuotient;
    78.         float newRotation = bodyRoation + rotationStep;
    79.         rotation = keepInInterval(newRotation, 0, 360);
    80.         body.rotation = Quaternion.Euler(0, rotation, 0);
    81.     }
    82. }
    Now when I start the "game" the cube falls on the map and I can move it around as I please. If I slowly approach the wall it collides with it the way it is supposed to. When I run at it at higher (but not very high) speed, it starts to push through the wall until it ultimately passes through. At higher speeds it just passes through as if there was no collider.

    I've tried to fix the problem by:
    • simplifying the collider
    • making the player collider bigger
    • adjusting the Fixed Timestep to way smaller values
    • checked that the player object is not tunneling through the map element collider with in one timestep, which it does not
    I tried searching for the solution however due to limited Unity knowledge I might be lacking the right terms, could somebody please point me into the right direction?

    Cheers

    xsebx
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,723
    You can also try changing the Collision Detection mode on your moving object's Rigidbody from Discrete (the default) to Continuous, which should be a bit better at preventing collisions.

    If you still have tunneling problems, a lot of people get around it by raycasting or sphereasting forward in each FixedUpdate to see if there are any obstacles your object will hit during the next physics update.
     
  3. XsebX

    XsebX

    Joined:
    Nov 25, 2018
    Posts:
    6
    Thank you for the fast response. I forgot to mention that I had already tried to change the Collision Detection mode which did not improve upon the situation.

    I will give the raycasting/ spherecasting approach a shot. Thanks :)
     
  4. XsebX

    XsebX

    Joined:
    Nov 25, 2018
    Posts:
    6
    I have implemented the raycasting method, and it works very well, including the player decelerating before a potential collusion. Thank you for the hint.

    For others that may encounter the issue here is my adapted player controller:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Cinemachine;
    5.  
    6. public class PlayerController : MonoBehaviour
    7. {
    8.     public float maxSpeed;
    9.     public float curSpeed = 0;
    10.     public Joystick joystick;
    11.     public Cinemachine.CinemachineVirtualCamera cvc;
    12.     private CinemachineFramingTransposer cft;
    13.  
    14.     private Rigidbody body;
    15.     private Vector3 moveVelocity;
    16.     public float moveDirection;
    17.     public float rotation;
    18.     public float rotationQuotient;
    19.     private float moveIntensity = 0;
    20.     public float moveIntensityIncrease;
    21.     private float moveIntensityIncreaseAdapted;
    22.     public float moveIntensityDecay;
    23.     public float minCamHeight;
    24.     public float maxCamHeight;
    25.  
    26.     public LayerMask collisionLayerMask;
    27.     public float minRayLength;
    28.     public float maxRayLength;
    29.  
    30.     private float keepInInterval(float value, float min, float max)
    31.     {
    32.         float step = max - min;
    33.         while (value < min) value += step;
    34.         while (value > max) value -= step;
    35.         return value;
    36.     }
    37.  
    38.     // Start is called before the first frame update
    39.     void Start()
    40.     {
    41.         body = GetComponent<Rigidbody>();
    42.  
    43.         CinemachineComponentBase componentBase = cvc.GetCinemachineComponent(CinemachineCore.Stage.Body);
    44.         if (componentBase is CinemachineFramingTransposer)
    45.             cft = (componentBase as CinemachineFramingTransposer);
    46.  
    47.         body.rotation = Quaternion.Euler(0, rotation, 0);
    48.     }
    49.  
    50.     // Update is called once per frame
    51.     void Update()
    52.     {
    53.         // User input collection
    54.         Vector2 moveInput = new Vector2(joystick.Horizontal, joystick.Vertical);
    55.  
    56.         // Collision Raycast
    57.         RaycastHit hit;
    58.         float raylength = minRayLength + (maxRayLength - minRayLength) * (curSpeed / maxSpeed) + 0.1f;
    59.  
    60.         if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, raylength, collisionLayerMask))
    61.         {
    62.             Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.forward) * hit.distance, Color.yellow);
    63.         }
    64.         else
    65.         {
    66.             Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.forward) * raylength, Color.white);
    67.         }
    68.  
    69.         // Determine maximum player velocity depending on distance to collidable objects
    70.         float speed = maxSpeed;
    71.         if(hit.distance!=0)
    72.         {
    73.             speed = ((hit.distance - minRayLength) / (maxRayLength - minRayLength)) * maxSpeed;
    74.         }
    75.  
    76.         // Determine current player velocity
    77.         moveVelocity.x = moveInput.x * speed;
    78.         moveVelocity.z = moveInput.y * speed;
    79.         curSpeed = Mathf.Sqrt(Mathf.Pow(moveVelocity.x, 2) + Mathf.Pow(moveVelocity.y, 2));
    80.  
    81.         // Determine input player direction
    82.         if (moveInput.SqrMagnitude() > 0.001)
    83.         {
    84.             float inputDirectionInRadian = Mathf.Atan2(moveInput.x, moveInput.y);
    85.             float inputDirectionInDegree = inputDirectionInRadian * 180.0f / Mathf.PI;
    86.             moveDirection = inputDirectionInDegree;
    87.         }
    88.  
    89.         moveIntensityIncreaseAdapted = (moveIntensityIncrease + moveIntensityDecay) * moveInput.SqrMagnitude() - moveIntensityDecay;
    90.     }
    91.  
    92.     private void FixedUpdate()
    93.     {
    94.         moveIntensity += moveIntensityIncreaseAdapted;
    95.         if (moveIntensity > 1)
    96.             moveIntensity = 1;
    97.         if (moveIntensity < 0)
    98.             moveIntensity = 0;
    99.  
    100.         float curCamHeight = minCamHeight + (maxCamHeight - minCamHeight) * moveIntensity;
    101.         cft.m_CameraDistance = curCamHeight;
    102.  
    103.         body.MovePosition(body.position + moveVelocity * Time.fixedDeltaTime);
    104.         float bodyRoation = keepInInterval(rotation, 0, 360);
    105.         float deltaRotation = moveDirection - bodyRoation;
    106.         deltaRotation = keepInInterval(deltaRotation, -180, 180);
    107.         float rotationStep = deltaRotation / rotationQuotient;
    108.         float newRotation = bodyRoation + rotationStep;
    109.         rotation = keepInInterval(newRotation, 0, 360);
    110.         body.rotation = Quaternion.Euler(0, rotation, 0);
    111.     }
    112. }