Search code examples
actionscript-3bitmapbitmapdata

How do I clear the bitmap each time before blitting?


I'm very new to blitting, and I'm still trying to understand the process. In my View object, I have this in my constructor;

this.bcg = new BitmapData(800,600,false,0x000000);
this.canvas = new Bitmap(bcg);

Then I add it to the stage;

addChild(canvas);

Then inside my main game loop, I iterate through a nested array to blit copies of rectof type BitmapData objects;

if (array[i][j] !=0) {
        canvas.bitmapData.copyPixels(rect, rect.rect, new Point(i, j));
}

I thought perhaps I could do it by blitting by background back onto canvas before my loop;

canvas.bitmapData.copyPixels(bcg, bcg.rect, new Point(0, 0));

But that doesn't work. I've tried searching around for an answer for this, but it's very difficult to find any in-depth information on blitting in AS3.

What I'm trying to do is clear the bitmap of all the pixels I've blitting onto it, and start again with just my background, bcg. I tried doing this before my loop;

this.bcg = new BitmapData(800,600,false,0x000000);
this.canvas = new Bitmap(bcg);

But I ended up with a completely black screen, and none of my rect were being blitted onto canvas.


Solution

  • Here's a simple blitting example:

    private var m_bg:BitmapData         = new BitmapData( 400, 300, false, 0xffff0000 );    // simple solid red colour
    private var m_canvas:BitmapData     = new BitmapData( 400, 300, true, 0x00000000 );     // the canvas that we're drawing into
    private var m_obj:BitmapData        = new BitmapData( 20, 20, false, 0xff00ff00 );      // simple green square
    private var m_objDrawPos:Point      = new Point;                                        // where we'll draw our obj
    private var m_objDir:Point          = new Point;                                        // the direction that our obj is moving in
    private var m_objSpeed:Number       = 20.0;                                             // the speed of our obj
    
    public function Main()
    {
        // create the bitmap for our canvas and add it to the stage
        var b:Bitmap = new Bitmap( this.m_canvas );
        this.addChild( b );
    
        // set our initial direction
        this.m_objDir.setTo( 1.0, 1.0 ); // diagonal right
    
        // add our enter frame
        this.addEventListener( Event.ENTER_FRAME, this._onEnterFrame );
    }
    
    private function _onEnterFrame( e:Event ):void
    {
        // move our object by changing it's draw position
        this.m_objDrawPos.x += this.m_objDir.x * this.m_objSpeed;
        this.m_objDrawPos.y += this.m_objDir.y * this.m_objSpeed;
    
        // simple bounds change, to reflect the object
        if ( this.m_objDrawPos.x < 0 || this.m_objDrawPos.x + this.m_obj.width > this.m_canvas.width )
            this.m_objDir.x *= -1;
        if ( this.m_objDrawPos.y < 0 || this.m_objDrawPos.y + this.m_obj.height > this.m_canvas.height )
            this.m_objDir.y *= -1;
    
        // copy our this.m_bg - this will erase all previous changes
        // NOTE: depending on what your bg is, you can all use fillRect() if it's a solid colour
        // NOTE: passing new Point() as the destPoint, will mean that our bg will always be drawn
        // in the top-left of the canvas. As this never changes - you can keep this as a variable
        this.m_canvas.copyPixels( this.m_bg, this.m_bg.rect, new Point );
    
        // copy our object to its new position
        this.m_canvas.copyPixels( this.m_obj, this.m_obj.rect, this.m_objDrawPos );
    }
    

    What you need to know about blitting, is that it's the position passed in as destPoint that determines the top-left position of the BitmapData that you're blitting - think of it as the x and y of a normal DisplayObject - (0,0) will mean that it's drawn in the top left, while (canvas.width - obj.width, canvas.height - obj.height) will mean that it's drawn in the bottom right.

    To make your life easier, create a simple class to store all this data for you. Something like:

    public class BlitObj
    {
    
        /************************************************************/
    
        private var m_bmd:BitmapData    = null; // our BitmapData graphics
        private var m_offset:Point      = null; // the offset (how we manage the reference point)
        private var m_drawPos:Point     = null; // our draw position for when we're blitting the object
        private var m_position:Point    = null; // the position of our object, in relation to the reference point
    
        /************************************************************/
    
        /**
         * The position of the BlitObj, in relation to the reference point
         */
        public function get position():Point { return this.m_position; }
    
        /**
         * The BitmapData graphics that we're going to blit
         */
        public function get blitGraphics():BitmapData { return this.m_bmd; }
    
        /**
         * The position to blit this BlitObj at (top-left corner)
         */
        public function get blitDestPos():Point { return this.m_drawPos; }
    
        /************************************************************/
    
        /**
         * Creates a new BlitObj
         * @param bmd The graphics for this BlitObj
         * @param offset The offset to our registration point
         */
        public function BlitObj( bmd:BitmapData, offset:Point = null )
        {
            this.m_bmd      = bmd;
            this.m_offset   = ( offset == null ) ? new Point : offset;
            this.m_drawPos  = new Point( -this.m_offset.x, -this.m_offset.y );
            this.m_position = new Point;
        }
    
        /**
         * Sets the position of the BlitObj (in relation to its reference point)
         * @param x The x position of the object
         * @param y The y position of the object
         */
        public function setPos( x:Number, y:Number ):void
        {
            this.m_position.setTo( x, y );
            this.m_drawPos.setTo( x - this.m_offset.x, y - this.m_offset.y ) ;
        }
    }
    

    One thing to watch for when blitting, and one this this class does, it handle the offset. When you provide a destPoint to the copyPixels() function, it's the position to place the top-left of your BitmapData before drawing it. Often, however, you want your object to have a different reference point that the top left (e.g, a circle will have its reference point in the middle). This lets you handle that.

    // create our circle graphics with their registration point in the center
    var circleBMD:BitmapData    = ...; // get the graphics for your circle
    var circle:BlitObj          = new BlitObj( circleBMD, new Point( circleBMD.width * 0.5, circleBMD.height * 0.5 ) );
    circle.setPos( this.stage.stageWidth * 0.5, this.stage.stageHeight * 0.5 ); // center it on the stage
    
    // now you can draw it:
    canvas.copyPixels( circle.blitGraphics, circle.blitGraphics.rect, circle.blitDestPos );