Saturday, January 16, 2010

So, I've gotten this far...

I have spent a good month now redoing everything in the project, but I've hit a bit of a wall. It's pretty much in a "good enough" state for a release, minus a few of the testbed examples I have yet to port. Oh, and all of the documentation. Ugh. Now with Box2D's wiki down, it makes it even more difficult.

There's that old adage "release early; release often", but I find it hard to jump on that bandwagon. Releases are very difficult to do in the first place for multiple platforms and multiple versions of Python. And then support them afterward? Forget it. Oh well. I might continue at a slow pace for a while and wrap some more things up for a release whenever I manage to get a bunch of free time again, or maybe not. There's a bunch more changes on the SVN since the last blog post if you have any interest.

Perhaps this will take over in the meantime?


  1. Thanks for the link to Pysics, but it's nowhere near finished. :-)

    I've kind of hit a wall with user data. I saw that you handle it quite nicely in pybox2d, though it looks a bit brittle.

    Keep up the good work.

  2. Mikael,

    No problem. I hope some day you can take over the box2d scene, allowing me to 'retire'. :)

    userData should be handled just fine as long as you do proper reference counting, really.

  3. The recent commit log for pybox2d looks great. In fact, I'll probably ditch Pysics and go back to using pyBox2D directly. Some feedback:

    1. Do you think it could be a good idea to add e.g. body.CreateRevoluteJoint(...) as a shortcut for body.CreateJoint(type=b2RevoluteJoint, ...)?

    2. On a related note, would you consider adding body.CreateCircleFixture(center, radius, ...) and body.CreatePolygonFixture(vertices, ...)?

    3. What's the purpose of the multi-shape call forms of body.CreateFixture(...)? Are they there to support the fixtures kwarg to the initializer? Wouldn't it be cleaner to have two alternate kwargs to the initializer, "fixture" (only one fixture) and "fixtures" (iterable of fixtures, initializer will iterate over them), and let CreateFixture create only one fixture at a time?

    Concerning user data, what happens if you e.g. set user data on a joint, then destroy one of the joint's bodies? As far as I can tell, Box2D will destroy the joint automatically. Does pyBox2D handle this case gracefully, or will it leak a Python reference?

  4. Corrections/edits to my previous comment:

    1. That should be world.CreateRevoluteJoint(...), not body.CreateRevoluteJoint(...).

    3. Having both "fixture" and "fixtures" as kwargs probably isn't a good idea, since "fixtures" is sufficient.

  5. Thanks, Mikael!

    These commits were by no means intended to stop your work. I hope to see some results from your experiments, also. :)

    1-2 are great ideas. The 'type=b2Joint' syntax is fairly ugly after all. I've been a bit more lax about sticking with the C++-style everywhere, and those calls would fit in well.

    I can see how the CreateFixture calls could be confusing. I'd be open for recommendations on making it clearer.

    The multi-shape calls are there just to allow you to create any number of shapes with the same b2FixtureDef properties (being friction, restitution, etc. -- these are no longer defined in the shape definitions). Or you can pass in fixture definitions along with shapes, and they'll be created independently of the kwargs.

    Re-reading your comment makes me think you're perhaps confused about CreateBody(fixtures=...) which accepts either a fixture, a list of fixtures, or a dictionary that allows one to set fixture-information (probably the strangest, but these arguments just get passed as kwargs to CreateFixture). Have I jumped beyond usefulness and made it too convoluted in this case?

    In regards to the ever-troublesome userData:
    If you destroy a joint/body without joints/fixture manually, the refcount on its userdata is actually decremented properly (see Box2D_userData.i). It can be a bit of a tricky situation. But you're right. In general, proper handling is still required on the user-side. Joints are destroyed automatically and b2DestructionListener.SayGoodbye is called for each of them. In this case, it is necessary to clear the userData manually if set.

    I don't see any easy way around it.

  6. I started writing Pysics because I wanted to be able to write less code when prototyping games. Now that pyBox2D supports a more concise syntax, there's much less motivation for Pysics. I'll try to start contributing to pyBox2D instead, starting with some feedback, though I hope to be able to write patches as well. Of course, it is up to you to decide what to accept.

    I was probably unclear in my feedback on CreateFixture. My gut feeling is that the current solution tries to do too many different things. From the name, CreateFixture should probably only create one fixture. There could be separate methods for the uther use cases, though I haven't personally felt a great demand for them.

    If you think that the shortcuts for adding joints and fixtures are a good idea, do you think it would also be a good idea to add the following shortcuts to b2World:


    Where world.CreateStaticBody(...) would be equivalent to world.CreateBody(type=b2_staticBody, ...).

  7. I see. Well, I'm happy you want to help!

    I like being able to create multiple shapes per body in a single call, as most of the time when there's more than one shape per body, you're likely to assign the same densities to those shapes (as in use a single fixture definition).

    But then I start thinking about it more, and... Well, maybe just breaking it up into CreateShape/CreateFixture would be best, with each taking a shape/fixture (or a list). CreateCircle/Polygon (as you recommended) could be there, but they wouldn't take shape definitions, just kwargs.

    This would further complicate utilizing the 'fixtures' kwarg in CreateBody() calls. Will have to think about that a bit more when I'm a bit less tired.

  8. Here's a suggestion:

    world.CreateBody(**bodyArgs, fixtures=(), shapes=(), **fixtureArgs)

    Where fixtures is a list of fixture defs (loop over them and call CreateFixture for each), shapes is a list of shapes, and fixtureArgs are fixture properties used only for the shapes. The shapes and fixtureArgs are passed to a new method:

    body.CreateFixtures(shapes, **fixtureArgs)

    This method creates zero or more fixtures, one for each shape in shapes, with identical fixture properties taken from fixtureArgs.

    Also, add new methods as suggested before:

    body.CreateCircleFixture(pos, radius, **fixtureArgs)
    body.CreatePolygonFixture(vertices, **fixtureArgs)

    And support only two ways of calling CreateFixture:


  9. When you said:
    body.CreateFixtures(shapes, **fixtureArgs)
    I believe you meant:
    body.CreateShape[s?](shapes, **fixtureArgs)

    I don't believe it's possible to pass two sets of kwargs to the same function as in CreateBody. Parsing the kwargs would be confusing (does friction apply to the body, or is it a fixture definition argument?). fixtureArgs as a kwarg would work, as in:
    world.CreateBody(**bodyArgs, fixtures=(), shapes=(), fixtureArgs=dict()) -- though that's not much better than the current solution. It might be our best option.

  10. I did mean CreateFixtures, but maybe CreateFixturesFromShapes or CreateFixturesForShapes is a better name. I don't think CreateShapes is a good name, since it doesn't describe what the method does.

    I realize that you can't pass two separate sets of kwargs in a single function call. I meant that the CreateBody method should pass on friction, restitution and so on to CreateFixturesFromShapes, but maybe this is ambiguous/confusing. I don't like the fixtureArgs=dict() solution a lot.

  11. Oh, and sorry if I didn't express myself very clear in my previous (or any) post. :-)

  12. Don't worry about it. I may be a native English speaker, but I'm by no means fluent or intelligible at all times. :)

    I see what you mean about CreateShape not being descriptive of the functionality. CreateFixture[s]FromShape[s] just seems so long and clunky.

    What about for CreateBody requiring a single b2FixtureDef (shapeFixture or something) that would apply to all shapes in the shapes kwarg? Something along the lines of:

    for each shape in shapes:
    It would require creating an actual definition before calling it, but the ugly dict() syntax would at least be gotten around. You could then also have separate fixtures passed in if necessary:
    world.CreateBody(*args, fixtures=(), shapes=(), shapeFixture=None, **bodyArgs)
    Where args would accept a single b2BodyDef if that's how you wanted to call it.

    CreateBody(**bodyArgs, fixtures=[b2FixtureDef(), b2FixtureDef()], shapes=[b2CircleShape(), b2PolygonShape()], shapeFixture=b2FixtureDef())

    The lack of a shapeFixture would then just use the default 0 density one and whatnot.

    Like that option any better?

  13. The shapeFixture argument to CreateBody is a reasonable solution.

    I still prefer CreateFixturesFromShapes. I agree that it's a bit long, but so are a few other Box2D method names. If you want a shorter name, I think CreateFixtures is the best option.

  14. I've been a bit busy, but I've finally mostly implemented these changes with r256. The main thing still lacking is Create(Circle/Polygon)Fixture for b2Body.

    Also, I made a little convenience function for myself allowing "conversion" of a b2JointDef to a dictionary -- jd.to_kwargs() -- do you think it should be publicly accessible? And if so, have any better suggestions for a name? I usually just leave function names as the first thing I think of, but it's so nice to have your feedback that I may as well get it right the first time. :)

    Please check it out when you get a chance and let me know what you think.

  15. If it's an implementation detail, you may want to prefix it with an underscore. Otherwise, I think it's fine.

    Sticking with the first thing you can come up with unless you find something that's obviously better is a productive approach. :-)

    The other changes sound good, I'll update my working copy and give them a try.

  16. I've updated to r258. The changes look good and seem to work well.

  17. Thanks for checking it out! :)

  18. I'm looking forward to hearing how pyBox2D is coming along.

  19. Me to, I'm starting to get a little worried that sirkne might have lost the motivation to go on.

  20. Hi guys,

    I'm afraid I haven't any progress since the last discussion I had with Mikael. All is not lost though, I still plan to eventually get around to updating to the most recent version of Box2D.

    There are a couple of interesting changes upstream, but unfortunately nothing groundbreaking.

    In any case, have any of you noticed any interesting new projects using pybox2d that might act as a bit of a morale booster? ;) It appears a bit stagnant from the quick search I just did. The Python forum on is the least active of any of the ports.

  21. But your gentle nudging made me start some work again, even if a bit slow.

    Updated to the latest Box2D svn, added loop/edge shapes (edges work, loops do not), reworked the framework system to be more OO-friendly (pyglet/pygame frameworks are derived from a base class now), and got pyglet basically working with the newest version 1.1.4 -- but it's got some major issues that need to be dealt with.

    Also added tiles, pinball, charactercollision, and bullet tests.

    Still needs a lot of work. Will eventually make a blog post detailing all the changes since the last version to encourage discussion.

    Right now, if you want to check it out, try:
    % svn checkout pybox2d-svn

  22. Good stuff, looking forward to the next release!

    Had a bit of a look around, don't think you have this one on the projects page yet: