Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setting Body.Enabled = false inside of OnCollision causes crash. #43

Open
poohshoes opened this issue Sep 12, 2017 · 7 comments
Open

Setting Body.Enabled = false inside of OnCollision causes crash. #43

poohshoes opened this issue Sep 12, 2017 · 7 comments

Comments

@poohshoes
Copy link

poohshoes commented Sep 12, 2017

I'm running a 4 year old version of Farseer Physics so if this is not an issue with this version please just mark as resolved.

I'm getting a crash in Contact.Update if the FixtureA OnCollision handler has the code Body.Enabled = false then the FixtureB will be null causing a crash before the FixtureB handlers can be called.

Currently I'm going to just do if(FixtureB != null so it won't crash as I can't see any side effects but OnCollision would also have to check if you had more than 1 collision handler attached.

@nkast
Copy link

nkast commented Sep 12, 2017

You can't set Body.Enabled while the simulation is running. (box2D code here)
You can ignore the collision by returning false from OnCollision.
You can remove or disable the body later, after World.Step() is finished.

@poohshoes
Copy link
Author

poohshoes commented Sep 12, 2017

Right but it's not an unreasonable thing to want to do in response to a collision. So if you need to set a bool and then disable it after World.Step is finished why not have farseer take care of it automatically?

And wouldn't it be easier to have that code in Farseer than for everyone who uses it to have to write around it?

Also if you aren't supposed to set Body.Enabled while the simulation is running perhaps it should give you a warning? The whole point of a library is to not have to dig around in the code and figure out what the issue is.

@Genbox
Copy link
Owner

Genbox commented Sep 13, 2017

@nkast The engine is different from Box2D in that you can actually set Body.Enabled in the OnCollision handler. I'm pretty sure I fixed this bug years ago and made a test for this particular scenario. See https://github.com/VelcroPhysics/VelcroPhysics/blob/master/Samples/Testbed/Tests/LockTest.cs

@poohshoes The fix you made is pretty much what solves it. There are multiple gotchas in event handling in C#, which is why I'm probably moving towards #8 with Velcro rather than having the engine internals change in the middle of a step. As for having the engine remember Body.Enabled changes during a step, that would considerably slow down the engine and take up a lot of memory - the Enabled property is just one out of many things that can change.

@nkast
Copy link

nkast commented Sep 14, 2017

It's hard to find the exact fix, maybe I will try to find it tomorrow, however there are a couple of issues that I think that are not addressed.

The other fixture does not get notified about the contact. BeginContact too (or maybe BeginContact gets an empty Contact). Small issue really but might be helpful, Ex. a bullet (A) disables itself and the ship (B) gets ++Hits.

A body (B) receives OnSeperation before OnCollusion. When a body is disabled it will remove/destroy all of it's contacts. This behavior puts your game object on an invalid state.

The index/Iteration of contacts is not corrected. So when a body or two is disabled, Collide()/SolveToi(), etc might skip one or two contacts. That's somehow similar to #41.

@nkast
Copy link

nkast commented Sep 14, 2017

@Genbox
Copy link
Owner

Genbox commented Sep 14, 2017

You are completely right, which is why it is a bad idea to change the state of the engine in the middle of a step. it is possible to do because it works for most games.

@nkast
Copy link

nkast commented Sep 14, 2017

going back to the idea of automatic disabling,
I was thinking of a World.WaitHandler, so you can write something like fixtureB.Body.World.WaitHandle.ContinueWith( (w)=>fixtureB.Enabled = false )
or provide Async methods like EnableAsync() and DisableAsync().

I am not sure if I can implement those without generating garbage. However it would be nice for quick prototyping and rare events.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants