PDA

View Full Version : [AS3] Best way to maintain rendering order/ Z index?



doomtoo
July 31st, 2009, 11:14 PM
In c++ I could choose to render everything in the say map array 1st, or sprites second, then all user interface objects.

The only way I have found in flash is to add the objects to the stage in the proper order, but this makes problems like when a window is brought up over the cursor that was previously added to the stage.

To get around that, I have a listener for when anything is added to the stage, that then changes the index of the cursor, but is their a better way to do this? Otherwise I'm going to have to reset the index of a ton of objects everytime things are added.

The only other way I can think of is to remove all objects from the stage at the end of rendering, then add them again before the next frame, but I'm not sure how to do that!

Any way I can say:
on enterframe
for each(map_tile in map)
map_tile.render)

for each(entity in entities)
entity.render()

for each (UI_element in UI_elementsArray)
UI_element.render()

TOdorus
August 1st, 2009, 12:53 AM
I suspect you use movieClips to render your game? You might want to look into blitting (http://www.8bitrocket.com/newsdisplay.aspx?newspage=17171), as it can do the exact thing you're asking for.

doomtoo
August 1st, 2009, 02:15 AM
I'm using the Loader class to load the sprite's externally, so I can exchange them at run time and can load different graphics into it at different points of the game when needed.

I'll look into blitting in as3 and see if it will work, thanks!

doomtoo
August 2nd, 2009, 02:22 PM
Do you have any additional sources on blitting? In AS3, it is just rendering everything to a texture before adding the entire texture as a bitmap in the flash window? Somewhat like double buffering, except just getting the control the render depth?

I googled it, but mainly stuff from 8bitrocket.

Maybe I can change the Z-index of all simmilar structures to the same?

TOdorus
August 2nd, 2009, 09:22 PM
Do you have any additional sources on blitting?

Well.. myself. I developed my own version of it after a thread on Flashkit (http://board.flashkit.com/board/showthread.php?t=732354) showing that using copypixels in AS3 was lightning fast. Afterwards I learned that it resembled an older technique called blitting.


In AS3, it is just rendering everything to a texture before adding the entire texture as a bitmap in the flash window? Somewhat like double buffering, except just getting the control the render depth?

I've never worked with double buffering, but I've heard it did bare some resemblance. The way I apply blitting, is to have all the objects needed to be displayed sorted (by using an array, ,the tile they occupy or whatever). Then it's a matter of copypixeling all the items that are furthest away from the camera and working your way up to the ones closest. So yes, it's basicly stamping picture after picture on an empty canvas.



var Canvas:BitmapData = new BitmapData(700, 510, true, 0xFFFFFFFF)
var Screen:Bitmap = new Bitmap(Canvas, "never", false)
var charactersArray:Array //array containing all the characters obviously
var BMPrender:Rendering //custom renderer class that gets the proper frame from a spritesheet
//
function updateRender():void {
Canvas.lock()
BMPrender.wipeCanvas()
charactersArray.sort(sortOnZ)
var i:int
var Length:int
var theCharacter:Character
for(i = 0; i < Length; i++){
theCharacter = charactersArray[i]
BMPrender.renderSheet(theCharacter.x, theCharacter.y, theCharacter.z, theCharacter.currentFrame)
}
Canvas.unlock()
}


I've posted some more on that renderer class in this thread (http://www.kirupa.com/forum/showthread.php?t=324447). If you have anymore questions on the subject I'll probably be able to anwer them.

doomtoo
August 20th, 2009, 10:01 PM
Hey thanks TOdorus,

I get it mostly, but wanted to clarify some things.

For "rendering" to the bitmap, you just copypixel the entire bitmap/sprite onto the surface, then how do you present the surface to screen?

At the beginning of the next pass, you just write everything, say black to have a fresh slate?

Also I saw your sprite sheet- how do you have actionscript be able to choose the color of the alpha value? For instance you, like I did previously and learned from one of my books, used a pink color that will be the subtracted color/used as the alpha channel. Have you noticed any speed improvements doing this vs. loading everything as PNG's with built-in alpha?

Do you have any other resources? I think I found enough code to get started with in the AS3 cookbook, but I'll check out your render class in the other thread as I go too. Thanks!

Gnoll
August 20th, 2009, 10:52 PM
Okay, you add one bitmap to the stage, that is your canvas. Then:

1. Lock your canvas's bitmapData
2. Clear it (fillRect with background colour seems to be fastest)
3. copyPixel all your images
4. Unlock

Something along those lines anyway :)

I have a little engine i started working on around here somewhere if you want to have a look.

For color based transparency you can use the threshold method. (I think)

Gnoll

Edit. Attached file, example usage is:



private var canvas:BitmapSpriteStage = new BitmapSpriteStage(new BitmapData(stage.stageWidth, stage.stageHeight, true, 0xFF000000));
private var container:BitmapSpriteContainer = new BitmapSpriteContainer();

//Main function
addChild(canvas);

//add some BitmapSprite to container etc

canvas.draw(container);



Edit2. It is optimized for fp10, you will need to change the BitmapSpriteContainer's holder to an array for lower versions

TOdorus
August 21st, 2009, 10:53 AM
For "rendering" to the bitmap, you just copypixel the entire bitmap/sprite onto the surface, then how do you present the surface to screen?

Well Gnoll uses loose graphics, frames if you will. I'm used to using spritesheets as I've found they can take up to 96% less memory with the same functionality. So I copypixel a cell of a spritesheet (my version of a frame) to a bitmapData. The bitmapdata I copypixel to is a high and width as the stage and used by a bitmap that is on the stage.

I did notice another difference with how Gnoll works and how I usually do it. Do you use a seperate sprite (and therefore a seperate bitmapdata) for every new agent Gnoll? I keep a reference to a spritesheet within every agent, so I only need one spritesheet per agenttype. The renderer class just reads the spritesheet property and works out where and which cell must be displayed. The x and y properties are on the agent itself. It's more of a model/view thing I guess.


Also I saw your sprite sheet- how do you have actionscript be able to choose the color of the alpha value? For instance you, like I did previously and learned from one of my books, used a pink color that will be the subtracted color/used as the alpha channel. Have you noticed any speed improvements doing this vs. loading everything as PNG's with built-in alpha?

I think Gnoll is on the right track with the treshold method, as you can pass a "==" to the operation string. I'd just make all the pink into alpha before the game starts, instead of converting it to a new bitmapData everytime something is drawn. The dis- and advantages I see in this method are: less memory usage, a small loading time. I haven't tried this method yet, as I was kind of lazy in just letting Flash handle it and just used transparent PNG's.


Do you have any other resources? I think I found enough code to get started with in the AS3 cookbook, but I'll check out your render class in the other thread as I go too. Thanks!

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

doomtoo
August 21st, 2009, 04:42 PM
Cool, thanks guys!

Do you guys make a main loop/ onEnterFrame to redraw the bitmap each time, or have some kind of timer?

I've been using onEnterFrame to update everything, and thats the only reasonable way I can see of updating the stage/bitmap/objects - What do you do?

Gnoll
August 21st, 2009, 06:35 PM
I never really finished it but my "AnimatableBitmapSprite" uses only a single bitmapdata, I think you are right I wasn't using references as I should.

Gnoll

therobot
August 21st, 2009, 06:56 PM
Cool, thanks guys!

Do you guys make a main loop/ onEnterFrame to redraw the bitmap each time, or have some kind of timer?

I've been using onEnterFrame to update everything, and thats the only reasonable way I can see of updating the stage/bitmap/objects - What do you do?

You can use a timer if you want, but that is ultimately tied to your framerate. Because of this, onEnterFrame is really the best way to get the most performance out of the flash player ;)

