fel*_*aia 8 flash actionscript-3
有没有办法在Flash上本机启用帧跳过?
当您开发游戏时,您可以开发动画以匹配游戏的速度,并以目标帧速率(通常为Flash的24-40fps)进行.但是如果用户的电脑太慢,并且无法保持目标帧率,Flash会自动降低fps,使应用程序播放缓慢.
如果你使用基于时间的逻辑,基于帧的渲染将与基于时间的逻辑不匹配,并且事情会很奇怪,并且会有很多极端情况需要解决.
事实上我知道有些游戏使用这种跳帧逻辑,比如Popcap的Zuma Blitz.他们是自己实施跳帧吗?
除非我能以某种方式重新实现MovieClip类并使其易于框架化,否则我无法在项目的这么晚实现这一点.另外,自己控制动画(覆盖Flash原生MovieClip控件)的开销是不是太大了?
使用的方法是考虑每秒像素的变化,而不是每帧像素.然后,您可以在EnterFrame上运行主循环.在enterframe中,调用getTimer()以毫秒为单位获取系统时间.并将其与上次运行脚本时的值进行比较.这将让您确切知道自上一帧以来经过的时间量.使用该金额来确定如何移动东西.
下面是一个示例,无论帧速率如何,都会以相同的速率移动圆圈:
包
{
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
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果您发现低帧速率影响碰撞计算的准确性,则使用计时器单独运行它们.这只是绘图循环,它不可避免地与帧速率相关联.
只是你知道,你不能在flash中跳帧.它由玩家处理.最好的方法是调整帧渲染技术以适应可变帧速率.
好吧,我意识到您并不是在寻找以下“解决方案”,该解决方案不起作用,因为所有帧仍会播放:
stage.frameRate = new_frame_rate;
Run Code Online (Sandbox Code Playgroud)
唯一的解决方案是在 EnterFrame 回调中跳过帧:
// 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...
}
Run Code Online (Sandbox Code Playgroud)
(假设,根据最佳实践,您已将游戏逻辑/动画集中在单个回调中),但是当运行任何异步回调时,这可能会出现竞争条件/并发症。
没有办法在运行时级别实际跳过帧;这是 AVM 合同的一部分 - 无论如何,不会跳过任何帧,所有代码都会运行。如果性能是一个问题,您可以尝试异步代码执行。有几种方法可以做到这一点:
1) 将一些计算卸载到 Pixel Bender,以便可以异步和/或并行处理 (http://www.adobe.com/devnet/flex/articles/flashbuilder4_pixelbender.html)
2)将冗长操作的执行分散到多个帧上(需要状态保存和状态恢复,一种备忘录模式)。详细信息(和一个很好的阅读)在这里:http ://www.senoptic.com/flash/tutorials/asyncoperations/
无论如何,我(首先也是最重要的)建议使用 Flash Builder Profiler 或 Stats 类(Mr. Doob)等工具来明确识别性能瓶颈。
Blitting 也可能是解决方案(为动画的每个帧创建一个带有图块的 spritesheet)。但无论如何,我认为您需要做的是子类化 MovieClip 并重写 play()、stop() 和 gotoAndPlay() 方法。你的类应该看起来像这样:
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);
}
// ....
}
Run Code Online (Sandbox Code Playgroud)
如果需要,跳帧侦听器将根据当前帧速率或帧时间跳帧。当然,当动画结束时,您还需要删除frameSkipListener。
虽然 MovieClip 覆盖解决方案可能会执行您在纸上想要的操作,但如果您有很多对象,这实际上可能会降低性能,因为额外的 ENTER_FRAME 侦听器会增加一些开销。