PDA

View Full Version : AS3 Explanations...



lgm432
February 15th, 2010, 08:19 AM
Ok, I realize that I am really knew to bitmaps, and rendering, and bitmap objects, etc. etc. So if someone could find it in the kindness of their heart to explain pretty much all of the stufff involving bitmaps, copypixels, offsets, bitmap objects, etc. etc. from this thread:
http://www.kirupa.com/forum/showthread.php?p=2535671#post2535671
Then I would be eternaly grateful.
(Also anything else you can explain about all this stuff would be really appreciated (-:)

-Lgm432 :o_rly:

mxrider108
February 15th, 2010, 10:55 AM
Hey again :)

Well, let's see... I assume you have a good understanding of object-oriented programming and related concepts. If not, I'd recommend you start there if you intend to use AS3.

As far as rendering goes, there are a couple of main techniques. Flash was created with a whole bunch of stuff done for you to make drawing/animating/rotating/scaling/etc easy and brainless. The built-in graphics libraries are intended to work by using something called the Display List, which holds specific types of objects which are considered DisplayObjects (such as Sprite or MovieClip). The Display List knows what DisplayObjects it should render because you addChild() or removeChild() them. After that, you just need to update a few properties like x, y, rotation, etc and the objects will render with the changes automatically.

Sounds easy, so why doesn't everyone use this method? Well, the native Flash rendering engine (using the Display List) has a lot of features which many games may not need. Instead, many people opt to use a technique from very old retro games known as "blitting." Blitting involves literally copying bitmap information as raw pixel data and shifting it to a different place in memory. This is a simple copy operation that doesn't require running a lot of complex algorithms like the Display List uses to render, say, a rotated MovieClip.

Another thing to understand is the difference between a Bitmap and a BitmapData. A Bitmap is a DisplayObject and thus can be rendered using the Display List. It can thus be moved around using the x and y properties, etc. Using the "blitting" technique requires making one big DisplayObject (Bitmap) that covers the whole screen, and then everything else is just copyPixels() from a BitmapData onto this object. This allows you to use one single BitmapData for each different type of enemy or game object.

This method is awesome for speed, but even simple things like rotation become complex tasks because you will practically need to write your own graphics library for any "advanced" features. (I've programmed games from scratch on a GameBoy before where I had to literally convert every image into an array, so I've had experience with these kinds of low-level operations).

So see what works best for you. The blitting technique can be great, but it can also be frustrating for beginners. If your game doesn't have a whole lot of complex objects moving around all the time then I would say save yourself some headaches and use the tools Flash gives you to make your life easier. Or, try using a mix of the two techniques (maybe only blit things like background objects or particles?).

Any questions? Was that fairly clear?

TOdorus
February 15th, 2010, 07:44 PM
http://www.flashmusicarchives.com/newsdisplay.aspx?newspage=13430

http://www.8bitrocket.com/newsdisplay.aspx?newspage=17171

lgm432
February 16th, 2010, 08:08 AM
Hey again :)

Well, let's see... I assume you have a good understanding of object-oriented programming and related concepts. If not, I'd recommend you start there if you intend to use AS3.

As far as rendering goes, there are a couple of main techniques. Flash was created with a whole bunch of stuff done for you to make drawing/animating/rotating/scaling/etc easy and brainless. The built-in graphics libraries are intended to work by using something called the Display List, which holds specific types of objects which are considered DisplayObjects (such as Sprite or MovieClip). The Display List knows what DisplayObjects it should render because you addChild() or removeChild() them. After that, you just need to update a few properties like x, y, rotation, etc and the objects will render with the changes automatically.

Sounds easy, so why doesn't everyone use this method? Well, the native Flash rendering engine (using the Display List) has a lot of features which many games may not need. Instead, many people opt to use a technique from very old retro games known as "blitting." Blitting involves literally copying bitmap information as raw pixel data and shifting it to a different place in memory. This is a simple copy operation that doesn't require running a lot of complex algorithms like the Display List uses to render, say, a rotated MovieClip.