Gnoll
August 21st, 2009, 07:35 PM
No point doing the blitting outside of an enterFrame but I personally still like to keep my logic in a timer.

Gnoll

doomtoo
August 22nd, 2009, 07:36 PM
I've been loading my images externally using a Loader, then I am able to add the loader to the stage directly.

With copying to the bitmapdata, I have to convert the loader to a bitmap, then to a bitmapdata before I can use it, and I also have to keep doing it until the loader no longer==null - so that it has loaded.

So for every item, besides having a loader, they will need a bitmap and a bitmapdata object, as well as a listener for "oncomplete" of the loader before converting it to a bitmapdata?

Also, with scrolling, if something was off screen, it would still be completely rendered- with the copy pixel method, do you have to check how much of an object will be on screen, and just make the rectangle for the amount on screen, or will it be fine copying to the canvas partially?

Thanks!

TOdorus
August 22nd, 2009, 08:08 PM
With copying to the bitmapdata, I have to convert the loader to a bitmap, then to a bitmapdata before I can use it, and I also have to keep doing it until the loader no longer==null - so that it has loaded.

Isn't there an event for that? Ah you mention that in your next quote :)


So for every item, besides having a loader, they will need a bitmap and a bitmapdata object, as well as a listener for "oncomplete" of the loader before converting it to a bitmapdata?

Well the bitmap holds a bitmapdata object. So you could just do a


var enemySprite:bitmapData
enemySprite = enemySpriteLoader.bitmapData
enemySpriteLoader = null




