- Home /
Inconsistent Collision Detection
Greetings,
I've encountered a simple problem with collision detection. I have a target (a spaceship in this case) and a bullet. Both are rigidbodies and both have primitive colliders. The bullet is given an initial push, accelerating it to a moderately high velocity towards the target. Sometimes the bullet hits the target and physics appropriately take place. Sometimes there is no collision at all and the bullet continues on it's merry way.
The real problem is that this happens even if both objects are set to be any combination of Continuous or Continuous Dynamic collision detection. The problem is worst under Discrete collision detection, but the rate of failure is still completely unacceptable even if both bullet and target are set to use Continuous Dynamic collision detection.
I've tried adding multiple layers of primitive colliders to the target, which helps "catch" the bullets, but that still looks terrible when bullets often impact inside the model rather than on/near the surface (or even worse, impact the opposite side as they exit). I've tried using mesh colliders, with even worse results (and far worse performance). The velocity involved really isn't that high compared to the size of the target, so this is a substantial obstacle from a design standpoint.
The question is: what else can I do to improve the consistency of my collision detection?
Answer by kromenak · Jun 18, 2011 at 01:08 AM
Also check that your Fixed Timestep (under Project Settings > Time) is set to a pretty small value. We were using 0.03 for awhile, but ran into a lot of physics issues. Setting this to like 0.01 made physics behave better for the most part, at the cost of some performance.
That's it! I was thinking of what I did when I had this problem a while back, and this was what solved it in the end. You don't want to use this for mobile devices though ;)
Haha, yeah, about that. While we are aware that using a 0.01 timestep is not too great an idea on mobile devices, we also feel like our game is really buggy without that precision.
Our game is running pretty good right now on mobile devices with this setting. A further optimization you can make is to set the $$anonymous$$aximum Allowed Timestep to something smaller, like 0.05. This will only allow physics updates to happen so many times in a single frame. This allowed us to tell the physics to be precise, but to not take up too much time.
Thank you very much, $$anonymous$$romenak; reducing the fixed timestep solved the problem immediately. Have to readjust a bunch of values now, since almost everything was being done with physics forces via FixedUpdate, but it works even after readjusting the numbers for a similar feel.
Just a heads up in that case, $$anonymous$$romenak, if you get a sudden performance hitch every few $$anonymous$$utes that draws on for several seconds it's because the garbage collector and FixedUpdate don't play well together. An explanation can be found here half-way the page: http://forum.unity3d.com/threads/18213-Zombieville-USA-performance-hitches/page3 , basically the garbage collector slows things down for a bit, and FixedUpdate slows things down a LOT trying to catch up on what it missed during the garbage collection.
So be warned ^.^
Hey, good to know - thanks for the link! $$anonymous$$y question then: does setting the $$anonymous$$aximum Allowed Timestep alleviate this issue?
For example, if the garbage collector runs and the physics decides it needs to now run 30 iterations or something to catch up, this could do$$anonymous$$o into a big performance issue. But, if you set the Fixed Timestep to 0.01 and $$anonymous$$aximum Timestep to 0.05, doesn't that mean that your physics updates will do a maximum of 5 iterations to catch up?
So far, the result of limiting the number of physics iterations in this way has been that the physics sometimes seem to "slow down" a bit if the phone is chugging. While still undesirable, it is better than collision errors and interpenetration.
Answer by Mikla · Feb 24, 2014 at 04:13 PM
I approached this in a mixed way since I needed bullet drop. In the script attached to the bullet, I checked at start and in every frame what the distance was to the target using raycast. If the distance was less than the bullet velocity deltaTime 2 (2 is just to make sure, but can be varied), then I hit the raycast collider gameobject. Not perfect, but better than just raycast or monkeying with Physic settings. Code:
using UnityEngine;
public class Bullet : MonoBehaviour
{
public float BulletLife = 5;
private float _currentLife = 0;
private RaycastHit _hitInfo;
private const float CHECK_MULTIPLIER = 2f;
// Use this for initialization
private void Start()
{
if (IsCloseToTarget()) RegisterHit();
}
private void FixedUpdate()
{
_currentLife += Time.deltaTime;
if (_currentLife > BulletLife) Destroy(this.gameObject);
if (IsCloseToTarget()) RegisterHit();
}
private bool IsCloseToTarget()
{
Physics.Raycast(transform.position, this.gameObject.rigidbody.velocity.normalized, out _hitInfo);
if (_hitInfo.collider != null && _hitInfo.collider.gameObject != null)
{
//Debug.Log("Bullet Distance:" + _hitInfo.collider.gameObject.name + "|" + _hitInfo.distance.ToString() + "|" +
// gameObject.rigidbody.velocity.ToString() + "|" + Time.deltaTime.ToString());
var distChk = gameObject.rigidbody.velocity.magnitude * Time.deltaTime * CHECK_MULTIPLIER;
return _hitInfo.distance < distChk;
}
return false;
}
private void RegisterHit()
{
Debug.Log("Bullet Hit " + _hitInfo.collider.gameObject.name);
Destroy(this.gameObject);
}
}
Answer by Joshua · Jun 18, 2011 at 12:15 AM
The problem you're having is that movement in games isn't continuous. You're teleporting the bullet forward frame by frame, making it look like it's moving. If it's moving to fast though, it might go past an object without collision taking place.
There are several ways to prevent this. the easiest way is using this script, DontGoThroughThings.js, which basically checks where am I now, where will I be next frame, and will I have skipped over something then?
As the OP wrote, that's what Discreet Detection does -- check at a few spots (the spots it jumps to each frame.) Speed is meters/sec, so if the bullet moves at 50m/s, it goes 1m/physicsFrame, so should never miss a standing still target 2 meters wide, with normal (Discret) collision. The Continuous setting is supposed to do a a $$anonymous$$i-raycast each frame. It's exactly for this sort of problem, and the OP seems to be using it exactly the correct way, so odd it doesn't work.
In my experience the 'continuous' setting on collision detection is a lot less reliable then doing the raycasting yourself.
Your answer
Follow this Question
Related Questions
Why there is no Collider.IsTouching(...) ? 2 Answers
Strange issue with collider 1 Answer
How to reliably break contact/collision? 0 Answers
Detect if a non-trigger collider is inside another collider 1 Answer
How to detect collision between 2 objects while checking are they the ones that need to collide? 1 Answer