Skipping frames in Flash

Is there a way to initiate a frame scan on Flash?

When you design a game, you design animations to match the pace of the gameplay, and do it at a target frame rate (usually 24-40 frames per second for Flash). But if the user computer is too slow and cannot support the target frame rate, Flash will automatically reduce the fps, making the application slow.

If you use time-based logic, frame-based rendering will not match time-based logic, and everything will be weird, and there will be a lot of corner cases around.

I know that some games use similar frame skipping logic, such as Popcap Zuma Blitz. Do they crop on their own?

I cannot afford to implement this so late in the project if I cannot somehow override the MovieClip class and make it easily copied. Also, aren't the overheads of managing the animation (overwriting the MovieClip Flash inline control) too much?

+8
flash actionscript-3
source share
6 answers

Well, I understand that you are not looking for the following β€œsolution” that will not work, since all frames will be played back:

stage.frameRate = new_frame_rate; 

The only solution is to simply skip frames in the enterFrame callback:

 // Defined elsewhere. var current_frame:Number = 0; var frame_skip_factor:uint; // Skip one frame every 'x' frames. var is_frame_skip_active:Boolean; function on_enter_frame(event:Event):void { if ( is_frame_skip_active && current_frame++ % frame_skip_factor == 0) { return; } // Game logic/rendering code... } 

(assuming that, in accordance with best practices, you have centralized logic / animation of the game in one callback), but this can lead to race conditions / complications when making any asynchronous callbacks.

It is not possible to actually skip frames at run level; this is part of the AVM contract - no frames are skipped, all code is launched, no matter what. If performance is a problem, you can try executing asynchronous code. There are several ways to do this:

1) Unload some calculations in Pixel Bender so that they can be processed asynchronously and / or in parallel (http://www.adobe.com/devnet/flex/articles/flashbuilder4_pixelbender.html)

2) Expand the execution of lengthy operations on multiple frames (requires state preservation and state restoration, a la memento pattern). Details (and great reading) here: http://www.senocular.com/flash/tutorials/asyncoperations/

In any case, I would (first of all) recommend finally identifying the performance bottleneck using a tool, for example, the Flash Builder profiler or the Stats class (Mr. Doob).

