开发者

How to show a Bitmap which is only a portion of its BitmapData in AS3?

I am writing a screen scroller for a game I'm making. There's a BitmapData object which holds the background graphic, yet I do not want to show/render it on screen all at once.

For example, I want to show only a 500x500 section of the data but the entire BitmapData is 1000x1000. I wanted to use the scroll() method to scroll the data but my problem is that I cannot restrict how much of the BitmapData is drawn on the Bitmap. I tried setting the height/width properties of the BitmapData to 500x500 (and draw all the 1000x1000), but any data drawn beyond the boundaries I defined is not really drawn.

Another option I considered is to store a different BitmapData object which holds the entire dat开发者_如何学编程a, and then use copyPixels() from it to the one used on the Bitmap itself, although then I cannot use scroll() and have to use different methods to achieve scrolling.

Thanks in advance for whoever answers.


The best way to do this is to blit using CopyPixels(). Essentially you'll add a Bitmap object to stage sized correctly to reflect the area you want to display, and then you'll use CopyPixels to bring over only what you want to display at any given time.

var largeBitmap:Bitmap = yourLargeBitmap;
var displayBitmap:Bitmap = new Bitmap(new BitmapData(500, 500));
addEventListener(Event.ENTER_FRAME, loop);

function loop(e:Event):void {
displayBitmap.bitmapData.copyPixels(largeBitmap, new Rectangle(X, Y, 500, 500), new Point());
}

Populate X and Y and you're set!

Edit: Yes, this require double the memory because you're essentially holding two bitmap data objects in memory at any given time - but honestly that's going to be a minimal problem. Especially if your bitmaps are so small, the memory footprint is negligible. What's nice, though, is that you are sidestepping any kind of object manipulation or display list jockeying - and THAT is where major performance benefits come in. Honestly for something this simple anything you do is going to work just fine - but if you're deploying to a mobile device, or end up making a larger background, or whatever, you're going to see performance increase from blitting over masking or scaling or any of the other tricks. This is generally held to be a Best Practice as far as I'm aware. /Edit

Note that a lot of gaming frameworks (such as Flixel, for instance) have blitting engines built in. You get much better performance if you blit everything as opposed to using the display list.


I would do:

//the rectangle you would like to draw
var rectangle:Rectangle = new Rectangle(100,100,400,500);

var shape:Shape = new Shape();
var matrix:Matrix = new Matrix(1,0,0,1,-rectangle.x, -rectangle.y);
shape.graphics.beginBitmapFill(bitmapData, matrix);
shape.graphics.drawRect(0, 0, rectangle.width, rectangle.height);
shape.graphics.endFill();

You can then scroll by changing the rectangle's position, or changing the matrix directly.

UPDATE: After checking Myk's answer, I was surprised to find (after fairly quick and loose tests) that beginBitmapFill appears to be actually faster than copyPixels. I'll leave my tests codes, so if you're interested have a go at it:

copyPixels (I get 15-20 fps):

var bmp:BitmapData=new BitmapData(1000, 1000, true, 0);
bmp.perlinNoise(100, 100, 3, 1, true, true);

var arr:Array=new Array();
for (var i:uint = 0; i < 50; i++) {
    var clip:Bitmap = new Bitmap(new BitmapData(500, 500));
    addChild(clip);
    clip.alpha = .05;
    arr.push(clip);
}
var t1:uint = getTimer();
stage.addEventListener("enterFrame", function() {
    trace(getTimer() - t1);
    t1 = getTimer();
    for each(var clip:* in arr) {
        var x:uint=Math.random()*100;
        var y:uint=Math.random()*100;

        clip.bitmapData.copyPixels(bmp,new Rectangle(x,y,500,500), new Point);
    }
});

and beginBitmapFill (I get 55-60 fps):

var bmp:BitmapData=new BitmapData(1000, 1000, true, 0);
bmp.perlinNoise(100, 100, 3, 1, true, true);

var arr:Array=new Array();
for (var i:uint = 0; i < 50; i++) {
    var clip:Shape = new Shape();
    addChild(clip);
    clip.alpha = .05;
    arr.push(clip);
}
var t1:uint = getTimer();
stage.addEventListener("enterFrame", function() {
    trace(getTimer() - t1);
    t1 = getTimer();
    for each(var clip:* in arr) {
        var x:uint=Math.random()*100;
        var y:uint=Math.random()*100;

        clip.graphics.clear();
        clip.graphics.beginBitmapFill(bmp,new Matrix(1,0,0,1,-x,-y),false,false);
        clip.graphics.drawRect(0,0,500,500);
        clip.graphics.endFill();
    }
});


Create shape, draw 500x500 filled rectangle into it and assign it to bitmap's mask property - bitmap will be clipped to this size.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