Another thing to understand is the difference between a Bitmap and a BitmapData. A Bitmap is a DisplayObject and thus can be rendered using the Display List. It can thus be moved around using the x and y properties, etc. Using the "blitting" technique requires making one big DisplayObject (Bitmap) that covers the whole screen, and then everything else is just copyPixels() from a BitmapData onto this object. This allows you to use one single BitmapData for each different type of enemy or game object.

This method is awesome for speed, but even simple things like rotation become complex tasks because you will practically need to write your own graphics library for any "advanced" features. (I've programmed games from scratch on a GameBoy before where I had to literally convert every image into an array, so I've had experience with these kinds of low-level operations).

So see what works best for you. The blitting technique can be great, but it can also be frustrating for beginners. If your game doesn't have a whole lot of complex objects moving around all the time then I would say save yourself some headaches and use the tools Flash gives you to make your life easier. Or, try using a mix of the two techniques (maybe only blit things like background objects or particles?).

Any questions? Was that fairly clear?


Yeah... I think I understand. So, to blit you would first make a Bitmap and add it to the display list, then nothing else would be added onto the stage, and all images would simply be pasted into this master Bitmap... right? Also, if this is the case, I can see why it would become nearly impossible to do things such as collision detection, or complicated movement. If I am wrong please correct me :)

Also I do indeed know about OOP for AS3

therobot
February 16th, 2010, 02:04 PM
Yeah... I think I understand. So, to blit you would first make a Bitmap and add it to the display list, then nothing else would be added onto the stage, and all images would simply be pasted into this master Bitmap... right? Also, if this is the case, I can see why it would become nearly impossible to do things such as collision detection, or complicated movement. If I am wrong please correct me :)

Also I do indeed know about OOP for AS3

This should help to clarify:



import flash.display.Bitmap;
import flash.display.BitmapData;


var bitmapInMemory:BitmapData = new BitmapData(500, 500);
var bitmapOnStage:Bitmap = new Bitmap(bitmapInMemory);


addChild(bitmapOnStage);


You work with the BitmapData object in your code. Any changes you make to it will get displayed since the Bitmap object holds a reference to it.

Collision detection and "complicated" movement are still possible this way. As far as collision detection goes, the only thing you'll be missing is flash's native hitTest, which is a bit inefficient anyways :)

lgm432
February 16th, 2010, 02:21 PM
This should help to clarify:


ActionScript Code:

</p>
<p>import flash.display.Bitmap;</p>
<p>import flash.display.BitmapData;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>var bitmapInMemory:BitmapData = new BitmapData(500, 500);</p>
<p>var bitmapOnStage:Bitmap = new Bitmap(bitmapInMemory);</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>addChild(bitmapOnStage);</p>
<p>




You work with the BitmapData object in your code. Any changes you make to it will get displayed since the Bitmap object holds a reference to it.

Collision detection and "complicated" movement are still possible this way. As far as collision detection goes, the only thing you'll be missing is flash's native hitTest, which is a bit inefficient anyways :)

So... you first create bitmapData object, then create a bitmap from that. Can you provide an example of blitting using above code?:write:

rumblesushi
February 16th, 2010, 02:49 PM
Yeah... I think I understand. So, to blit you would first make a Bitmap and add it to the display list, then nothing else would be added onto the stage, and all images would simply be pasted into this master Bitmap... right? Also, if this is the case, I can see why it would become nearly impossible to do things such as collision detection, or complicated movement. If I am wrong please correct me :)

Also I do indeed know about OOP for AS3

Yes you are wrong. Collision detection would be absolutely no different at all, you'd be using the same coordinates for the objects, regardless of how they are rendered. The only difference is you'd have more juice left for advanced collision detection by usign copyPixels etc, rather than using movieClips as it's faster - and as someone else mentioned, the native collision detect methods aren't very good and are slow anyway.

Plus using BMD based rendering allows you to use getPixel based collision tests if you so desire.

therobot
February 16th, 2010, 06:17 PM
Here is a more fleshed out example of how copy pixels works. In a game, your source bitmapdata object would be like a sprite sheet or a tilesheet, and you'd want to come up with a routine for figuring the position of your source rectangle and destination point.