Blitting can be a solution (create a spritesheet with tiles for each frame of the animation). But anyway, I think that you will need to subclass MovieClip and override the play (), stop (), and gotoAndPlay () methods. Your class should look something like this:

 public class MyMovieClip extends MovieClip { override public function play():void { addFrameSkipListener(); super.play(); } override public function gotoAndPlay(frame:Object, scene:String = null):void { addFrameSkipListener(); super.gotoAndPlay(frame, scene); } // .... } 

If the frame skip listener skips frames in accordance with the current frame rate or frame time, if necessary. Naturally, you will also need to remove the frameSkipListener when the animation has reached the end.

While MovieClip's redefinition solution can do what you need on paper if you have a lot of objects, it can actually degrade performance, as additional ENTER_FRAME listeners will add some overhead.

+3
source share

The approach to use is to think about changes in pixels per second instead of pixels per frame. Then you can run the main loop on EnterFrame. In enterframe, call getTimer () to get the system time in milliseconds. And compare this value with the value when the script was last run. This will allow you to know exactly the time elapsed since the last frame. Use this amount to determine how to move things.

Here is an example of what will move the circle at the same speed regardless of the frame rate:

package

 { import flash.display.Shape; import flash.display.Sprite; import flash.events.Event; import flash.utils.getTimer; /** * ... * @author Zachary Foley */ public class Main extends Sprite { private var lastFrame:int = 0; private var thisFrame:int; private var pixelsPerSecond:Number = 200; private var circle:Shape private var percentToMove:Number; public function Main():void { if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE, init); circle = new Shape(); circle.graphics.beginFill(0xFF0000); circle.graphics.drawCircle(0, 0, 25); circle.x = 50; addChild(circle); addEventListener(Event.ENTER_FRAME, onEnterFrame); } private function onEnterFrame(e:Event):void { // Get the miliseconds since the last frame thisFrame = getTimer(); percentToMove = (thisFrame - lastFrame) / 1000; // Save the value for next frame. lastFrame = thisFrame; // Update your system based on time, not frames. circle.x += pixelsPerSecond * percentToMove; } private function init(e:Event = null):void { removeEventListener(Event.ADDED_TO_STAGE, init); // entry point } } } 

If you find that low frame rates affect the accuracy of collision calculations, run them separately with a timer. This is just a drawing outline, which is inevitably tied to the frame rate.

And so that you know, you cannot skip a frame in flash memory. It is processed by the player. The best approach is to set up a frame rendering technique to accommodate a variable frame rate.

+9
source share

The biggest problem is that you do not hit. Artists can still animate on a timeline and export sprites. I would spend some time seriously understanding the performance limitations associated with animation based on the temporary animation of a flash player. Here are some links to get you started:

As you can see, timeline animation control with gotoAndStop (); this is the worst possible animation method regarding the number of sprites you work with.

You can also learn how to use the new graphics api molehill 2d, Starling Framework

To directly answer your question, I would take advantage of the solution already considered by doing a buffered visualization to handle the sheets at runtime. Depending on the number of sprites required at any given time, you can swap low animation performance for memory limitations.

Good luck.

+2
source share

I recently came across something similar; perhaps the following helps in some way:

  • gotoAndStop (frame) will immediately execute the actioncript in the frame
  • you can make multiple calls to gotoAndStop during one ENTER_FRAME event (or any other event).

As a test, I created a new AS3.0 project in Flash Pro CS5.5. I created a new MovieClip and extended the timeline to 23 frames.

In the first frame, I added the following code:

 import flash.events.Event; // do something every frame this.addEventListener(Event.ENTER_FRAME, handleEnterFrame); // let event handler change the playHead this.stop(); // advance playhead 2 frames every frame function handleEnterFrame(anEvent: Event): void { trace('* ENTER_FRAME'); this.gotoNextFrame(); this.gotoNextFrame(); } // advance to next frame, show playheads position function gotoNextFrame(): void { // at last frame? if (this.currentFrame < this.totalFrames) { // no, advance to next frame var before: int = this.currentFrame; this.gotoAndStop(this.currentFrame + 1); trace('before: ' + before + ', current: ' + this.currentFrame); } else { // last frame, stop updating the playhead this.removeEventListener(Event.ENTER_FRAME, handleEnterFrame); } } 

In frame 5, I created a keyframe and added the code:

 this.gotoAndPlay(10); 

In frame 14, I created a keyframe and added the code:

 this.gotoAndPlay(16); 

After starting, I got the following trace output:

 * ENTER_FRAME before: 1, current: 2 before: 2, current: 3 * ENTER_FRAME before: 3, current: 4 before: 4, current: 10 * ENTER_FRAME before: 11, current: 12 before: 12, current: 13 * ENTER_FRAME before: 13, current: 16 before: 16, current: 17 * ENTER_FRAME before: 17, current: 18 before: 18, current: 19 * ENTER_FRAME before: 19, current: 20 before: 20, current: 21 * ENTER_FRAME before: 21, current: 22 before: 22, current: 23 * ENTER_FRAME 

I have no idea how efficient or time consuming it is above. I had to use it with only one MovieClip (at a late stage of development it was found that it would be convenient if the main character could work too, but there was no budget for starting the animation, the symbol contained steps generating a script on the timeline for the right timing )

In your case, you can check how much time has passed since the last ENTER_FRAME, and then specify the correct number of frames.

You can subclass MovieClip and use it as a base class (to quickly do this, select all the clicks that require this in the library, right-click, properties, edit the base class). For those MovieClips that are already associated with ActionScript, you can simply update the .as file by moving from the new MovieClip class.

+1
source share

As far as I know, in AS3 there is nothing to skip MovieClip frames at a given interval or to advance faster than usual through timeline animation. Games like Zuma may either do it manually or control their animation without using a timeline to get started.

To do this manually, you have two main options:

Timeline option: (it may not be worth it, for the reasons explained below). If you are really, absolutely attached to the timeline animation, and changing the frame rate causes a serious problem, you have the time or technical freedom to re-animate with the code, you can probably use the Event.ENTER_FRAME listener to call the function from each MovieClip frame to validate stage.frameRate and skip the next frame or two if frameRate has dropped.

For example:

 var preferredFrameRate = 24; //use whatever your timeline animations are set to function skipFramesIfNeeded() { var currentFrameRate = stage.frameRate; var speedDifference = 1 - (currentFrameRate / preferredFrameRate);//value between 0-1 if(.5 <= speedDifference < .66) { gotoAndPlay(this.currentFrame+1); } else if(.66 <= speedDifference) { gotoAndPlay(this.currentFrame+2); } } 

There are some serious problems with this, but the worst thing is that you can only skip whole frames - skipping every other frame, you will double your speed by skipping every two frames, triple it, etc. Thus, it will not be as smooth or efficient as driving your animation with code instead of a timeline. Executing code from each individual frame of the animation can also slow down even further.

Code only:. If you can find the time, it would be much better to accept all the other offers. Distract your animations from the timeline and run them using code. Keep settings or factors for animation and transition speed, or how many pixels of objects are moving per frame.

Then you can save your preferred frameRate, compare it with stage.frameRate and adjust the multiplier accordingly. This would allow for a smoother gradation of speed.

For example:

 var preferredFrameRate = 24; //or whatever you want this to run at var defaultSpeedMultiplier = 1; var speedMultiplier = 1; //this is the multiplier we'll update function updateAnimationSpeed() { var currentFrameRate = stage.frameRate; // 18, hypothetically var speedDifference = 1 - (currentFrameRate / preferredFrameRate); //.25, or a difference of 25% speedMultiplier = defaultSpeedMultiplier + extraSpeed; //speed multiplier increases from 1 to 1.25 to make up for less frequent frames } 

For the visual states created by the artist, you can load a numbered set of raster images and switch between them in the order in which you will move from one frame to another.

Edit: in theory, you can probably also just detect the changes and change the frameRate back, but if the user machine cannot keep up, Flash will probably ignore it.

+1
source share

You can simply create one hundred or several frames with a long empty movie clip somewhere in the root of your scene, put ten seconds in it or an almost completely silent sound clip and set the sound to stream and loop.

This will actually give you flash memory with an arbitrary variable in Flash, where each timeline and code-based animation anywhere in your file will always run for a given time, skipping frames where necessary, but still executing all the code from a temporary scale even from visually skipped frames. This is a really simple and hassle-free solution, I am surprised that more people do not know about it.

+1
source share

All Articles