Also, with scrolling, if something was off screen, it would still be completely rendered- with the copy pixel method, do you have to check how much of an object will be on screen, and just make the rectangle for the amount on screen, or will it be fine copying to the canvas partially?

That's why you build in a check. Every enemy should have a width and height property to have a bounding rectangle (I suggest using just one that always encompasses the whole graphic no matter what frame or rotation). Copypixels is so efficient that I wouldn't be doing the trouble of calculating what part of the graphic is onscreen. Basicly you'll be doing some calculations PLUS the copypixel. Just check against the rectangle of the screen for overlap of the bounding rectangle and if they intersect (the bounding rectangle is onscreen) render the character.

Gnoll
August 22nd, 2009, 08:16 PM
Also, with scrolling, if something was off screen, it would still be completely rendered- with the copy pixel method, do you have to check how much of an object will be on screen, and just make the rectangle for the amount on screen, or will it be fine copying to the canvas partially?


It is just like copying bytes to another spot, but there is nowhere to put them if it is outside of the width/height of the bitmapdata. I wonder if it causes any overhead attempting to copypixels to nowhere.

Gnoll

TOdorus
August 22nd, 2009, 08:24 PM
I wonder if it causes any overhead attempting to copypixels to nowhere

Yes.

(experience is a harsh mistress)

Gnoll
August 22nd, 2009, 08:52 PM
:D

Do you know if it is worse then a legitimate copypixel?

Gnoll

doomtoo
August 22nd, 2009, 08:52 PM
Ok, cool, thanks again guys! TOdorus -

Yes.

(experience is a harsh mistress) you mean by copying everything, not just ones that intersect slightly at the edges? (like if 1/2 a tile is offscreen, it should be fine, but copying every tile, even if 1000tiles are offscreen will be slow?)

TOdorus
August 22nd, 2009, 09:08 PM
:D

Do you know if it is worse then a legitimate copypixel?

Gnoll

I know that the check gave me some CPU, so it was a valid optimization. Never tested if a usefull copypixels differs from a useless copypixels (I hope to think Adobe optimized this, but I've been dissapointed in the past). Still if eliminating copypixels just by checking a bounding box saves up speed, I don't find reason to check if that case would give a result between the other two. So if Adobe actually did optimize it, your own check is more efficient (yeah that sounds like Adobe).


you mean by copying everything, not just ones that intersect slightly at the edges? (like if 1/2 a tile is offscreen, it should be fine, but copying every tile, even if 1000tiles are offscreen will be slow?)

Well copypixels is lightning fast, so even a 1000 executions won't really halt your engine. I've got good reason to believe that distance checks are a lot more expensive then copypixels, so your rendering actually becomes cheaper then your collision detection by using copypixels (eat that movieClip). It is a significant optimization to use the check though (forgot the numbers as it was obvious from the first test it was my way to go), so it's a good idea to implement it anyway.

doomtoo
August 23rd, 2009, 03:13 PM
Awesome, thanks again guys, I'll be able to convert it semi-easily from using the stage, and finally have proper control over "rendering order"!

Next step will be to explore loading sprite sheets/animations, but I think with this method, I could just load an animation sheet, and just keep changing the srcRect to select a different pose- like I could do in directx/C++.

Thanks!!

doomtoo
August 23rd, 2009, 05:18 PM
Actually a couple more questions. I have an updated/dynamic textfield on screen- how do I copy that onto the bitmapdata structure?

Also, how do you draw vector graphics on it? Like if I have a series of lines making a dynamic shapes, could I just copy pixel them?

Gnoll
August 23rd, 2009, 06:24 PM
myBitmapData.draw(vectorGraph);

TOdorus
August 23rd, 2009, 07:27 PM
draw is a bit more expensive operation, so if you plan to do this over multiple frames, you might first want to convert it to a bitmapData and copypixel from that bitmapdata.

psuedocode


myBitmapData = new bitmapData()
myBitmapData.draw(vectorGraph)
canvas.copypixel(mybitmapData)

doomtoo
August 23rd, 2009, 07:44 PM
ok cool, good idea, but to copy the textfield would be the same "draw" function?

And yeah, I would only use the vector graphics for a small time, but once they are finalized, they won't need to be edited anymore, and I could copy them over to a bitmap- but didn't know you had to use "draw"- I almost got everything rendering the same as before, but proper depth!

doomtoo
August 23rd, 2009, 09:02 PM
Ok. it did work- but there was a problem.

If I tried to copy the text to a surface using draw, then a copy pixel to the canvas BitmapData, then the text no longer has transparency. Any way to fix this?

I also just used "draw" directly to the canvas, using a matrix to "translate" it into the position I wanted, but would like to know how to do the previous way as well.