import flash.display.Bitmap;
import flash.display.BitmapData;

// start with a black bitmap
var bitmapInMemory:BitmapData = new BitmapData(500, 500, true, 0xff000000);
var bitmapOnStage:Bitmap = new Bitmap(bitmapInMemory);

addChild(bitmapOnStage);


// copying pixels requires 4 things:
// 1. a destination BitmapData to copy to.
// 2. a source BitmapData to copy from
// 3. a Rectangle object that defines the region you want to copy from the source.
// 4. a Point to paste the copy pixels into

// don't forget to import Point and Rectangle !
import flash.geom.Point;
import flash.geom.Rectangle;

// create a source bitmapdata object that we will copy from.
// normally, you'd probably have a sprite sheet or a tilesheet here.
// to demonstrate, we'll just use a green sheet.
var sourceBMD:BitmapData = new BitmapData(100, 100, true, 0xff00ff00);


var copyDestinationPoint:Point = new Point (50, 50);
var sourceCopyRectangle:Rectangle = new Rectangle(10, 10, 40, 40);


// basically this is going to copy a 40x40 chunk from the sourceBMD, starting at (10, 10),
// and paste it into bitmapInMemory at the destination point (50, 50)
bitmapInMemory.copyPixels(sourceBMD, sourceCopyRectangle, copyDestinationPoint);

mxrider108
February 16th, 2010, 11:58 PM
Yes you are wrong. Collision detection would be absolutely no different at all, you'd be using the same coordinates for the objects, regardless of how they are rendered. The only difference is you'd have more juice left for advanced collision detection by usign copyPixels etc, rather than using movieClips as it's faster - and as someone else mentioned, the native collision detect methods aren't very good and are slow anyway.

Plus using BMD based rendering allows you to use getPixel based collision tests if you so desire.
Exactly. The only things that are more complicated using this method have to do with rendering-- such as rotation and scaling.

For example:
I can make my own "box" object which does not extend MovieClip, but instead renders by copyPixels() from a bitmapData of a cardboard box. I then give this class a "rotation" property. Now I can change the box.rotation value all day long, but in reality all I'm doing is changing an arbitrary number -- the box will never appear to rotate. The difference is that when Flash renders MovieClips it looks up the value of this number and runs a rotation algorithm (likely implemented with a matrix stack) before it renders the pixels.

If you want to be able to render objects with rotation using copyPixels() you have to figure out how to do that yourself, as copyPixels() only understands the basic copy. Option 1. Write your own algorithm using a transformation matrix (and maybe anti-aliasing algo to prevent jagged edges). This is complicated and chances are good your version will be slower than the native Flash one anyway. Option 2. Do something crafty like pre-render a rotation spritesheet and just find/change the coordinates and size of the Point and Rectangle objects you pass to the copyPixels() routine.

I know I strayed a bit from the theory here, but I wanted to give you some concrete examples of the main pros and cons of blitting. If you need more help with specific things like rotation, let us know, but the posts in this thread should be sufficient to answer your original questions (although feel free to ask for clarification if need be).

dandylion13
March 5th, 2010, 02:00 PM
Hey guys, this is interesting!

I have not had the need to try out this technique until now, and you've all done a great job of explaining this. I've used copyPixels many times, but for different things. What you've described seems ideal for particle effects, which is what I'm working on at the moment.

But...! I have a question! :)

therobot, I understand what your code is doing. But how can you make an object move using that technique? (I understand that one doesn't "move objects", just re-copy rectangular sections of the bitmapInMemory to different places in the destination bitmapdata)

Do you figure out positions abstractly and then use x and y co-ordinates to re-map parts of the bitmapInMemory using copyPixel() each frame?

dandylion13
March 5th, 2010, 02:46 PM
Ok.. I figured it out! My guess was right.

dandylion13
March 6th, 2010, 04:26 AM
First.. this is amazingly fast! I'm really enjoying it. It's also really, really simple once you get the concepts down.. not much code either.

But I do have another question! (for real, this time!) :)

