Copy link to clipboard
Copied
Hello everyone. Here is a simple package with DepthManager, the question is in performance of it.
1) Create .fla AS3, size = 600x400, grey background.
2) Create in library a MovieClip, named THING, linkage = THING, and open it. Draw a 15-corner star in the centre of it. Fill by standart from-black-to-white linear gradient.
3) Set the name MAIN as main class of the document (don't forget save them all in one directory), open it, and paste there this code:
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
public class MAIN extends MovieClip
{
public var array_THINGS:Array = new Array();
public function MAIN()
{
var tmp_thing:MovieClip;
//BECAUSE I'M NOT GOING TO REMOVE THIS, I CAN USE ANONYMOUS FUNCTION
stage.addEventListener(MouseEvent.MOUSE_UP, function()
{
//WE WILL CREATE SOME THINGS TO DISPLAY
for(var i = 1; i <= 100; i++)
{
tmp_thing = new THING();
tmp_thing.x = Math.random() * 600;
tmp_thing.y = Math.random() * 400;
//LETS MAKE IT EASIER FOR PLAYER BY SETTING cacheAsBitmap TO true
tmp_thing.cacheAsBitmap = true;
addChild(tmp_thing);
array_THINGS.push({INSTANCE:tmp_thing});
}
});
stage.addEventListener(Event.ENTER_FRAME, function()
{
ENTER_FRAME_1(); //USING DepthMan
//ENTER_FRAME_2(); //NOT USING DepthMan
//MAKE ONE OF THOSE FUNCTIONS IN // TO SEE THE DEFFERENCE IN FRAMERATE
});
}
private function ARRAY_THINGS_GET_POS_OF_OBJECT(element:*, index:int, arr:Array)
{
var thing_x = MovieClip(element.INSTANCE).x;
var thing_y = MovieClip(element.INSTANCE).y;
return {INSTANCE:element.INSTANCE, X:thing_x, Y:thing_y};
}
private function ENTER_FRAME_1()
{
var array_DETAILED_THINGS:Array = array_THINGS.map(ARRAY_THINGS_GET_POS_OF_OBJECT);
array_DETAILED_THINGS.sortOn(["Y", "X"], [Array.NUMERIC, Array.NUMERIC | Array.DESCENDING]);
for(var i in array_DETAILED_THINGS)
{
var tmp_mc:MovieClip = MovieClip(array_DETAILED_THINGS.INSTANCE);
tmp_mc.rotation += 7;
tmp_mc.parent.setChildIndex(tmp_mc, i);
}
}
private function ENTER_FRAME_2()
{
for(var i in array_THINGS)
{
var tmp_mc:MovieClip = MovieClip(array_THINGS.INSTANCE);
tmp_mc.rotation += 7;
}
}
}
}
We click stage = we create 100 stars, each is rotated every frame.
Each frame the function ARRAY_THINGS_GET_POS_OF_OBJECT gets the position of the INSTANCE (it's a simple example, imagine that things may move, so the constant position will not suite).
Then things are sorted and reindexed.
Code works.
The main problem is:
With the ENTER_FRAME_1() turned ON (and ENTER_FRAME_2() turned off, ofcourse), the framerate is much lower, when 300 things (3 clicks) and more on the stage. We don't have so big decline, not using DepthManager (ENTER_FRAME_1() turned OFF and ENTER_FRAME_2() turned ON). And I don't even mention, that a star has not much dots to draw. So the problem is in setting indexes, or may be even in Array.map().
The tip is:
There is a way to use swapDepths, adding an EnterFrame function to each thing, which will "understand", if the thing is higher or lower(.y) from its neighbours, whose depths +1, -1. So it will be one check but by each star...
The question is:
Will it work faster? Or there is another way to make all this RUN?)
yes that is all the code
as3 can sort arrays of objects on properties of those objects
e.g. if you push 3 sprites into an array you can sort those sprites based any property of Sprite x, y, alpha, etc
Copy link to clipboard
Copied
No one used dynamic depth manager? Nobody wrote code for games?
Copy link to clipboard
Copied
I only write code for games and no I have never used a dynamic depth manager
for ENTER_FRAME_1 why do you sort the MoiveClips every frame? surely you could just do this each time the MovieClips are added in your mouse listener?
also it would be a good idea to profile your code to find out where the bottleneck is
and whether the swapDeths will be faster or not well the best way would be to try it and find out
Copy link to clipboard
Copied
also you are creating a new object for each star each frame this is not good
I'd recommend subclassing MovieClip and have the result of ARRAY_THINGS_GET_POS_OF_OBJECT cached for each object
this would stop the creation of hundreds of objects every frame and well as the overhead for the map() function
i bet this is where the main loss of performance is
Copy link to clipboard
Copied
I have actually had a chance to play around with it now
and with 400 stars my ENTER_FRAME_1() runs at 10 fps and so does ENTER_FRAME2()
I am using
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
public class MAIN extends MovieClip
{
public var array_THINGS:Array = new Array();
private var stats:Stats = new Stats();
public function MAIN()
{
stage.addEventListener(MouseEvent.CLICK, mouseUpHandler);
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
private function mouseUpHandler(e:MouseEvent):void
{
var tmp_thing:THING;
//WE WILL CREATE SOME THINGS TO DISPLAY
for (var i = 1; i <= 100; i++)
{
tmp_thing = new THING();
tmp_thing.x = Math.random() * 600;
tmp_thing.y = Math.random() * 400;
//LETS MAKE IT EASIER FOR PLAYER BY SETTING cacheAsBitmap TO true
tmp_thing.cacheAsBitmap = true;
addChild(tmp_thing);
array_THINGS.push(tmp_thing);
}
array_THINGS.sortOn(["y", "x"], Array.NUMERIC | Array.DESCENDING);
for (var j in array_THINGS)
{
var tmp_mc:THING = THING(array_THINGS
); tmp_mc.parent.setChildIndex(tmp_mc, j);
}
addChild(stats);
}
private function enterFrameHandler(e:Event):void
{
ENTER_FRAME_1(); //USING DepthMan
//ENTER_FRAME_2(); //NOT USING DepthMan
//MAKE ONE OF THOSE FUNCTIONS IN // TO SEE THE DEFFERENCE IN FRAMERATE
}
private function ENTER_FRAME_1()
{
for (var i in array_THINGS)
{
var tmp_mc:THING = THING(array_THINGS);
tmp_mc.rotation += 7;
}
}
private function ENTER_FRAME_2()
{
for (var i in array_THINGS)
{
var tmp_mc:THING = THING(array_THINGS);
tmp_mc.rotation += 7;
}
}
}
}
and a copy of MrDoobs stats class
/**
* stats.as
* https://github.com/mrdoob/Hi-ReS-Stats
*
* Released under MIT license:
* http://www.opensource.org/licenses/mit-license.php
*
* How to use:
*
* addChild( new Stats() );
*
**/
package {
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Matrix;
import flash.geom.Rectangle;
import flash.system.System;
import flash.text.StyleSheet;
import flash.text.TextField;
import flash.utils.getTimer;
public class Stats extends Sprite {
protected const WIDTH : uint = 70;
protected const HEIGHT : uint = 100;
protected var xml : XML;
protected var text : TextField;
protected var style : StyleSheet;
protected var timer : uint;
protected var fps : uint;
protected var ms : uint;
protected var ms_prev : uint;
protected var mem : Number;
protected var mem_max : Number;
protected var graph : BitmapData;
protected var rectangle : Rectangle;
protected var fps_graph : uint;
protected var mem_graph : uint;
protected var mem_max_graph : uint;
protected var colors : Colors = new Colors();
/**
* <b>Stats</b> FPS, MS and MEM, all in one.
*/
public function Stats() : void {
mem_max = 0;
xml = <xml><fps>FPS:</fps><ms>MS:</ms><mem>MEM:</mem><memMax>MAX:</memMax></xml>;
style = new StyleSheet();
style.setStyle('xml', {fontSize:'9px', fontFamily:'_sans', leading:'-2px'});
style.setStyle('fps', {color: hex2css(colors.fps)});
style.setStyle('ms', {color: hex2css(colors.ms)});
style.setStyle('mem', {color: hex2css(colors.mem)});
style.setStyle('memMax', {color: hex2css(colors.memmax)});
text = new TextField();
text.width = WIDTH;
text.height = 50;
text.styleSheet = style;
text.condenseWhite = true;
text.selectable = false;
text.mouseEnabled = false;
rectangle = new Rectangle(WIDTH - 1, 0, 1, HEIGHT - 50);
addEventListener(Event.ADDED_TO_STAGE, init, false, 0, true);
addEventListener(Event.REMOVED_FROM_STAGE, destroy, false, 0, true);
}
private function init(e : Event) : void {
graphics.beginFill(colors.bg);
graphics.drawRect(0, 0, WIDTH, HEIGHT);
graphics.endFill();
addChild(text);
graph = new BitmapData(WIDTH, HEIGHT - 50, false, colors.bg);
graphics.beginBitmapFill(graph, new Matrix(1, 0, 0, 1, 0, 50));
graphics.drawRect(0, 50, WIDTH, HEIGHT - 50);
addEventListener(MouseEvent.CLICK, onClick);
addEventListener(Event.ENTER_FRAME, update);
}
private function destroy(e : Event) : void {
graphics.clear();
while(numChildren > 0)
removeChildAt(0);
graph.dispose();
removeEventListener(MouseEvent.CLICK, onClick);
removeEventListener(Event.ENTER_FRAME, update);
}
private function update(e : Event) : void {
timer = getTimer();
if( timer - 1000 > ms_prev ) {
ms_prev = timer;
mem = Number((System.totalMemory * 0.000000954).toFixed(3));
mem_max = mem_max > mem ? mem_max : mem;
fps_graph = Math.min(graph.height, ( fps / stage.frameRate ) * graph.height);
mem_graph = Math.min(graph.height, Math.sqrt(Math.sqrt(mem * 5000))) - 2;
mem_max_graph = Math.min(graph.height, Math.sqrt(Math.sqrt(mem_max * 5000))) - 2;
graph.scroll(-1, 0);
graph.fillRect(rectangle, colors.bg);
graph.setPixel(graph.width - 1, graph.height - fps_graph, colors.fps);
graph.setPixel(graph.width - 1, graph.height - ( ( timer - ms ) >> 1 ), colors.ms);
graph.setPixel(graph.width - 1, graph.height - mem_graph, colors.mem);
graph.setPixel(graph.width - 1, graph.height - mem_max_graph, colors.memmax);
xml.fps = "FPS: " + fps + " / " + stage.frameRate;
xml.mem = "MEM: " + mem;
xml.memMax = "MAX: " + mem_max;
fps = 0;
}
fps++;
xml.ms = "MS: " + (timer - ms);
ms = timer;
text.htmlText = xml;
}
private function onClick(e : MouseEvent) : void {
mouseY / height > .5 ? stage.frameRate-- : stage.frameRate++;
xml.fps = "FPS: " + fps + " / " + stage.frameRate;
text.htmlText = xml;
}
// .. Utils
private function hex2css( color : int ) : String {
return "#" + color.toString(16);
}
}
}
class Colors {
public var bg : uint = 0x000033;
public var fps : uint = 0xffff00;
public var ms : uint = 0x00ff00;
public var mem : uint = 0x00ffff;
public var memmax : uint = 0xff0070;
}
Copy link to clipboard
Copied
Unfortunately my simple example doesn't show all the necessity of dynamic listening the actual position of each star, so I've mentioned imagine that things may move.
In fact, the example is too abstract. In the real code game, the stars are the pieces of grass on the ground. So we might use NOT dynamic DeMan. But also I have people, who move on that ground (walk), so depths should be always changed. So each frame AMV2 should understand, where is the thing, then sort the array of their pos... framerate falls down quickly, though flashPlayer easily processes 500+ "things" when DeMan is not used.
Copy link to clipboard
Copied
reimplementing the sort to happen every frame still shows little degradation in frame rate:
private function mouseUpHandler(e:MouseEvent):void
{
var tmp_thing:THING;
//WE WILL CREATE SOME THINGS TO DISPLAY
for (var i = 1; i <= 100; i++)
{
tmp_thing = new THING();
tmp_thing.x = Math.random() * 600;
tmp_thing.y = Math.random() * 400;
//LETS MAKE IT EASIER FOR PLAYER BY SETTING cacheAsBitmap TO true
//tmp_thing.cacheAsBitmap = true;
addChild(tmp_thing);
array_THINGS.push(tmp_thing);
}
}
private function ENTER_FRAME_1()
{
array_THINGS.sortOn(["y", "x"], Array.NUMERIC | Array.DESCENDING);
for (var i in array_THINGS)
{
var tmp_mc:THING = THING(array_THINGS);
tmp_mc.rotation += 7;
tmp_mc.parent.setChildIndex(tmp_mc, i);
}
addChild(stats);
}
Copy link to clipboard
Copied
Are you sure, that it is all code? I'm confused:
array_THINGS.sortOn(["y", "x"], Array.NUMERIC | Array.DESCENDING);
Can AS3 check and sort properties, which are not in array? Because you hadn't pushed .x and .y to array_THINGS.
Copy link to clipboard
Copied
yes that is all the code
as3 can sort arrays of objects on properties of those objects
e.g. if you push 3 sprites into an array you can sort those sprites based any property of Sprite x, y, alpha, etc
Copy link to clipboard
Copied
array_THINGS.sortOn(["y", "x"], Array.NUMERIC | Array.DESCENDING);
Not using Arrray.map() removes almost half of calculations!
Thank you very much for your help, _spoboyle!
Just tell me one last thing. I never knew about
. From where you had found out that?) There are no such examples in reference/actionscript/3, and I never heard about that in AS2...
if you push 3 sprites into an array you can sort those sprites based any property of Sprite
Copy link to clipboard
Copied
the documentation for Array.sortOn() does give an example showing this
instead of using sprites it uses a custom class called vegetable which has 2 properties name and price and the example sorts on price
this is the same method and have Sprites and sorting on y for example
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Array.html#sortOn()
Copy link to clipboard
Copied
Ou, now I get it) There were used user-defined properties, so I didn't thought of standart properties like x, y, alpha.
THANK YOU FOR YOUR HELP, _spoboyle