How to prevent colliders from passing through each other?
Asked Answered
S

8

21

I am having trouble keeping game objects inside of a contained space. When they reach the edge, there is some momentary push back but then they will go right through the wall.

I am using a Box Collider on the player, and a Mesh Collider for the level's wall. I am having issues with both a Player Character (a space ship) that the movement is controlled by the player. And with projectiles, which are fire and forget moving at a constant speed.

This is my movement code for my player. It is being run in the FixedUpdate() function.

//Movement
    haxis = Input.GetAxis("Horizontal") * speed;
    vaxis = Input.GetAxis("Vertical") * speed;

    moveVector.x = haxis;
    moveVector.z = vaxis;

    if(moveVector.magnitude > 1)
    {
        moveVector.Normalize();
    }

    rigidbody.MovePosition(transform.position + moveVector * speed);

With the bullets, they are given a velocity and the engine calculates their moviements. They are using Box Collider and it is set as a Trigger so they don't have physics. But I use OnTriggerEnter to destroy them.

//Projectiles without physics collisiions
function OnTriggerEnter (other : Collider) {
    Destroy(gameObject);
}

Some, but not all of the bullets will be destroyed when hitting the mesh collider wall. The player will sometimes hit it and stop, but can usually push through it. How can I make the collisions with the mesh collider work every time?

Spokeswoman answered 13/3, 2012 at 16:39 Comment(5)
I've even created a simpler mesh collider from the wall's mesh and it didn't help.Spokeswoman
How wide are the mesh colliders you use for the screen and how fast can bullets and the player travel? If bullets or the player can move a distance longer than the collider in one frame, there you have it. Also, I'd avoid moving the rigidbody manually. That will only confuse the physics engine and prevent it from optimizing. Move the gameobject's transform instead.Memento
@Memento The colliders are about 8 character and 20 bullets wide. They aren't moving completely through the collider in a single frame. If you move the transform Unity will ignore all physics, rigidbody.MovePosition takes physics into account.Spokeswoman
You're right, I got the relationship the other way around. Do you take deltaTime into account when calculating speed? Does your character bump repeatedly against the wall until it goes through? What does your character do OnCollision?Memento
@Memento The MovePosition() call is called as a result of FixedUpdate() so deltaTime shouldn't be necessary. I haven't been able to find a real pattern of behavior for the collision working / failing.Spokeswoman
B
14

Collision with fast-moving objects is always a problem. A good way to ensure that you detect all collision is to use Raycasting instead of relying on the physics simulation. This works well for bullets or small objects, but will not produce good results for large objects. http://unity3d.com/support/documentation/ScriptReference/Physics.Raycast.html