How is it possible to modify the alpha for individual tiles? For example, to gradually fade them out?

I'm guessing that alpha would be modified in the copyPixels() operation, but I'm not sure of how to do this. If anyone could off a suggestion for what I could try, that would be great :)

mxrider108
March 8th, 2010, 11:34 AM
BitmapData objects support 32-bit ARGB values for every pixel in the bitmap, so for non-changing alpha you can have that directly in your source BitmapData object. However, if you want to "fade" an object you probably don't want to touch the source BitmapData. Instead you have a couple of options:

You can pre-render a bunch of different versions of the bitmap, stored in multiple or one BitmapData objects, and use a spritesheet animation style to simply display each new level of fade a frame at a time.

You can use the optional "alphaBitmapData" parameter (http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/display/BitmapData.html#copyPixels()) of copyPixels and keep passing in a more and more faded alpha mask. This is useful if you have several types of objects which are the same size/shape because you can re-use the mask objects for each of these types.

Another way to do this is to dynamically set the ARGB values using getPixel32() / setPixel32() in a loop (or getPixels() / setPixels()). This requires less memory usage because it can be done on-the-fly, but it takes more CPU cycles to compute (slower).

Which method is best depends on if the fading is something which happens all the time in your game or just on occasion (new game/end game for example). If anyone has a better way to accomplish this (at what threshold does the native Display List become faster for this type of thing?), speak up, because I am curious as well.

dandylion13
March 8th, 2010, 02:38 PM
Thanks mxrider!
I was not aware of those options.
I will look into the alphaBitmapData a bit more closely.. that sounds like what I was looking for.
Bascially I'm trying to fade out the tiles (bobs) at different rates after the explosion. They're all same size.

My guess is that pre-rendering the bitmaps in the tile sheet will be the fastest option. Yes, you're right, as soon as we ask the Flash player to start doing more complex things we loose the performance advantage that is the hallmark of this system.

Thanks again.. I will run some tests! :)

mxrider108
March 8th, 2010, 03:44 PM
I actually just wrote a method that you can use to fade a BitmapData for use in copyPixels() dynamically. The pre-rendering method is a little too hard to scale in my opinion (and it gets even worse if you are using rotation/animation, cause you have to pre-render a fade for every frame of that too).

This may not be quite as fast as pre-rendering the fades, but I am using Vectors and bitwise math to optimize it the best I can. There are a couple other things you could do to speed this up more, such as pre-create the input vector using getVector() when your object gets first created, so Vector objects aren't being created and destroyed each time this method runs. You could also substitute the multiplication of alpha with a bitshift if you don't mind having a little less precision in your fade.



// source: The source BitmapData object we wish to fade.
// dest: A pre-created BitmapData holder object to store the result. Better than creating a new object every time.
// alpha: A number from 0 - 1 which is the % of fade (ex: 1 = 100% opaque).
public function changeAlpha(source:BitmapData, dest:BitmapData, alpha:Number):void {
// get the pixels as a Vector object (FP 10 and higher only!)
// ( why to use Vectors instead of ByteArrays: http://webr3.org/blog/haxe/bitmapdata-vectors-bytearrays-and-optimization/ )
var pixels:Vector.<uint> = source.getVector(source.rect);
var totalPx:int = pixels.length;
// update the vector with the modified pixel data
var pixel:uint;
for (var i:int = 0; i < totalPx; ++i) {
pixel = pixels[i];
// modify only the alpha of ARGB uint (8-bit value from 0-255)
if ((pixel >>> 24) > 0) pixels[i] = (((pixel>>>24)*alpha) << 24) + (pixel & 0×00FFFFFF);
}
dest.setVector(dest.rect, pixels);
}


You can pass the same BitmapData object to "source" and "dest" if you want to permanently modify the original, or you can use a separate object to hold all temporary fade states of the object without losing your original.

dandylion13
March 8th, 2010, 04:21 PM
Wow, that's great, MX!
I will look at it closely and see if I can get it working in my system.

Thank you so much for taking the time!!

Yes, understand what you mean about pre-rendering being a bit hard to scale.