0
votes

I got a problem with AS3 and AIR. I'm working on a side-scrolling game for smartphones with a plane and I use different backgrounds as layers.

Before all other: I use GPU and only bitmaps, quality is set to low. So Performance settings are all set for smartphone use.

I putted them into a rectangle using the drawing API and move the background with a matrix:

protected var scrollingBitmap:BitmapData;
protected var canvas:Graphics;
protected var matrix:Matrix;

public function move(dx:Number, dy:Number):void {
    matrix.translate(dx, dy);
    if(dx != 0) matrix.tx %= scrollingBitmap.width;
    if(dy != 0) matrix.ty %= scrollingBitmap.height;
    drawCanvas();
}

protected function drawCanvas():void {
    canvas.clear();
    canvas.beginBitmapFill(scrollingBitmap, matrix, true, true);
    canvas.drawRect(0, -scrollingBitmap.height, 1404, scrollingBitmap.height);
}

UPDATE2 (

Take a look at this: http://plasticsturgeon.com/2010/06/infinite-scrolling-bitmap-backgrounds-in-as3/

I used this to create my backgrounds.

With this I can simulate that my plane is flying to the right without moving the whole background and I can use a small single graphic which repeats every time (for the foreground layer).

For the background layer I use this method, too, but with a much larger graphic and I move it only with less the speed of my plane to simulate a far background.

My move-method is on an enterframe event. So I can update the background every frame with the "movement" of my plane.

)

The plane can exceed the height of the bitmaps. Everytime the bitmap comes back into the window/screen a real long lag occurs. And when the plane flies very fast, the game start to lag, too.

My first approach was to use .PNG files (but they are very big: 1-3MB size). My next approach was to use .GIF files (much less size).

With both it's the same. So it can't be that.

I read about draw() and copyPixels() but I don't know, how I can use those to repeat the image.

UPDATE1:

protected var scrollingBitmap:BitmapData;
protected var canvas:Bitmap;

protected function init(e:Event):void {
    removeEventListener(Event.ADDED_TO_STAGE, init);
    canvas = new Bitmap(new BitmapData(1404, scrollingBitmap.height, true), "auto", true);
    this.addChild(canvas);
    drawCanvas();
}

public function move(dx:Number, dy:Number):void {
    if(dx != 0) dx %= scrollingBitmap.width;
    if(dy != 0) dy %= scrollingBitmap.height;
    drawCanvas(dx, dy);
}

protected function drawCanvas(xPos:Number = 0, yPos:Number =  0):void {
    canvas.bitmapData.copyPixels(scrollingBitmap, new Rectangle(0, 0, 1404, scrollingBitmap.height), new Point(xPos, yPos), scrollingBitmap);
}
2
I'm thinking your move isn't going to work, because you've only moving the bitmap with the translation--I don't see where you're moving any pixels back to the other side. But your question is about the speed of the copy, not the effectiveness of the move, so that is what I answered.Amy Blankenship
The move is working, it moves to the left, with the speed the plane is flying. But I move the whole Level:MovieClip (it's another file) in the y direction. Take a look here: plasticsturgeon.com/2010/06/…WolvDev
It sounds, then, like your graphic is far larger (twice as large) than what it needs to be, which is part of your speed issue.Amy Blankenship
I got a background graphic which is far more larger than twice. I need to scroll this image with 1% the flight speed to simulate a far background and another layer in the foreground will move at normal speed.WolvDev
Updated my question with "Update2" maybe this will lead to a better understanding of what I will achieveWolvDev

2 Answers

3
votes

I think you'd be better off with a Bitmap instead of using the graphics object with fill. copyPixels is very fast. So what you'd do is simply copyPixels over the top of whatever was there before, presuming everything is opaque. If everything is not opaque, you'll need to use your source bitmap as its own alpha data so previously drawn pixels don't show through.

Let's reframe your canvas so it is a Bitmap and not a MC. your new code will look like:

protected function drawCanvas():void {
   canvas.bitmapData.copyPixels(scrollingBitmap, new Rectangle(0, 0, scrollingBitmap.width, scrollingBitmap.height), new Point(0,0), scrollingBitmap);
}

Oh, and look at that! Not only is this code faster, it's only one line of code!

EDIT: Added working code

package  {
    import flash.display.MovieClip;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.events.Event;
    import flash.geom.Rectangle;
    import flash.geom.Point;


    public class EndlessBG extends MovieClip{
        //this one stays stationary, we're getting the pixels for the right side of the pic from here
        private var _source:BitmapData;
        //this is the one moving to the left (the pixels for the right side are not visible except for once a cycle);
        private var _movingPixels:BitmapData;
        private var _canvas:Bitmap;
        private var _xOffset:int = 0;
        private var _rect:Rectangle = new Rectangle();;
        private var _point:Point = new Point();

        public function EndlessBG() {
            super();
            _source = new BathroomStillLife();
            _canvas = new Bitmap(new BitmapData(_source.width, _source.height));
            _canvas.bitmapData.draw(_source);
            _canvas.x = stage.stageWidth/2 - _canvas.width/2;
            _canvas.y = 5;
            addChild(_canvas);
            addEventListener(Event.ENTER_FRAME, gameLoop);
            setGeometryDefaults();
            _movingPixels = new BitmapData(_source.width, _source.height);
            _movingPixels.copyPixels(_source, _rect, _point);
            //turn this on to watch red pixels be drawn where the source pixels are coming in
            //_source = new BitmapData(_source.width, _source.height, false, 0xFF0000);
        }

        private function gameLoop(e:Event):void {
            _xOffset--;//where the background is moving to
            if (_xOffset < -_source.width) {
                _xOffset = 0;
                //this doesn't seem to work correctly:
                //_movingPixels.scroll(_source.width, 0);
                _movingPixels = new BitmapData(_source.width, _source.height);
                _movingPixels.copyPixels(_source, _rect, _point);
            }
            trace(_xOffset);
            setGeometryDefaults();
            _movingPixels.scroll(-1, 0);
            //draw the moved part of the canvas
            _canvas.bitmapData.copyPixels(_movingPixels, _rect, _point);
            //If we stop here, we get a smear to the right
            //so, get the remaining pixels directly from the source
            //1) reset our rect and point to be to the right side
            _rect.x = 0;
            _rect.width = -_xOffset;
            _point.x = _source.width + _xOffset;
            //2) copy from the source
            _canvas.bitmapData.copyPixels(_source, _rect, _point);
        }
        private function setGeometryDefaults():void {
            _rect.x=0;
            _rect.y=0;
            _rect.width = _source.width;
            _rect.height = _source.height;
            _point.x = 0;
            _point.y = 0;
        }

    }

}

Not ideal, and not polished enough yet for a blog post, but should get you started.

Edit: Eventually I did write that blog post.

0
votes

http://www.greensock.com/blitmask

This might help although not free