在我们的游戏项目中,我们确实有一个计时器循环设置为每秒触发大约 20 次(与应用程序帧速率相同)。我们用它来移动一些精灵。我想知道这是否会导致问题,我们应该使用 EnterFrame 事件处理程序来进行更新?我的印象是,让计时器循环运行得比应用程序帧速率快可能会导致问题……是这样吗?
作为更新,尝试在 EnterFrame 上执行此操作会导致非常奇怪的问题。不是每 75 毫秒一帧,而是突然跳到 25 毫秒。请注意,不仅仅是我们的计算声称帧速率不同,动画突然加速到了疯狂的速度。
在我们的游戏项目中,我们确实有一个计时器循环设置为每秒触发大约 20 次(与应用程序帧速率相同)。我们用它来移动一些精灵。我想知道这是否会导致问题,我们应该使用 EnterFrame 事件处理程序来进行更新?我的印象是,让计时器循环运行得比应用程序帧速率快可能会导致问题……是这样吗?
作为更新,尝试在 EnterFrame 上执行此操作会导致非常奇怪的问题。不是每 75 毫秒一帧,而是突然跳到 25 毫秒。请注意,不仅仅是我们的计算声称帧速率不同,动画突然加速到了疯狂的速度。
我会选择 Enter 帧,在某些特殊情况下,有两个“循环”可能很有用,一个用于逻辑,一个用于视觉,但对于大多数游戏,我坚持使用 Enter 帧事件侦听器。有一个单独的计时器来移动你的东西有点不必要,因为将它设置为除帧率之外的任何东西都会使运动变得生涩或不可见(因为没有重绘帧)。
但是要考虑的一件事是将您的逻辑与帧速率解耦,这最容易通过使用 getTimer(在 as2 和 as3 中都可用)来计算自上一帧以来已过期的时间并相应地调整运动或其他方式来完成。
计时器并不比进入帧事件更可靠,flash 将尝试跟上您设置的任何速率,但如果您正在执行繁重的处理或复杂的图形,它会减慢计时器和帧速率。
下面简要介绍了 Flash 如何处理帧速率以及您看到内容播放速度更快的原因。
在最深层次上,Flash 运行的任何宿主应用程序(通常是浏览器)都会每隔一段时间轮询 Flash。该间隔在一个浏览器中可能是每 10 毫秒,在另一个浏览器中可能是 50 毫秒。每次轮询发生时,Flash 都会执行以下操作:
ENTER_FRAME
事件但是,某些类型的外部事件(例如按键、鼠标事件和计时器事件)与上述过程异步处理。因此,如果您有一个在按下某个键时触发的事件处理程序,则该处理程序中的代码可能会在帧更新之间执行多次。updateAfterEvent()
除非您使用该方法(在 AS2 中为全局,在 AS3 中附加到事件),否则屏幕仍将在每帧更新时仅重绘一次。
请注意,这些事件的异步行为不会影响帧更新的时间。即使您使用计时器事件,例如每秒重绘屏幕 50 次,帧动画仍然会以发布的帧速率发生,并且如果脚本动画由 enterFrame 事件驱动(而不是计时器)。
使用输入帧事件的好处是您的处理将与渲染同步降级,并且您将在代码块完成后立即获得屏幕更新。
任何一种方法都不能保证在特定的时间间隔内发生。因此,您的事件处理程序应该确定自上次执行以来已经过去了多长时间,并据此做出决定,而不是纯粹运行多少次。
我建议使用 TweenLite ( http://blog.greensock.com/tweenliteas3/ ) 之类的轻量级类,大约 3kb,或者如果您需要更多功率,您可以使用 TweenMax,我相信它是 11kb。这里有很多优点。首先,这个“引擎”已经过彻底的测试和基准测试,并且是众所周知的为少数甚至很多东西制作动画的最资源友好的方式之一。我看过一个基准测试,在 AS3 中,1,500 个精灵正在使用 TweenLite 进行动画处理,它拥有强大的 20 fps,而像 Tweener 这样的竞争对手则会陷入 9 fps http://blog.greensock.com/tweening-speed-测试/。下一个优点是易于使用,我将在下面演示。
//确保您有一个指向包含以下内容的文件夹的类路径。 导入 gs.TweenLite; 导入 gs.easing。*; var ball_mc:MovieClip = new MovieClip(); var g:Graphics = ball_mc.graphics; g.beginFill(0xFF0000,1); g.drawCircle(0,0,10); g.endFill(); //现在我们动画ball_mc //示例:TweenLite.to(displayObjectName, totalTweeningTime, {someProperty:someValue,anotherProperty:anotherValue,onComplete:aFunctionCalledWhenComplete}); TweenLite.to(ball_mc, 1,{x:400,alpha:0.5});
因此,这需要 ball_mc 并将其从 x 轴上的当前位置移动到 400,并且在同一 Tween 期间,它将 alpha 从其当前值减少或增加到 0.5。
导入所需的类后,真的只需要 1 行代码就可以为每个对象设置动画,非常棒。我们也可以影响轻松度,我相信默认情况下是 Expo.easeOut(Strong easeOut)。如果您希望它反弹或具有弹性,只需向对象添加如下属性即可获得此类效果。
TweenLite.to(ball_mc, 1,{x:400,alpha:0.5,ease:Bounce.easeOut}); TweenLite.to(ball_mc, 1,{x:400,alpha:0.5,ease:Elastic.easeOut});
缓动全部来自 gs.easing.* 导入,我相信这是通过 TweenLite 使用的 Penner 的缓动方程。
最后,我们无需管理诸如 Timer 之类的轮询(开环),并且我们拥有非常易读的代码,可以轻松修改或删除。
还需要注意的是,TweenLite 和 TweenMax 提供的功能远远超过我在此处展示的内容,可以肯定地说,我在每个项目中都使用这两个类中的一个。动画是自定义的,它们附加了功能(onComplete:functionCall),而且它们是最佳的和资源友好的。
我认为 timerEvent 和 Enter Frame 都是不错的选择,我在游戏中都使用过它们。(您是指定时器循环中的 timerEvent 吗?)
PS:请注意,在慢速机器中,计时器可能刷新不够快,因此您可能需要调整代码以使游戏在慢速机器中“更快”运行。