- Home /
any way to get a pre-solve collision callback?
I have a AAA console gamedev background, so I'm used to having source access & I am finding myself immensely frustrated by what I can only describe as a missing feature in Unity's rigidbody collision behaviour.
Physics engines typically work in several passes per update, broadly speaking:
1) update all objects in the simulation based on forces / accelerations / impulses acting on them this step
2) check for collisions
3) resolve collisions
AFAIK all physics engines I have used have the concept of a 'pre-solve' collision callback/event - (i.e. after or during step 2 but before step 3). I assume that physx does, but couldn't find the SDK documentation online to check.
For example: Bullet - http://www.bulletphysics.org/mediawiki-1.5.8/index.php?title=Collision_Callbacks_and_Triggers#Contact_Callbacks
Box2d - http://www.box2d.org/manual.html#_Toc258082975
Having this event makes it very easy to detect all collisions but choose contextually on a collision by collision basis to ask the engine to ignore them (i.e. not to physically resolve them).
The important factor being that there are many gameplay reasons why for any given pair of objects the decision to ignore the contact, or not, might be based on information only available at the point that the contact is generated - i.e. immediately before the collision is resolved.
Assuming there isn't a unity event for this (which I am pretty confident it isn't as I have found no answers when I searched before writing this) then what is the "usual" workaround?
I'm anticipating some archaic combination of game objects having triggers that contain rigid bodies with colliders and additional logic, so would be very pleased if someone has an elegant solution :)
Regards, Alex
That's actually a very good question, although I fear the best you can do is to make Raycasts for the objects where this might matter.
Could you write down a few of that "gameplay reasons", so we can get a better view of what you mean and what the appropriate Unity solution could be?
there is the, to me, exceptionally confusing
Documentation/ScriptReference/Physics.IgnoreCollision.html
call, which may be relevant. you can see a few answers about it on here
sorry for posting the same text in 2 places (see my comment on the answer below), but it seemed easier than typing approx. the same thing again :)
By 'ignoring' the collision I mean preventing the physics solver from resolving the collision - i.e. the engine detects the collision with full physics info generated, but then allows me to ask it to behave as if the collision didn't happen which would let the objects pass through each other.
Obviously it is possible to ignore collisions using layers or Physics.IgnoreCollision, but these approaches are limited in that (as far as I can tell) they only allow either:
no collisions, or
all collisions
between any two specific objects.
The behaviour I am trying to achieve requires me to know when physically simulated objects have collided, look at the SPECIFIC circumstances of that collision (e.g. relative velocities, relative positions, the specific objects involved and their state (time since spawning for example) etc.) and then if, and only if, the circumstances meet specific conditions ask the physics simulation to ignore the collision.
The classic example of this sort of behaviour is the platform that you can jump up through, but not fall down through in a platform game - what I'm trying to do is similar but relies on more than just the objects' relative positions etc.
Answer by Fattie · Sep 09, 2013 at 10:48 AM
Just to be clear Alex ... are you aware that it's "not too late" to call Physics.IgnoreCollision in OnCollision???
Please launch the little project attached and run it.
Caveat - I've never really understood Physics.IgnoreCollision (perhaps because it's totally undocumented, "when" it happens) but it seems to work in cases like that. This may or may not help you in some way.
Nope, I was definitely not aware of that - as you say, that behaviour isn't documented.
That is almost the behaviour I was looking for, I still need to turn collisions between those objects back on again at some point which might be a pain in the bum...
Awesome, thanks. Will check out the project. $$anonymous$$uch appreciated.
You know I really think this is the solution or factoid you were after, $$anonymous$$.
(This is "Common Situation #13" on this list. Someone, perhaps a seasoned-but-new-to-unity programmer, asks a question that has a relatively simple answer, but everyone assumes "oh, it can't just be that the OP wants to know X, what the hell else could it be." ... heh)
{The very most common Common Situation on this list is that a beginner asks how to do a timer (Invoke) but thinks you need to use yield ;-) }
Anyway yeah.
(To turn it on again, just bool the fricker - notice the second form of the call with another argument. Of course, like any game development in that situation, you have messy considerations like "when do I turn it on again" "What is the philosophical nature of when a new footfall begins" but that's no different at all in bullett, $$anonymous$$acPaint or whatever, you know - it will depend strictly on your situation of course and is often trivial.)
"I come from AAA gamedev background..." dude what's this b/s man? :) Your headhunter's not on here ;-)
I always tell people I come form a "20 year" or "Blue label" background. As in $$anonymous$$acallan or Johnnie Walker
As far as I can see in the docs, the only way to re-enable the collisions is to deactivate and then reactivate one of the objects (possibly both).
That sounds a bit nuts. Any idea how I might just deliberately un-ignore the collision?
dude I hate that call but I think you just ,false at the end. Look at the second version of the call on the doco page. it's a state and you flip it...
Answer by Ultroman · Nov 29, 2017 at 10:06 PM
This is not currently possible in Unity.
There are workarounds, but none let you handle the cases where an object collides with 2+ things in the same physics step, and needs to be affected in a custom way e.g. be stopped or moved or bounced using custom code.
/
If you save the velocity/angularVelocity/etc. from last FixedUpdate, you will have the data for the object before any of the collisions happened. OnCollisionEnter(2D) is properly called for both collisions (yay), BUT you don't have much info about what happened. You have the circumstances, like the collision normal, the separation/distance, contact point(s), but you don't have data for each object, like position and velocity/direction before and after the collision, or how far into the physics step the collision occurred.
/
Even if you did, you cannot simply roll back the object to the collision point, and do some custom bounce-code for each collision, because when you change the behaviour/result of the first collision/OnCollisionEnter(2D), then the data for the second collision/OnCollisionEnter(2D) call is made invalid.
/
To handle 2+ collisions in a single physics step, you only have two choices, really:
React to the first OnCollisionEnter(2D) call for each physics step, and do any further collision detection for this physics step manually...but you may have seen the problem with this...any other object in the scene will not have been rolled back to its previous position. You will have to roll back every object, and manually do incremental physics/collision detection updates. That's a LOT of code and a LOT of CPU cycles.
Turn down the Fixed Time Step variable, even though that only makes the problem less frequent.
That gets us down to 0 possibilities to fix this problem.
Answer by Eric5h5 · Sep 09, 2013 at 12:58 AM
The workaround isn't that convoluted: always store the velocity/angular velocity/position from the previous physics frame, and after a collision, if it's not desired, just restore the velocity etc. so it continues on as if nothing had happened.
This doesn't prevent OnCollision/OnTrigger events from happening which then requires at least some additional infrastructure.
Well, yeah, it doesn't prevent those events from happening, that's why it's a workaround. It does, however, have the effect of ignoring collisions on-demand, which is what you're asking for.
I'm not the OP :). I was just adding to your answer what I thought is also worth considering.
This 'workaround' is barely even a workaround - it just puts the object back where it was on the frame before the collision which is not even vaguely the same thing that I am asking about.
By 'ignoring' the collision I mean preventing the physics solver from resolving the collision - i.e. the engine detects the collision with full physics info generated, but then allows me to ask it to behave as if the collision didn't happen which would let the objects pass through each other.
Obviously it is possible to ignore collisions using layers or Physics.IgnoreCollision, but these approaches are limited in that (as far as I can tell) they only allow either:
no collisions, or
all collisions
between any two specific objects.
The behaviour I am trying to achieve requires me to know when physically simulated objects have collided, look at the SPECIFIC circumstances of that collision (e.g. relative velocities, relative positions, the specific objects involved and their state (time since spawning for example) etc.) and then if, and only if, the circumstances meet specific conditions ask the physics simulation to ignore the collision.
Your answer
Follow this Question
Related Questions
How do I get the GameObject that is inside my Collision 1 Answer
OnCollisionExit2D workaround? 0 Answers
On Collision sound clip change 1 Answer
Destroy OTHER objects on Collision Unity 3 Answers
OnColliderEnter2D not working 2 Answers