Optimization of HaxeFlixel

1,788 views
Skip to first unread message

kurismakku

unread,
Dec 21, 2013, 9:11:53 AM12/21/13
to
Hey everyone !

I am optimizing my game and I believe I found some problems in HaxeFlixel. I wanted to ask about this so that I see what was the reasons that it was done this way because maybe this stuff is really needed, but because I am not expert in HaxeFlixel structure, I don't see it.

1) In FlxSprite constructor makeGraphics is always called, and in most cases user will call makeGraphic or loadGraphic again. Situation with FlxText is not better because makeGraphic is also called in constructor of FlxText which results in 2 times calling makeGraphics even though this is called 3rd time when actual text is set.

2) Why all sprites have AnimationController even if the sprite doesn't have animations ?

3) Why is caching set as mandatory ? Set and get cache key etc is called every time pixels are changed, and this is not needed, for example in case when someone wants to directly manipulate pixels BitmapData, like in my case where I was calling  pixels = new BitmapData(...). Not sure is this error with caching because every time get cache was called even though it didn't have any result, and it made also game slower every time this happened because CachedGraphics wasnt' properely destroyed ( cause I was setting pixels with  pixels = new BitmapData( ... ) ...

I fixed above 3, and so far I didn't encounter any bugs, and game is running faster.

4) Is there any way to avoid updateFrameData() ?  It is slow, and I am not sure is it even needed since I have simple sprite, I don't have texture or sprite sheet... I want to set pixels with new BitmapData( ... ) so my question is could this be done in simpler way ?

- for 1) to 4) : 
Testing with Adobe Scout in some frames I had 12000+ allocations when objects was created which made  the game lag a lot.  I also encountered on some other places that stuff is called just so that there is no bugs, I believe this could be fixed in some other ways with checking is something null, and changing actions depending is it or is not...

5) When I use big object and I change the scale (  to lower or higher amount ) it slows the game a lot. I believe this is not problem with HaxeFlixel, but with bitmapData.draw method, so I wanted to ask for advice, what should I do about this. If scaling was animated would that be faster ? 
This is the art I am using : https://dl.dropboxusercontent.com/u/63196046/propeler.png

6) I also fixed some other problems like in recycle Std.is is used which results in slower recycling, this can be fixed by having arrays of objects that contain only specific object types.

7) Also, does it seems to me or recycle doesn't really work when MaxSize is set to bigger then 0 because it doesn't take in account what type of object you want to recycle, it always recycle the next one in the array ?

8) Is it smart to have FlxSprites as variables in other FlxSprite, and then in draw method of that FlxSprite call draws of other FlxSprite that are members of it ?  I am not adding those FlxSprites anywhere so their update is not called ( not sure is this okay ? ), and also their draw is called only once. Here is a screenshot of case like this :
https://dl.dropboxusercontent.com/u/63196046/draw.png   Notice the big memory, and notice that the next frame it is everything okay. How is this possible ? Shouldn't drawing have constant performanse if nothing is changed ?  

Thanks for reading, answers, and big thank you for awesome framework !!!  I am working now on sequel of Sudden Aviator, and comparing to AS3 Flixel the game is running at least 2 times faster even though in sequel I have much more objects on the screen, and game is more complex. :)

kurismakku

unread,
Dec 21, 2013, 3:22:56 PM12/21/13
to
9)  If I remember well onScreen is slow ?  In most of the programs all sprites are usually on the screen all the time since they don't move or anything, example is the HUD or player.  In FlxSprite draw() every frame it is checked is object on screen by calling onScreen method, if it is not on screen the object is not drawn. It would be good to have a variable which when set to true skips onScreen checking in draw() method.  Also, the standard onScreen method used for drawing should be simpler while there should be other function for checking onScreen that takes in consideration rotation, scale and other parameters.

Gama11

unread,
Dec 21, 2013, 4:57:02 PM12/21/13
to haxef...@googlegroups.com
Thanks for your thoughtful post!

(not answering to all points)

1) I agree with you on the FlxSprite loadGraphic() call - it's mainly a leftover from Flixel AS3 and for debugging purposes I guess (when loading a graphic has failed for whatever reason).  I'm not sure how expensive the call really is, but in case of FlxText it really is totally unnecessary, but hard to avoid due to inheritance without removing the call from the FlxSprite constructor.
Not sure what you mean by "when actual text is set" - FlxText.text is usually set in the constructor.

2) For version 3.0.0, the animation logic has been moved out of FlxSprite, but is of course still intertwinded. A while ago the idea of creating a more basic version of FlxSprite came up, since not every sprite needs animations etc, but it hasn't been implemented yet. Seperating all the (rendering) logic is not an easy task.

5) FlxSprite has a function called simpleRenderSprite(), and it becomes true as soon as you use angle without baked rotations, scale or blend modes. "Complex rendering" is done via .draw() and is about 10 times slower than the usual copyPixels(). The only way to have fast scaling in flash would be stage3D, which might eventually be integrated. Animations would probably be a lot faster, yes.

