2D Physics XBAP Source

You can get the source for my XBAP 2D Physics demo here.  It’s not as neat and tidy as I’d like but it’s still pretty good.  Right now it’s all in one project; the actual ‘DynamicsEngine’ is just in a subfolder.  I’ll shamefully admit that when I wrote it I had no idea XBAPs could deploy external assemblies too! (something I’ve since been exploiting).

The code is pretty much a straight port from Flade, an excellent Flash/Actionscript engine by Alec Cove.  Just be wary of the couple of small hacks I’ve added for particle/particle collision (it works, but I’m not certain my calcs are good).  Also, you might notice a wheel “on its own” doesn’t seem to accelerate when it rolls down a slope — but it’s on my todo list!

13 Comments

  1. Hey Chris, I’m calling AddForce and setting values to the Force property on CBody instances, but nothing is happening. However I’m able to set X, Y, and Angle by applying a matrix, and also change the Velocity without problem. Any ideas why changing the force is failing?

    Reply

  2. Hey Chris, a bit more information — I’m calling this in response to a mouse move. I’m trying to get a CBody element to follow the mouse. Any tips or suggestions are appreciated.

    Reply

  3. Thanks for the quick response. I think the problem might be that I’m applying the force in the mouse move, and the ApplyForceAndTorque handler is invalidating/overwriting any change I make there. I’ve changed the ApplyForceAndTorque handler for the paddle to remove the effects of gravity, and instead I’m applying a different force vector (a field which I update in the mouse move). Right now the results are pretty “loose,” like a paddle on a long elastic string, but I’m betting that cranking up the force (about to test that now) will get the results I want.

    Reply

  4. Got client coordinates….
    Bodies bodies = GetBodies();

    Point mousePosition = e.GetPosition(world);
    double actualWorldHeight = world.ActualHeight;
    mousePosition.X -= world.ActualWidth / 2;
    mousePosition.Y -= actualWorldHeight / 2;

    double worldScaling = bodies.WorldHeight / actualWorldHeight;
    double mouseX = worldScaling * mousePosition.X;
    double mouseY = worldScaling * mousePosition.Y;

    The non-intuitive part was the y-scaling appears to be needed for unravelling the x position. This appears to be related to the ScaleTransform code inside World.xaml.cs.

    Reply

  5. OK, achieved relatively decent results with this code (setting force just made it way too crazy — turns out velocity works much better):

    DateTime time = DateTime.Now;

    float secondsSinceLastUpdate = _LastTimeMoved.HasValue ? (float)(time – _LastTimeMoved.Value).TotalSeconds : 0;

    if (secondsSinceLastUpdate > 0)
    {
    double velocityX = (mouseX – paddleX) / (10 * secondsSinceLastUpdate);
    double velocityY = (mouseY – paddleY) / (10 * secondsSinceLastUpdate);
    bodies.PlayerPaddle.Velocity = new Vector3D(velocityX, velocityY, 0);
    }

    _LastTimeMoved = time;

    Reply

  6. BTW, the “10 * ” multiplier on secondsSinceLastUpdate (in the code above) keeps values from getting way too high.

    Hey Chris, if you would prefer I send you email instead of polluting your blog with comments, you can reach me at markm att devexpress (dott comm).

    One last issue — my paddle won’t move until another body collides with it. Working on that now…

    Reply

  7. Hey Mark – Go right ahead and “pollute” away :o) This is all good stuff that could help someone else, so this is a great place for it.

    One question though — is this definitely the 2D/XBAP stuff (based on Flade) you’re working with, or my original 2d/WPF one (based on Newton Dynamics engine)? Certainly although the Newton one isn’t a managed assembly (and thus can’t be deployed with a partial-trust XBAP) it’s been around a long time and seems pretty robust and reliable.

    Reply

  8. It’s the original 2d/WPF one based on the Newton Dynamics engine. It’s pretty cool stuff. I was really impressed with your technique of using the DataTemplate (took me a while to figure out how you were rendering). I figured out the paddle won’t move problem (set AutoFreeze to false — seems to work the way I want it). Tomorrow I’ll try creating custom controls that I can register and drop down in Blend so I can set up the playing surface interactively at design time.

    Reply

  9. Mark – Great to hear it’s working well :o) The binding technique really is cool, but there’s one “problem” I’ve found with it; when objects are first added to the collection and rendered, they’re not databound immediately. The binding doesn’t actually kick in until a frame later. This makes the object ‘flicker’ at the canvas origin briefly before appearing in its proper place. It’d be cool if one of the nice Microsoft guys who read this could offer an explanation/solution (maybe it’s possible for us to delay adding to the collection until databinding time — a bit like ASP.NET’s [On]DataBinding event).

    For another project I instead added the objects directly to a canvas. This works great, but it’s *very* important to make sure you don’t clear and re-add the collection every frame (just update the objects you’ve already added to the canvas; add/remove some dynamically if necessary). If you re-add, performance suffers greatly.

    Reply

  10. Update: To support declarative instantiation of CBody descendants in Xaml (which will allow design time placement and property setting inside Blend — I’m really looking forward to being able to set Mass and Velocity in the Blend property grid at design-time), I’m making small architectural changes to the NewtonDynamics project and to classes that descend from CBody. The biggest change stems from having CBody descend from UIElement.

    I haven’t investigated this yet, but I strongly suspect that CBody neatly wraps a C class called Body from the physics engine you started with. Changing this wrapper class makes it less of a true port (which is often desireable), however I have taken care to only add new members, and not change any existing signatures.

    I think you’ll want to integrate these changes into your code base. We might also want to set up source control for this so everyone interested in maintaining the source can do so safely.

    Speaking of which, what’s the distribution model on the NewtonDynamics assembly and the primitive CBody descendants inside WPFPhysics1? Is this all open source? That’s been my assumption all along, but I probably blazed past any explanatory text that would have clued me in.

    Reply

Leave a comment