Hello again, today I bring you another lesson learnt.
When you choose Haxe for a project there are a wealth of 2D physics engines available, mostly ports of other popular engines, like Box2D. There are actually a few distinct ports to Haxe of various versions of B2D, but the most up-to-date and the one I’ve been using is Joshua Granick’s port of 2.1a. You can get it from Haxelib by opening a command prompt / terminal and running “haxelib install box2d”
In brief, it’s fantastic. Once you get a handle on how it works and where all the bits you want to use are it’s pretty simple, a far cry from the engine I initially experimented with – Physaxe – which was basically 20 pages of pure maths disguised as classes and functions! But there are some small issues I’ve run across while using it, and here comes the latest (and its solution, I wouldn’t leave you hanging!)
As we’ve discussed previously, my project runs in two threads, and Box2D is updated from the second, worker thread. I’m not sure if that’s contributed something to this problem, or if it’s just odd coincidence. Also since I’m building a tower defense game, I’m basically using B2D as a collision system, I’ve disabled all the collision response code that would usually make objects bounce/push out of each other and instead just report the start and end of collisions to the objects concerned (You can learn more about that in this previous post). In particular, of course, I have enemies and bullets, and the two must meet fairly regularly and be destroyed fairly regularly.
Herein lies the problem, no matter what I did I couldn’t get B2D to remove the physics body of an enemy after they’d been destroyed. The enemy sprite vanished, but the collision system still sees it, and the gun keeps firing at nothing. Initially I thought I must always be hitting the B2World.destroyBody method while the B2World was being updated (and thus, is locked), so I added some code to the destroyBody method to store any objects arriving during a lock in an array, and then remove them at the very start of B2World.step.
public function destroyBody(b:B2Body):Void { if (isLocked() == true) { this.bodiesToRemove.push(b); return; } etc... } public function step(dt:Float, velocityIterations:Int, positionIterations:Int):Void { foreach (b in this.bodiesToRemove) this.destroyBody(b); etc... }
This… well it didn’t do anything, to be honest. That surprised me a lot, and I started wondering if it wasn’t something more serious. Although, other bodies go fine — I can create a weapon, then destroy it, and the body goes too, but here it just doesn’t work at all.
I turned to Google, as we all do in times of need, knowing I’d already looked through a few pages of results on the subject and found nothing that useful. This time however, I got something to work. As usual, I wont pretend to know why this works and my original method didn’t, but let’s just go with it…
The chosen answer to this question is what worked — set a property in the body object and iterate over them seperate to the main step loop. In my implementation, I set the m_userData variable of B2Body (since I don’t use it for anything else) and just run a short function immediatly after B2World.step which I called B2World.destroyBodyQueue. If m_userData is true, we kill the object.
public function destroyBodyQueue() { var b:B2Body = m_bodyList; while (b != null) { if (b.getUserData()==true) { b = b.m_next; this.destroyBody(b.m_prev); continue; } b = b.m_next; } }
Easy!
– B