6) Are you refering to FlxTypedGroup.recycle()? For groups that only have instances of a specific class, you should use FlxTypedGroup<SpecificClass> for type safety instead of FlxGroup (which is a FlxTypedGroup<FlxBasic>).

7) Have you read the documentation of recycle()?

If you specified a maximum size for this group (like in </code>FlxEmitter</code> ),
then recycle will employ what we're calling "rotating" recycling.
<code>recycle()</code> will first check to see if the group is at capacity yet.
If group is not yet at capacity, recycle() returns a new object.
If the group IS at capacity, then recycle() just returns the next object in line.

It seems that the implementation assumes you would use fixed group sizes + recycle() only for groups containing objects of the same class.

9) I don't think onScreen() is that expensive, compared to drawing the sprite. You could try playing around with FlxBunnyMark. You're probably right that in most games it wouldn't be necessary, it really depends from case to case though. A flag to skip the check seems like a sensible option to me, allowing experienced users who know what they are doing to improve their game's performance.

Beeblerox

unread,
Dec 22, 2013, 2:27:05 AM12/22/13
to
Hello and thanks for your opinion about perfomance optimizations ways. Most of them (regarding graphics) are due to my work with which i wanted to unify native and flash codebase.
about question 1-4: you get new object allocations on flash due to bitmap buffer "optimization" which main idea is to hold sprite's frame bitmapdata and transform it according to sprite's color and alpha, so if you want to avoid it then you won't be able to change sprite's color and alpha. Please tell me if you want to have such sprite (with limited functionality)

About sprite's animation controller: you're right that it should be created only on user's demand, i will try to work on it on holydays.
about automatic call of loadGraphic(): it was added to be sure that sprite have some graphics to be drawn. i can remove it but it will add one new check in draw() method.

To automaticall destroy unneeded cached graphics you'll need to set something like: sprite.cachedGraphics.destroyOnNoUse = true;

Scaling is very slow on flash target especially for big bitmaps and i cannot advice anything about it, sorry

kurismakku

unread,
Dec 22, 2013, 10:18:26 AM12/22/13
to
Here is the data from 100 frames from my game inside of the level :

https://dl.dropboxusercontent.com/u/63196046/cpu.png
https://dl.dropboxusercontent.com/u/63196046/memory%20allocs.png

Adobe Scout profile file of my game : https://dl.dropboxusercontent.com/u/63196046/RC%20profile.flm

Note that PC on which I am testing the game is not really good.  My 5 years old laptop ( that was average when I bought it ) have better frame rate then this.
Most of the time is wasted on the draw stuff because I have some sprites colored, some of them use alpha, and I noticed too many of them uses blending even it is almost not noticeable, so I am on my way to fix that now. Maybe in the end this game will run good on mobile phones, that would be amazing. :)  HTML5 is another dream !

@Gama11

1) I agree that it is rare that someone doesn't set text in constructor, but it happens. What I mean is that there is no need to create graphics if text in constructor is empty ( null or "" ).

6) Yes, I am using FlxTypedGroup, but still recycle checks the object type with Std.is so I made simpler method called  recycleFromThis.

7) Ok, gotcha, I didn't read the docs so it seemed weird. :)

@Beeblerox

Yes, I would like to have that type of sprite, specially if there would be way to avoid updateFrameData which is making problem because I make lot of sprites at once, and I set their bitmap data by splitting some bigger bitmap data. To be more precise, my enemies explode into pieces.

"To automaticall destroy unneeded cached graphics you'll need to set something like: sprite.cachedGraphics.
destroyOnNoUse = true;"
Good you mentioned this, I started using persist cause I have static arrays of objects that are used in every level and this method in BitmapFrontEnd was disabling me do that :

public function clearCache():Void
   
{
       
var obj:CachedGraphics;
       
       
if (_cache == null)
       
{
            _cache
= new Map();
       
}

       
for (key in _cache.keys())
       
{
            obj
= _cache.get(key);
           
if ((obj != null && !obj.persist) && inOpenFlAssets(obj.bitmap) == false)
           
{
                _cache
.remove(key);
                obj
.destroy();
                obj
= null;
           
}
       
}
   
}

10)
So instead of using persist I should add flag to this method, and use "destroyOnNoUse" ?  In case that pixels are changed I can then destroy cachedGraphics, remove it from cache, and then set it again. 

When I keep objects in static array I am not sure why after state switching animations don't work anymore, but I get error here :
_sprite.frame = _sprite.framesData.frames[Frame];
Inside of  set_frameIndex(Frame:Int):Int in FlxAnimationController.  I don't them add them to the state or to any other group, I call their draw() method only inside of the draw method of their parent.

11)
One more thing that I am doing with some sprites, specially for special effects when it is possible ( like for example if each missile have one trail ) is that I have only one instance of object but I draw it multiple times, once for each missile inside of draw() of missile.  This way the sprites are grouped nicely together, and there is no problems with sprites draw order for example that some other sprite comes between missile and trail.  Is this good or it slowers the game somehow in some way that I don't see ?


