- Home /
Bullet/Projectile Collision Question
In the image above, I've illustrated (very crudely in Paint) a problem I anticipate within Unity3D (or any game engine to be honest), regarding projectile/bullet collision.
If I have a bullet prefab game object instantiated at the tip of a gun, and it travels at 2 metres per second, and an enemy is standing 3 metres away, what would happen if my framespersecond was at 1fps?
If my game was running so slowly, would that collision happen? In my mind, the game is running at 1 frame per second. So in Frame 1 the bullet is just in front of the gun. Frame 2 the bullet is at 2metres, at frame 3 the bullet is at 4 metres, etc. So if the game was running at 1fps, and the bullet moving at 2 metres per second, then any enemies standing in odd numbered distance intervals (3,5,7,9 etc) would not trigger a collision?
Or does Unity's FixedUpdate method deal with physics in such a way, that it detects the collision, regardless of how many visual frames it renders per second? I think I remember reading somewhere, the fixedupdate happens regardless of your FPS, it occurs at fixed intervals in the game and is not affected by your FPS output?
I'm trying to understand how Unity deals with collisions, and how accurate/reliable this is for someone on a PC with low FPS. I'm sure no one would even play a game at 1fps, but I'm wondering what would happen if maybe they had an FPS spike too low for a brief moment, would they be cheated/robbed of a potential kill because of this 'bug' in my game?
Answer by rutter · Nov 04, 2015 at 08:19 AM
If my game was running so slowly, would that collision happen?
Nope! Not by default, anyway.
You've discovered the difference between discrete and continuous collision.
In discrete collision, the position of each object is checked once per frame, and it's entirely possible for fast-moving objects to go completely through colliders without ever "touching" them. This is the default behavior for most colliders in most engines, because it's very performant.
Continuous collision is good and bad. It's good because it's more accurate and will catch things like a fast-moving bullet that hits a wall. It's bad because it's more work for the computer, and that can bog down performance if you're not careful.
From the Unity manual, you can apply several collision detection models to a rigidbody:
Discrete: Use Discreet collision detection against all other colliders in the scene. Other colliders will use Discreet collision detection when testing for collision against it. Used for normal collisions (This is the default value).
Continuous: Use Discrete collision detection against dynamic colliders (with a rigidbody) and continuous collision detection against static MeshColliders (without a rigidbody). Rigidbodies set to Continuous Dynamic will use continuous collision detection when testing for collision against this rigidbody. Other rigidbodies will use Discreet Collision detection. Used for objects which the Continuous Dynamic detection needs to collide with. (This has a big impact on physics performance, leave it set to Discrete, if you don’t have issues with collisions of fast objects)
Continuous Dynamic: Use continuous collision detection against objects set to Continuous and Continuous Dynamic Collision. It will also use continuous collision detection against static MeshColliders (without a rigidbody). For all other colliders it uses discreet collision detection. Used for fast moving objects.
So, for example, you might set bullets to continuous dynamic and walls to continuous.
Side note: when it comes to bullets, lasers, and similarly instantaneous movement, it is sometimes simpler to simulate all of this behavior by raycasting.
Yup. Raycasting is the best conclusion for (normal) bullets. I wouldn't worry about performance here since your bullets calculation can be done in one frame like this and raycasting in Unity still is very performant. I think raycasting once per bullet is much cheaper than calculating every bullet in an update loop.
Of course it doesn't work for slow projectiles like rockets though. For things like this, using Fixed Update is the best direction.
It's also possible to combine the two methods: Have the bullet be a real GameObject with rigidbody, and move it forward continuously. At the same time, cast a short ray from the bullet's last position to it's current one; this ray will catch any collisions that happened between frames.
Wouldn't increasing the tail end of the collider mesh work too.
entirely possible for fast-moving objects to go completely through colliders without ever "touching" them
This even happens in Continuous Dynamic. I did a bunch of testing previously and discovered that only a $$anonymous$$esh Collider can detect collisions over ~10000units/sec (roughly). Of course that is pretty damn quick movement, so shouldn't be a problem.
But in instances where collisions are intermittent, watch the speed and test against a mesh collider to narrow down the problem.
The key phrase in the docs is
For all other colliders it uses discreet collision detection (Under Continuous Dynamic) which in my view defeats its purpose.
Thanks everyone for the answers! I have a good understanding of what happens now, and I have the keywords to go do more research.
Thanks :)
Answer by Sdvsdv · Mar 16, 2017 at 08:24 PM
Hello. I find so far this is bit more accurate than colliders for me atm. its bit late but it might help other ppl like me.
private RaycastHit myHit;
private Vector3[] oldFramesVector = new Vector3[5];
float testVelocity = 45f;
void Update() {
// simple motor
transform.Translate(Vector3.forward * testVelocity * Time.deltaTime);
//hit detection for fast moving objects
if (oldFramesVector[4] != Vector3.zero) {
for (int i = 0; i < oldFramesVector.Length; i++) {
if (Physics.Linecast(transform.position,
oldFramesVector[i], out myHit)) {
if (myHit.transform.gameObject.name !=
"object who created this one") {
print("did hit " + myHit.transform.name +
" coll check succed on : " + i + " frame ");
break;
}
}
}
}
if (oldFramesVector[0] != transform.position) {
for (int i = oldFramesVector.Length; i > 0 - 1; i--) {
if (i + 1 < oldFramesVector.Length) {
oldFramesVector[i + 1] = oldFramesVector[i];
}
if (i == 0) {
oldFramesVector[i] = transform.position;
}
}
}
}
Your answer
Follow this Question
Related Questions
get only one colliding body 3 Answers
How to get OnTriggerEnter effect without using isTriggered on Collider? 1 Answer
(Virtual reality) Collision fighting when tunneling - Any ideas? (gif included) 0 Answers
Gameobject not detecting collison from other Box Collider 2D [SOLVED?] 2 Answers
Makign an object collide continously 1 Answer