Search code examples
c#unity-game-enginegame-physics

Prevent object from passing through collider


I am building a 3D maze that is moved by the player. I'm taking a "labyrinth" approach and having a small ball be maneuvered through the maze when the player moves the maze. The problem occurs when the player moves a wall that the ball is currently resting on in the direction of the ball. The ball passes through the wall and stops on the next available wall.

The maze uses a mesh collider and rigidbody and the ball is a sphere collider.

I have drastically increased the physics frame rate to no avail. Considering the complexity of the maze and the potentially large number of maze combinations I really don't want to attach simple colliders to every wall. Any tips, tricks, suggestions, comments, etc. would be appreciated.

Ball Script for continious rotation:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ballGravity : MonoBehaviour {
    public Rigidbody m_Rigidbody;
    public Vector3 m_EulerAngleVelocity;

    // Use this for initialization
    void Start () {
        m_EulerAngleVelocity = new Vector3 (0, 100, 0);
        m_Rigidbody = GetComponent<Rigidbody>();
    }

    // Update is called once per frame
    void FixedUpdate () {
        Quaternion deltaRotation = Quaternion.Euler (m_EulerAngleVelocity * Time.deltaTime);
        m_Rigidbody.MoveRotation (m_Rigidbody.rotation * deltaRotation);
    }

}

Maze Rotation Script:

using UnityEngine;
using System.Collections;

public class rotObj : MonoBehaviour 
{
    private float baseAngle = 0.0f;
    float rotSpeed = 10;


    void OnMouseDown(){
        Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);
        pos = Input.mousePosition - pos;
        baseAngle = Mathf.Atan2(pos.y, pos.x) * Mathf.Rad2Deg;
        baseAngle -= Mathf.Atan2(transform.right.y, transform.right.x) *Mathf.Rad2Deg;
    }


    void OnMouseDrag(){
        //float rotY = Input.GetAxis("Vertical")*rotSpeed*Mathf.Deg2Rad;
        //gm.transform.Rotate(Vector3.right, rotY);
        Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);
        pos = Input.mousePosition - pos;
        float ang = Mathf.Atan2(pos.y, pos.x) *Mathf.Rad2Deg - baseAngle;
        transform.rotation = Quaternion.AngleAxis(ang, Vector3.forward);
    }
}

Solution

  • To get consistent physics state its best to move colliders within FixedUpdate - if you move colliders in a OnMouseXX stage of the pipeline (Consider consulting https://docs.unity3d.com/Manual/ExecutionOrder.html), you risk that the change might be missed next time FixedUpdate is called. I.e. your ball moves through the state of your scene based on how it was before you rotated the maze, and with some unfortunate timings its possible that collisions get missed. If you already tried with a tighter timestep, consider queueuing the OnMouseDrag change, like store the resulting rotation in a variable, and apply it in FixedUpdate, so it is applied just in case for next physics computation.

    you may also consider moving your ball at the same time as you rotate your maze, quickly moving a mesh collider against a much smaller rigidbody is a sure source of trouble. Can you move a camera instead ?