Question

I am trying to implement phsyics with the as3 box2d port. I currently have a b2body for each of some certain sprites in my game and I am able to update the sprite's positions correctly from the positions of the bodies. This is shown in the picture below (debugDraw shows the positions of the b2bodies overlaid on their corresponding spirtes. The green rectangles are the walls and floor)

enter image description here

However, I also want to have the sprite's rotations reflect the rotations of the b2bodies. But, after I rotate the sprites, the offset I use to center them correctly with the b2body positions is no longer accurate.

enter image description here

My code for updating the sprites positions is as follows:

private function Update(update_event:TimerEvent):void
            {
                //step physics simulation forward 
                world.Step(0.025,10,10);



                //update all objects in world
                for each (var obj:HouseItemPhysicsObject in physicsObjects)
                {
                    //update object's position from gravity if it is not being dragged
                    if(!obj.isHeld)
                    {
                        /*adjust rotation of sprite along with body -> yourMC.rotation = (yourMCbody.GetAngle() * 180 / Math.PI) % 360; */
                        obj.object.rotation = (obj.pBody.GetAngle() * 180/Math.PI) % 360;   

                        if(obj.object.rotation >=5)
                        // set object's x position but adjust for offset between the cooridinate systems
                        obj.x = (obj.pBody.GetPosition().x* scaleFactor)-(obj.object.width/2); 
                        //keep in horizontal bounds of screen
                        if(obj.x > GeneralConstants.GAME_WIDTH)
                        {
                            obj.x =GeneralConstants.GAME_WIDTH;
                        }
                        else if(obj.x < 0)
                        {
                            obj.x = 0;
                        }

                        // set object's x position but adjust for offset between the cooridinate systems in Flash and box2d
                        obj.y = (obj.pBody.GetPosition().y * scaleFactor)-(obj.object.height/2);

                        //keep in vertical bounds of the screen
                        if(obj.y > GeneralConstants.GAME_HEIGHT)
                        {
                            obj.y =GeneralConstants.GAME_HEIGHT;
                        }
                        else if(obj.x < 0)
                        {
                            obj.x = 0;
                        }



                        /*Draw shapes to see for debug*/
                        //obj.DrawDebug();
                        //trace("OBJECT's X is :" + obj.x + " Y is :" +obj.y);
                        trace("Object's rotation is:" + obj.object.rotation);
                    }



                }

                //move debug draw to front of display list
                m_sprite.parent.setChildIndex(m_sprite, m_sprite.parent.numChildren - 5);
                world.DrawDebugData();
            }

How can I find the correct X and Y offset between the coordinate systems (Flash and Box2d) after rotating the sprite according to the b2Body? Thanks for the help.

EDIT: For clarity, the object is a class that extends the Sprite class, and it's data member _object is a an instance of MovieClip.

Was it helpful?

Solution

Box2D objects have their anchor point in the center by default, while for Flash objects, it's in the top left. To position them properly, you need to take this into account

Easy way

Wrap your Bitmaps/whatever in a Sprite and center them:

// create the image, center it, and add it to a holder Sprite
var image:Bitmap    = new Bitmap( objGraphicsBitmapData );
image.x             = -image.width * 0.5;
image.y             = -image.height * 0.5;
var holder:Sprite   = new Sprite;
holder.addChild( image );

Now just set the position and rotation of holder as you do currently, and it should be fine

Hard way

You need to manually adjust the position offset based on the object's rotation. A simple rotation function:

public function rotate( p:Point, radians:Number, out:Point = null ):Point
{
    // formula is:
    // x1 = x * cos( r ) - y * sin( r )
    // y1 = x * sin( r ) + y * cos( r )
    var sin:Number  = Math.sin( radians );
    var cos:Number  = Math.cos( radians );
    var ox:Number   = p.x * cos - p.y * sin;
    var oy:Number   = p.x * sin + p.y * cos;

    // we use ox and oy in case out is one of our points
    if ( out == null )
        out = new Point;
    out.x = ox;
    out.y = oy;
    return out;
}

First we need to store the object's offset - this is normally new Point( -obj.width * 0.5, -obj.height * 0.5 ). You need to stock this while it's rotation is 0, and rotating the object will change its width and height properties, so the following won't work properly.

obj.offset = new Point( -obj.width * 0.5, -obj.height * 0.5 );

When you're updating the position, simply rotate the offset by the rotation and add it:

// get our object's position and rotation
// NOTE: you'll probably need to adjust the position based on your pixels per meter value
var pos:Point   = new Point( obj.pBody.GetPosition().x, obj.pBody.GetPosition().y ); // pos in screen coords
var rotR:Number = obj.pBody.GetAngle();     // rotation in radians
var rotD:Number = radiansToDegrees( rotR ); // rotation in degrees

// rotate our offset by our rotation
var offset:Point = rotate( obj.offset, rotR );

// set our position and rotation
obj.x           = pos.x + offset.x;
obj.y           = pos.y + offset.y;
obj.rotation    = rotD;

Other useful functions:

public function degreesToRadians( deg:Number ):Number
{
    return deg * ( Math.PI / 180.0 );
}
public function radiansToDegrees( rad:Number ):Number
{
    return rad * ( 180.0 / Math.PI );
}

OTHER TIPS

If you do it to give your sprites properties of physical objects, it can be easier to use physInjector for box2D:

http://www.emanueleferonato.com/2013/03/27/add-box2d-physics-to-your-projects-in-a-snap-with-physinjector/

It is free can do it in a couple of lines.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top