Friday, November 22, 2013

Arbitrary Center Bitmap Rotation in OpenFL

The problem: Bitmap objects (and display objects in general) are always rotated about the (0,0) relative coordinate when the .rotation member is set. This does not allow an object to pivot on the spot, but rather orbit its upper left point.

The solution: specify a coordinate pair to act as the center, perform a matrix rotate transformation on the point to determine where it would be after the rotation and then translate the Bitmap object to account for the difference.

The downside: the x and y location of the rotating bitmap class must be tracked separately from the x and y of the parent Bitmap, as they will be different. Also, an update method must be called to do the offset.

// import the usual suspects
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.events.Event;
import openfl.Assets;
import flash.Lib;
import flash.geom.Matrix;

class Main extends Sprite {

    private var myTest:RotatingBitmap;

    public function new() {
        super();
        myTest = new RotatingBitmap(
                   Assets.getBitmapData("assets/circle.png")
        );
        myTest.xloc = 400;
        myTest.yloc = 400;
        myTest.xcenter=25;
        myTest.ycenter=25;

        removeEventListener (Event.ENTER_FRAME, this_onEnterFrame);

addEventListener (Event.ENTER_FRAME, this_onEnterFrame);

    }

    private function this_onEnterFrame(event.Event):Void {
        myTest.rotation+=15;
        myTest.update();
    }    

}

class RotatingBitmap extends Bitmap {
        // the intended location, since x and y will be changing
public var xloc:Float;
public var yloc:Float;
        // the center x,y of the rotation
public var xcenter:Float;
public var ycenter:Float;

public function new(asset:Dynamic) {
                // load the asset and add to the stage
super(asset);
flash.Lib.current.addChild(this);
}

public function update() {
                // here's where the magic happens

                // define the rotation parms
var mymatrix:Matrix = new Matrix();
mymatrix.rotate(Math.PI*(this.rotation)/180);

                // create a point to represent the center
var mypoint = new flash.geom.Point(xcenter,ycenter);

                // transform into a new point
var newpoint:flash.geom.Point = mymatrix.transformPoint(mypoint);
                // move the bitmap to the proper new location
                this.x = xloc-newpoint.x;
this.y = yloc-newpoint.y;

}

}

Here is a little example of the default rotation and a rotation set at the (nearly) center of the image.

No comments:

Post a Comment

I had to add anti-spam measures because, let's face it, almost nobody comments on blogs anymore unless they are spamming. Sorry.