As for scaling, I am gonna try to see is it possible to animate this stuff. OR :
12)
What if scaling could be cached ? For each scale increment create a new bitmapdata that copies the current state of sprite. Then after you just need to draw the right bitmapdata depending on the current value of scale ?  The only thing I am not sure is can you create bitmapdata that takes the current scale in account.

I am glad I could help somehow, and thank you for the answers ! :)

Beeblerox

unread,
Dec 22, 2013, 7:41:20 AM12/22/13
to haxef...@googlegroups.com
Your answer showed me that there is logical error in BitmapFrontEnd class, i'll try to fix and answer you later

kurismakku

unread,
Dec 23, 2013, 4:31:23 AM12/23/13
to haxef...@googlegroups.com
Most of the execution time in my game is spent on rasterizing edges, to be precise it takes 50% of total execution time.  Is there any way to optimize this ?

Beeblerox

unread,
Dec 23, 2013, 12:04:43 PM12/23/13
to haxef...@googlegroups.com
What do you mean by "rasterizing edges"? i don't understand this term. Is it the problem with updateFrameData() and call of loadGraphic() in the constructor you told earlier?

Samuel Batista

unread,
Dec 23, 2013, 11:35:56 PM12/23/13
to haxef...@googlegroups.com
This is Flash doing its rendering. The only way to optimize this is to remove alpha and scaling from your BitmapData objects (make them "simple renders").

Here's an excerpt from Adobe's documentation which you can find here: http://www.adobe.com/devnet/scout/articles/understanding-flashplayer-with-scout.html

"Rasterizing edges – Flash Player now has to convert the edges and colors into actual pixels. It divides the dirty region into horizontal lines called scan lines, one for each vertical pixel. The scan lines get shared out among the cores on your machine. Flash Player walks along each scan line, figuring out what color to shade each pixel, based on the fill for the area between the edges that bound it. The time this takes depends on the number of pixels, and the cost of drawing each pixel. Solid colors are the least expensive to draw, whereas rotated and scaled bitmaps with multiple layers of alpha blending can be pretty costly!"

kurismakku

unread,
Dec 31, 2013, 7:33:40 AM12/31/13
to
In case when we have static animations ( for example when one weapon have 10 looks so depending on type of weapon the right frame is set ) is it maybe faster to not have animation at all, but instead have 10 pieces of graphics that we load depending on type   ?  Sometimes the frame changes during gameplay for example if player picks up super powerup the weapon costume changes to super for few seconds - in this case I could just have 2 FlxSprites that I switch by changing exists property to  true / false , is this faster then using play() method ?
One more reason why this could be better is because in that case I can use loadRotatedGraphic so if only transformation is changing angle I could have simple rendering instead of complex one.

Question about cachedGraphics : should I use persist often ?  Why is persist not set as true for all cases when graphic is loaded via loadGraphic, wouldn't this speed up the game ?

Also, what is the difference between destroyOnNoUse and persist ?

kurismakku

unread,
Jan 21, 2015, 6:24:18 AM1/21/15
to haxef...@googlegroups.com
Hey everyone ! :)

We are still working on this game, and I think we are finally finishing it really soon !

So I am again working on optimization, and I am wondering how much HaxeFlixel's performance changed since this thread was opened ?
I as I described, I did change my version of HaxeFlixel to fix lot of problems above, but it was done in hacky way.

Basically if I would want to use newer version of HaxeFlixel, I would probably need to change a lot of stuff, so I am wondering is it worth the effort ?
The highest hit on performance is still "rasterizing edges".

Since my game have lot of special effects, does anyone have suggestion how particles could be optimized ?
Of course I am using pooling already.

SruloArt

unread,
Jan 21, 2015, 6:50:10 AM1/21/15
to haxef...@googlegroups.com
1. Not really. It sounds like you just have a lot of graphics on screen on the same time, so you won't benefit much from upgrading to 4.0.0 dev (which is cool but not magical).
2. Particles would explain why you're having that problem, and the best trick for that is to use an animation sequence instead of the real particles.
3. If your particles can't be replaced with animation you should re-design your game. Another trick is to use bigger particles so you actually have less graphical objects on screen and less logic.

kurismakku

unread,
Jan 22, 2015, 9:33:41 AM1/22/15
to
I optimized lot of stuff by using prerotated graphics, and removing where I could changing alpha, shadows, scaling etc.

But some of the sprites have animation so I tried using FlxSpriteAniRot, but I didn't get much better performance. Usually when I use loadRotatedGraphic I get almost 5 times better performance, and with FlxSpriteAniRot I get maybe 0.1-0.2x better performance. I mean this would be okay I guess if this animations was real animations, but I am using only one frame all the time ! 


Maybe the mistake is that I added Width and Height parameter to FlxSpriteAniRot ? 
super(Data.ImgPlayerMissile, 360, 26, 13 ); 
animation.add( "missile1", [0, 1, 2, 3, 4, 5]);
animation.play("missile1");

Here is the version of FlxSpriteAniRot I am using : http://pastebin.com/560U3ar0
Reply all
Reply to author
Forward
0 new messages