Pseudo-codeish (I don't have code-completion here and a poor memory):

void FixedUpdate()
{
    Vector3 direction = new Vector3(transform.position - lastPosition);
    Ray ray = new Ray(lastPosition, direction);
    RaycastHit hit;
    if (Physics.Raycast(ray, hit, direction.magnitude))
    {
        // Do something if hit
    }

    this.lastPosition = transform.position;
}
Birchfield answered 14/3, 2012 at 19:20 Comment(8)
Submitted an edit, but it should be Ray(lastPosition, direction) otherwise you may be inside the mesh collider and the Ray won't hit from inside of a collider. Looks like a good approach, I'll check it out.Spokeswoman
The only problem I can think of here is that we could be looking at a lot of moving elements and I suspect doing Raycast on all of them will be heavier on performance than using the compound colliders. If I get a chance to test this out I'll let you know what the performance difference is.Spokeswoman
collider.Raycast checks against a single collider - I edited to Physics.Raycast. Regarding performance, I don't think it will have a big hit, but it needs testing. You cam use the layerMask parameter of Physics.Raycast to ensure it only gets tested against what you want it to (see the docs).Birchfield
Raycasting is the way to go, because a lot of theoretical stuff that i can't fit in a comment, but this is the answer.Tournedos
Thanks @Fabio'Petrucio'Stange this answers the question very well. Though further along with my project, I need the physics info from a collision (some complex obstacles that will actually hit/damage the player based on the collision data). For this the compound colliders are doing the job quite well, I don't expect the Raycast to give me as much data.Spokeswoman
You sir, are my new God! THANK YOU!Scrumptious
You can use Rigidbody.maxDepenetrationVelocity for big objects that moving fast.Duncan
@Duncan might be worth writing up a new answer. This is a 5 year old question, so an updated answer would be helpful.Spokeswoman
B
14

I have a pinball prototype that also gave me much trouble in the same areas. These are all the steps I've taken to almost (but not yet entirely) solve these problems:

For fast moving objects:

  • Set the rigidbody's Interpolate to 'Interpolate' (this does not affect the actual physics simulation, but updates the rendering of the object properly - use this only on important objects from a rendering point of view, like the player, or a pinball, but not for projectiles)

  • Set Collision Detection to Continuous Dynamic

  • Attach the script DontGoThroughThings (https://www.auto.tuwien.ac.at/wordpress/?p=260) to your object. This script cleverly uses the Raycasting solution I posted in my other answer to pull back offending objects to before the collision points.

In Edit -> Project Settings -> Physics:

  • Set Min Penetration for Penalty to a very low value. I've set mine to 0.001

  • Set Solver Iteration Count to a higher value. I've set mine to 50, but you can probably do ok with much less.

All that is going to have a penalty in performace, but that's unavoidable. The defaults values are soft on performance but are not really intented for proper simulation of small and fast-moving objects.

Birchfield answered 15/3, 2012 at 3:2 Comment(4)
Hi, I am not able to find the DontGoThroughtThings scripte Can you provide it. may be user has remove from above link.Sejant
I found link for the DontGoThroughtThings Scripte code.google.com/p/lava-in-antarctica/source/browse/trunk/…Sejant
Am using Unity 5 and after reading this, though I couldn't find 'Min Penetration for Penalty' but I tried changing the 'default contact offset' to 1. Now, fast moving objects are getting detected :)Gumboil
Collision Detection: Dynamic worked for me. Using Unity 2017.Odele
B
6

How about set the Collision Detection of rigidbody to Continuous or Continuous Dynamic?

http://unity3d.com/support/documentation/Components/class-Rigidbody.html

Boeke answered 14/3, 2012 at 7:50 Comment(1)
I'm pretty sure that mesh colliders can't be set to Continuous if they are more than a certain number of tris. And even so, setting Continuous / Continuous Dynamic on the characters / bullets and even the meshes didn't work.Spokeswoman
S
1

So I haven't been able to get the Mesh Colliders to work. I created a composite collider using simple box colliders and it worked exactly as expected.

Other tests with simple Mesh Colliders have come out the same.

It looks like the best answer is to build a composite collider out of simple box/sphere colliders.

For my specific case I wrote a Wizard that creates a Pipe shaped compound collider.

@script AddComponentMenu("Colliders/Pipe Collider");
class WizardCreatePipeCollider extends ScriptableWizard
{
    public var outterRadius : float = 200;
    public var innerRadius : float = 190;
    public var sections : int = 12;
    public var height : float = 20;

    @MenuItem("GameObject/Colliders/Create Pipe Collider")
    static function CreateWizard()
    {
        ScriptableWizard.DisplayWizard.<WizardCreatePipeCollider>("Create Pipe Collider");
    }

    public function OnWizardUpdate() {
        helpString = "Creates a Pipe Collider";
    }

    public function OnWizardCreate() {
        var theta : float = 360f / sections;
        var width : float = outterRadius - innerRadius;

        var sectionLength : float = 2 * outterRadius * Mathf.Sin((theta / 2) * Mathf.Deg2Rad);

        var container : GameObject = new GameObject("Pipe Collider");
        var section : GameObject;
        var sectionCollider : GameObject;
        var boxCollider : BoxCollider;

        for(var i = 0; i < sections; i++)
        {
            section = new GameObject("Section " + (i + 1));

            sectionCollider = new GameObject("SectionCollider " + (i + 1));
            section.transform.parent = container.transform;
            sectionCollider.transform.parent = section.transform;

            section.transform.localPosition = Vector3.zero;
            section.transform.localRotation.eulerAngles.y = i * theta;

            boxCollider = sectionCollider.AddComponent.<BoxCollider>();
            boxCollider.center = Vector3.zero;
            boxCollider.size = new Vector3(width, height, sectionLength);

            sectionCollider.transform.localPosition = new Vector3(innerRadius + (width / 2), 0, 0);
        }
    }
}
Spokeswoman answered 14/3, 2012 at 19:16 Comment(0)
S
1
  • Edit ---> Project Settings ---> Time ... decrease "Fixed Timestep" value .. This will solve the problem but it can affect performance negatively.

  • Another solution is could be calculate the coordinates (for example, you have a ball and wall. Ball will hit to wall. So calculate coordinates of wall and set hitting process according these cordinates )

Sty answered 29/5, 2014 at 11:7 Comment(0)
D
1

1.) Never use MESH COLLIDER. Use combination of box and capsule collider.

2.) Check constraints in RigidBody. If you tick Freeze Position X than it will pass through the object on the X axis. (Same for y axis).

Disaccord answered 10/5, 2015 at 12:26 Comment(2)
why not use mesh colliders?Byrom
Mesh collider are hard to process, more mesh means more usage of processor, this questions is old so, at that time it was harder for mesh to process on cheap phones, specially android phones.Disaccord
J
1

Old Question but maybe it helps someone.

Go to Project settings > Time and Try dividing the fixed timestep and maximum allowed timestep by two or by four.

I had the problem that my player was able to squeeze through openings smaller than the players collider and that solved it. It also helps with stopping fast moving objects.

Judicious answered 14/8, 2016 at 12:7 Comment(0)
L
-1

Try setting the models to environment and static. That fix my issue.

Lynettalynette answered 25/1, 2020 at 20:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.