[haXe] Animation performace issues

edA-qa mort-ora-y eda-qa at disemia.com
Sat Aug 25 12:26:23 CEST 2007


I have several answers that may help.

1. Don't use updateAfterEvent.  I know every site says this is a good
thing, but I've actually seen better performance by just setting the
framerate higher.  That is, just take 30FPS, and whatever timer you
want, and the animation will be smoother.

2. That said, 10ms timer is a little low, and you are likely only
getting a 40-50ms timer.  Choose about 50ms (that is how my Palisaro
game works and the animation is smooth there)

3. Your Collision detection is the likely long-term slow-down, it is
consuming an *extreme* amount of memory.  I have a class which does this
and cache's the bitmaps (no excessive allocation).  This had shown
significant performance improvements in Palisaro.  I'm happy to make
this available to you.

4. MovieClip vs. Sprite.  None of your shot objects actually need a
MovieClip, and Sprite would be better suited to that (perhaps the
MovieClip is adding overhead that is slowing down your code)

5. You should never need to assign null or do a deleteField for the
purpose of freeing memory -- not to mention that it likely doesn't even
achieve that.

Jaevla Faenskap wrote:
> Hi all,
> 
> I'm totally new to flash and actionscript development, so I might be way off here.. However I was hoping you could help me a bit with a few issues I'm having.
> 
> This might be a little more general actionscript than haxe specifically, I'm not sure - I've only used haxe so far (and I think it's a great project!).
> 
> It might be a little long, but I decided to include all my code (it's (almost) a small game). Let me know if I should have posted it some other way. I am targeting Flash9 (AS3).
> 
> Anyway, on to the questions.. The problems I am having is with animation. All the games I have seen have really smooth movement. Mine not so. I'm using a timer for updating positions (so it will run at the same speed independent of framerate), and I use an updateafterevent(). But still when I move my player-controlled clip I see a lot of stuttering - no matter what framerate I run it on. What's the magic trick I am missing?
> 
> Also, if I let the "game" run, it just keeps on slowing down. I guess that this is because of my shots not beeing properly deleted somehow when they move out of the screen - even tough I set them to null. I've also tried Reflect.deleteField() - to no avail (though I couldn't find any documentation on what the string was supposed to be?).
> 
> I hope I'm not asking too much, and that someone with the knowledge and kindness will step up?
> 
> 
> Cheers
> 
> 
> --- CODE FOLLOWS ---
> import flash.display.StageScaleMode;
> import flash.display.Bitmap;
> import flash.display.BitmapData;
> import flash.display.MovieClip;
> import flash.display.Sprite;
> import flash.events.Event;
> import flash.events.KeyboardEvent;
> import flash.events.TimerEvent;
> import flash.geom.ColorTransform;
> import flash.geom.Rectangle;
> import flash.Lib;
> import flash.net.ObjectEncoding;
> import flash.ui.ContextMenu;
> import flash.utils.Timer;
> import flash.display.BlendMode;
> import haxe.Timer;
> 
> class Mob extends MovieClip
> {
>   public var direction:String;
>   public function new()
>   {
>     super();
>     
>     this.graphics.beginFill(0x555555);
>     this.graphics.drawCircle(32,32,32);
>     this.graphics.endFill();
> 
>     direction = "RIGHT";
>   }
> }
> class Shot extends MovieClip
> {
>   public var speed:UInt;
>   public function new()
>   {
>     super();
>     
>     this.graphics.beginFill(0xff0000);
>     this.graphics.drawCircle(8,8,8);
>     this.graphics.endFill();
>     
>     this.speed = 4;
>   }
> }
> class MobShot extends MovieClip
> {
>   public var speed:UInt;
>   public function new()
>   {
>     super();
>     
>     this.graphics.beginFill(0xff0000);
>     this.graphics.drawRect(0,0,3,6);
>     this.graphics.endFill();
>     
>     this.speed = 2;
>   }
> }
> class Spaceship extends MovieClip
> {
>   public var moveleft:Bool;
>   public var moveright:Bool;
>   public var speed:UInt;
>   public function new()
>   {
>     super();
> 
>     this.graphics.beginFill(0x000000);
>     this.graphics.moveTo(31,0);
>     this.graphics.lineTo(33,0);
>     this.graphics.lineTo(33,10);
>     this.graphics.lineTo(64,64);
>     this.graphics.lineTo(0,64);
>     this.graphics.lineTo(31,10);
>     this.graphics.lineTo(31,0);
>     this.graphics.endFill();    
> 
>     this.moveleft = false;
>     this.moveright = false;
>     this.speed = 3;
>   }
> }
> 
> 
> class App
> {
>   var player:Spaceship;
>   var shots:Array<Shot>;
>   var mobs:Array<Mob>;
>   var mobshots:Array<MobShot>;
>   
>   var updatetimer:Timer;
>   
>   var canvas:Sprite;
>   
>   var shottimer:UInt;
>   
>   public function new(w:Int, h:Int)
>   {
>     // Set up the board
>     canvas = new Sprite();
>     canvas.graphics.beginFill( 0xffffffff, 0x0 );
>     canvas.graphics.drawRect( 0, 0, w, h );
>     canvas.graphics.endFill();
>     Lib.current.addChild(canvas);
>     
>     // Set up the pieces on the board
>     player = new Spaceship();
>     player.x = ( w / 2 ) - ( player.width / 2);
>     player.y = h - player.height - ( h / 20 );
>     
>     shots = new Array<Shot>();
>     shottimer = 0;
>     
>     mobs = new Array<Mob>();
>     mobshots = new Array<MobShot>();
>     
>     var mob1 = new Mob();
>     mobs.push(mob1);
>     
>     canvas.addChild(player);
>     for ( i in mobs )
>     {
>       canvas.addChild( i );
>     }
>     
>     // Handlers
>     updatetimer = new Timer( 10, 0 ); // T=10ms => f=
>     updatetimer.addEventListener(TimerEvent.TIMER, update);
>     updatetimer.stop();
>     
>     Lib.current.stage.addEventListener(KeyboardEvent.KEY_DOWN, keyhandler);
>     Lib.current.stage.addEventListener(KeyboardEvent.KEY_UP, keyhandler);
>   }
>   public function start()
>   {
>     updatetimer.start();
>   }
>   public function stop()
>   {
>     updatetimer.stop();
>   }
>   public function pause()
>   {
>     if ( updatetimer.running == true ) updatetimer.stop();
>     else updatetimer.start();
>   }
>   private function keyhandler(evt:KeyboardEvent)
>   {
>     switch( evt.keyCode )
>     {
>       case 37:
>         // left
>         if ( evt.type == KeyboardEvent.KEY_DOWN ) player.moveleft = true;
>         else if ( evt.type == KeyboardEvent.KEY_UP ) player.moveleft = false;
>       case 39:
>         // right
>         if ( evt.type == KeyboardEvent.KEY_DOWN ) player.moveright = true;
>         else if ( evt.type == KeyboardEvent.KEY_UP ) player.moveright = false;
>       case 32:
>         // space, shoot
>         if ( evt.type == KeyboardEvent.KEY_DOWN && shottimer == 0)
>         {
>           shottimer = 30;
>           var newshot = new Shot();
>           newshot.x = ( player.x + ( player.width / 2) ) - ( newshot.width / 2);
>           newshot.y = player.y - 1;
>           this.canvas.addChild( newshot );
>           this.shots.push( newshot );
>         }
>     }
>   }
>   private function update(evt:TimerEvent)
>   {
>     // Move player
>     if ( player.moveleft == true ) 
>     {
>       player.x -= player.speed;
>       if ( player.x < 0 ) player.x = 0;
>     }
>     if ( player.moveright == true ) 
>     {
>       var xmax = canvas.width - player.width;
>       var newx = player.x + player.speed;
>       if ( newx > xmax ) player.x = xmax;
>       else player.x = newx;
>     }
>     
>     // Move shots
>     if ( shottimer >= 1 ) shottimer--;
>     for ( s in this.shots )
>     {
>       s.y -= s.speed;
>       if ( s.y < (0-s.height) )
>       {
>         this.canvas.removeChild( s );
>         this.shots.remove( s );
>         s = null;
>         Reflect.deleteField(s, "");
>       }
>     }
>     
>     // Move mobs
>     for ( i in this.mobs )
>     {
>       // Shoot?
>       if ( Math.random() < 0.02 )
>       {
>         var ms = new MobShot();
>         ms.x = i.x + ( i.width / 2 ) - ( ms.width / 2 );
>         ms.y = i.y + i.height + 1;
>         this.mobshots.push( ms );
>         this.canvas.addChild( ms );
>       }
>       // Movement
>       switch( i.direction )
>       {
>         case "LEFT":
>           i.x--;
>           if ( i.x <= 0 ) 
>           {
>             i.x = 0;
>             i.direction = "RIGHT";
>           }
>         case "RIGHT":
>           i.x++;
>           var xmax = canvas.width - i.width;
>           if ( i.x >= xmax )
>           {
>             i.x = xmax;
>             i.direction = "LEFT";
>           }
>         default:
>       }
>     }
>     // Move mobshots
>     for ( msh in this.mobshots )
>     {
>       msh.y += msh.speed;
>       if ( msh.y > canvas.height + msh.height )
>       {
>         this.canvas.removeChild( msh );
>         this.mobshots.remove( msh );
>         msh = null;
>         Reflect.deleteField(msh, "");
>       }
>     }
>     
>     // Check for collisions
>     // Playershot - Mob
>     for ( sh in this.shots )
>     {
>       for ( mo in this.mobs )
>       {
>         var col = this.checkForCollision( sh, mo, 0 );
>         //if ( col != null ) trace("HIT!");
>       }
>     }
>     // Mobshot - Player
>     for ( msho in this.mobshots )
>     {
>       var col = this.checkForCollision( msho, player, 0);
>       //if ( col != null ) trace ("BANG, YOU'RE DEAD!");
>     }
>     
>     // Update
>     evt.updateAfterEvent();
>   }
>   private function checkForCollision( p1:MovieClip, p2:MovieClip, alphatolerance:Int ) : Rectangle
>   {
>     var bounds1 = p1.getBounds( Lib.current );
>     var bounds2 = p2.getBounds( Lib.current );
>     if ( ( ( bounds1.right < bounds2.left ) || ( bounds2.right < bounds1.left ) ) || ( ( bounds1.bottom < bounds2.top) || ( bounds2.bottom < bounds1.top ) ) )
>     {
>       return null;
>     }
>     var bounds = new Rectangle();
>     bounds.left = Math.max( bounds1.left, bounds2.left );
>     bounds.right = Math.min( bounds1.right, bounds2.right );
>     bounds.top = Math.max( bounds1.top, bounds2.top );
>     bounds.bottom = Math.min( bounds1.bottom, bounds2.bottom );
>     
>     var img:BitmapData = new BitmapData( cast( bounds.width,Int ), cast( bounds.height,Int ), false );
>     var mat = p1.transform.concatenatedMatrix;
>     mat.tx -= bounds.left;
>     mat.ty -= bounds.top;
>     img.draw( p1, mat, new ColorTransform( 1, 1, 1, 1, 255, -255, -255, alphatolerance ) );
>     
>     mat = p2.transform.concatenatedMatrix;
>     mat.tx -= bounds.left;
>     mat.ty -= bounds.top;
>     img.draw( p2, mat, new ColorTransform( 1, 1, 1, 1, 255, 255, 255, alphatolerance ), BlendMode.DIFFERENCE );
>     
>     var intersection:Rectangle = img.getColorBoundsRect( 0xFFFFFFFF, 0xFF00FFFF );
>     if ( intersection.width == 0 ) { return null; }
> 
>     intersection.x += bounds.left;
>     intersection.y += bounds.top;
>     return intersection;
>   }
> }
> 
> class Main
> {
>   public function new()
>   {
>     Lib.current.addEventListener( Event.ENTER_FRAME, firstframe );
>   }
>   static function main()
>   {
>     Lib.current.stage.scaleMode = StageScaleMode.NO_SCALE;
>     var self = new Main();
>   }
>   public function firstframe(evt:Event)
>   {
>     Lib.current.removeEventListener( Event.ENTER_FRAME, firstframe );
>     var app = new App( Lib.current.stage.stageWidth, Lib.current.stage.stageHeight );
>     app.start();
>   }
> }
> 
> 


-- 
edA-qa mort-ora-y
Idea Architect
http://disemia.com/

Sign: Please digitally sign your emails.
Encrypt: I'm also happy to receive encrypted mail.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 254 bytes
Desc: OpenPGP digital signature
Url : http://lists.motion-twin.com/pipermail/haxe/attachments/20070825/9a749549/signature.pgp


More information about the Haxe mailing list