更新6 :
Fenomenas建议我尽可能简单地重新创造一切。我怀疑这会有什么不同,因为算法保持不变,而且性能似乎不是问题。无论如何,这是我在这里得到的唯一建议:
代码:
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.utils.getTimer;
[SWF(width="800", height="600", frameRate="40", backgroundColor="#000000")]
public class SimpleMovement extends Sprite
{
private static const TURNING_SPEED:uint = 180;
private static const MOVEMENT_SPEED:uint = 400;
private static const RADIAN_DIVIDE:Number = Math.PI/180;
private var playerObject:Sprite;
private var shipContainer:Sprite;
private var moving:Boolean = false;
private var turningMode:uint = 0;
private var movementTimestamp:Number = getTimer();
private var turningTimestamp:Number = movementTimestamp;
public function SimpleMovement()
{
//step 1: create player object
playerObject = new Sprite();
playerObject.graphics.lineStyle(1, 0x000000);
playerObject.graphics.beginFill(0x6D7B8D);
playerObject.graphics.drawRect(0, 0, 25, 50);
//make it rotate around the center
playerObject.x = 0 - playerObject.width / 2;
playerObject.y = 0 - playerObject.height / 2;
shipContainer = new Sprite();
shipContainer.addChild(playerObject);
shipContainer.x = 100;
shipContainer.y = 100;
shipContainer.rotation = 180;
addChild(shipContainer);
//step 2: install keyboard hook when stage is ready
addEventListener(Event.ADDED_TO_STAGE, stageReady, false, 0, true);
//step 3: install rendering update poll
addEventListener(Event.ENTER_FRAME, updatePoller, false, 0, true);
}
private function updatePoller(event:Event):void
{
var newTime:Number = getTimer();
//turning
if (turningMode != 0)
{
var turningDeltaTime:Number = newTime - turningTimestamp;
turningTimestamp = newTime;
var rotation:Number = TURNING_SPEED * turningDeltaTime / 1000;
if (turningMode == 1) shipContainer.rotation -= rotation;
else shipContainer.rotation += rotation;
}
//movement
if (moving)
{
var movementDeltaTime:Number = newTime - movementTimestamp;
movementTimestamp = newTime;
var distance:Number = MOVEMENT_SPEED * movementDeltaTime / 1000;
var rAngle:Number = shipContainer.rotation * RADIAN_DIVIDE; //convert degrees to radian
shipContainer.x += distance * Math.sin(rAngle);
shipContainer.y -= distance * Math.cos(rAngle);
}
}
private function stageReady(event:Event):void
{
//install keyboard hook
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown, false, 0, true);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUp, false, 0, true);
}
private final function keyDown(event:KeyboardEvent):void
{
if ((event.keyCode == 87) && (!moving)) //87 = W
{
movementTimestamp = getTimer();
moving = true;
}
if ((event.keyCode == 65) && (turningMode != 1)) //65 = A
{
turningTimestamp = getTimer();
turningMode = 1;
}
else if ((event.keyCode == 68) && (turningMode != 2)) //68 = D
{
turningTimestamp = getTimer();
turningMode = 2;
}
}
private final function keyUp(event:KeyboardEvent):void
{
if ((event.keyCode == 87) && (moving)) moving = false; //87 = W
if (((event.keyCode == 65) || (event.keyCode == 68)) && (turningMode != 0)) turningMode = 0; //65 = A, 68 = D
}
}
}
结果如我所料。绝对没有改善。我真的希望有人有另一个建议,因为这件事需要修复。另外,我怀疑这是我的系统,因为我有一个非常好的系统(8GB内存,Q9550 QuadCore英特尔,ATI Radeon 4870 512MB)。此外,到目前为止我问过的其他人都和我的客户有同样的问题。
更新5:另一个流畅的Flash游戏示例,只是为了证明我的运动绝对不同!见http://www.spel.nl/game/bumpercraft.html
更新4 :我追溯渲染前的时间(EVENT.RENDER)和渲染后的正确时间(EVENT.ENTER_FRAME),结果如下:
rendering took: 14 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 14 ms
rendering took: 14 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 24 ms
rendering took: 18 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 232 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 16 ms
rendering took: 12 ms
rendering took: 14 ms
rendering took: 12 ms
范围是12-16毫秒。在这些差异中,震惊/翘曲/闪烁运动已经开始。还有1个232ms的峰值,此时有一个相对较大的扭曲。然而,这不是最大的问题,最大的问题是在正常运动期间连续的小扭曲。这会给任何人一个线索吗?
更新3 :经过测试,我知道以下因素不导致我的问题:
我100%确信问题出在我的代码或算法中。拜托,帮帮我吧。现在已经差不多两周了(我问过这个问题的一周),我仍然需要得到我的回答。
更新1:请参阅完整的Flex项目源代码的底部以及演示我的问题的实时演示。
我正在开发一款2D游戏。玩家船只作为对象创建:
ships[id] = new GameShip();
当移动和旋转信息可用时,这将被定向到相应的船只:
ships[id].setMovementMode(1); //move forward
现在,在此GameShip对象中,移动使用“Event.ENTER_FRAME”事件:
addEventListener(Event.ENTER_FRAME, movementHandler);
然后运行以下功能:
private final function movementHandler(event:Event):void
{
var newTimeStamp:uint = UtilLib.getTimeStamp(); //set current timeStamp
var distance:Number = (newTimeStamp - movementTimeStamp) / 1000 * movementSpeed; //speed = x pixels forward every 1 second
movementTimeStamp = newTimeStamp; //update old timeStamp
var diagonalChange:Array = getDiagonalChange(movementAngle, distance); //the diagonal position update based on angle and distance
charX += diagonalChange[0];
charY += diagonalChange[1];
if (shipContainer)
{ //when the container is ready to be worked with
shipContainer.x = charX;
shipContainer.y = charY;
}
}
private final function getDiagonalChange(angle:Number, distance:Number):Array
{
var rAngle:Number = angle * Math.PI/180; //convert degrees to radian
return [Math.sin(rAngle) * distance, (Math.cos(rAngle) * distance) * -1];
}
当对象不再移动时,将删除事件侦听器。正在使用相同的方法进行旋转。一切都近乎完美。
我已将项目的目标FPS设置为100并创建了一个FPS计数器。根据FPS计数器,firefox中的平均FPS大约为100,而顶部是1000,底部是22.我认为底部和顶部FPS只发生在客户端初始化(启动)。
问题是船看起来几乎是非常光滑的,而它应该只是没有“几乎”部分。这几乎就像船快速地“闪烁”,你实际上看不到它,但是当它用眼睛移动时很难聚焦在物体上。而且,偶尔会出现一些帧速率峰值,好像客户端正在跳过几帧,然后你会看到它快速变形。
很难解释真正的问题是什么,但总的来说,运动并非完全平滑。那么,您对如何使物体的运动或过渡完全平滑有任何建议吗?
更新1:
我重新创建了客户端来演示我的问题。请检查一下。
客户: http://feedpostal.com/test/MovementTest.html
动作脚本项目(完整来源): http://feedpostal.com/test/MovementTest.rar
平滑Flash游戏的一个例子(不是我创建的):http://www.gamesforwork.com/games/swf/Mission%20Racing_august_10th_2009.swf
我花了很长时间重新创建这个客户端版本,我希望这有助于解决问题。
请注意:是的,实际上非常顺利。但这绝对不够顺畅。
答案 0 :(得分:9)
答案 1 :(得分:2)
您的代码顺利运行给我。没有任何尖峰。 使用updatePoller函数末尾添加的以下代码对其进行测试。
var shadow:Sprite = new Sprite();
shadow.graphics.beginFill(0xFFFFFF, 0.01);
shadow.graphics.lineStyle(1, 0xFFFFFF, 0.8);
shadow.graphics.drawRect(0, 0, 25, 50);
this.addChildAt(shadow, 0);
shadow.x = shipContainer.x;
shadow.y = shipContainer.y;
shadow.rotation = shipContainer.rotation;
100 fps版本趋向于获得不均匀的模式,但这是正常的,因为根据您的计算,如果计算帧花费超过10 ms,则无法在一秒内渲染100帧。 所以,至少对我来说,最后一个代码以30fps顺利运行。
至于模糊部分,一个主要的dooh,希望你不会生气我问: 模糊/模糊效果是否有可能是因为你的显示器? 即使在液晶显示器上的响应时间为10毫秒时,静态黑色背景上的白色快速移动的东西也会显得模糊。
答案 2 :(得分:1)
我认为问题的根源是“vertical sync”与屏幕的不同。这与在60hz屏幕上观看24fps电影时出现的问题相同。更新不会完美匹配(在你的情况下是100/60),当它们达到更大的跳跃时,它看起来像是一个小的抖动。
这可以通过降低帧速率来弥补,任何高于屏幕的任何东西都只是浪费处理能力。尽管newer wmodes for flash embedding可能是一种可能的解决方案,但它并不能完全避免。
答案 3 :(得分:0)
我可以建议你过早担心吗?
如果你仔细观察你所连接的“非常流畅”的Flash游戏,你会注意到它会让你感受到流畅运动的“错觉”。
汽车根本没有快速移动 - 可能是每隔几帧一个像素。它是完成大部分运动的背景。仔细看看:有一点抖动和你试图解决的“难以聚焦”效果,但由于它是背景,看起来很正常。即使汽车确实显示出这些效果,背景和游戏玩法也会让您分心注意它们。
我认为你注意到了抖动,因为你现在拥有的只是一艘完全黑色背景的船。一旦游戏的其余部分到位,玩家可能不会有额外的注意力来注意一点抖动。至于“难以聚焦”的效果,当你降低船的移动速度时它会消失。
为什么你不首先在游戏的剩余部分工作?如果仍然存在问题,您可以随后回来调整动作。你花了很多时间在动画工件上。游戏玩法不是更重要吗?
答案 4 :(得分:0)
这是一个非常好的问题。我已经扫描了代码,我有一些建议,虽然我的建议可能不太好。
我认为你可以做很多事情来优化代码。显然,不是在这个早期阶段。但是您可以使用该代码进行测试并快速查看优化代码,然后您就会知道它是否值得继续。
以下是我的“异议”:
你使用了很多分歧。师 比...更贵 乘法。
var distance:Number =(newTimeStamp - movementTimeStamp)/ 1000 * movementSpeed;
可以很容易地写成
var distance:Number = (newTimeStamp - movementTimeStamp) * .001 * movementSpeed;
你有很多很多参考资料 功能。
像fixAngle()之类的东西可以在同一个函数中,而不需要经常来回运行的调用。这适用于对外部类和Math.PI或Math.sin等的引用,正如fenomas和Allan指出的那样。
我已经测试了this方法的正弦和余弦,它的速度非常快。当然它会使代码变脏,但这就是为什么你不尽快优化它,直到你的大部分工作方式都需要工作,优化只会让你疯狂,因为代码会变得更难阅读。根据我的经验,sin和cos是相当昂贵的操作。
正如其他人已经提到的那样,你可能会在这一步过度担心。请记住,有很多事情可以加速,直到你的所有逻辑都正常工作,甚至不考虑优化。
答案 5 :(得分:0)
我认为这几乎可以肯定是因为你的速度达到了80fps。 Flash根本无法快速提供一致的帧速率。下降到30fps并继续测试。另外,尝试在实际背景前飞行,我想你会注意到这一点。
答案 6 :(得分:0)
要下载的文件不存在(http://feedpostal.com/test/MovementTest.rar)。
答案 7 :(得分:0)
我已回答了有关此问题的其他问题,请阅读以下内容:
我感觉到你的痛苦,因为我目前正在开发自己的游戏。在默认设置下,无论您生成什么代码,Flash渲染器都会产生可怕的屏幕撕裂/ v-sync问题。
这就是为什么我很高兴能找到最简单,最优雅的答案,那就是没有重新分解代码(这对单个位有帮助,问题是Flash播放器,而不是代码)。
只需在“发布设置”中启用硬件加速即可。有两种不同的选择:
第1级:直接;和第2级:GPU 。
在官方文档中了解更多相关信息:Specify publish settings for SWF files,并确定哪种选项最适合您的游戏。
目标市场确实在这里发挥作用,如果它对游戏玩家来说是一个严肃的游戏,你不需要担心可能的性能问题,因为大多数游戏玩家都有GPU。
This article并未特别向我提供解决方案,但引导我朝着正确的方向前进。但是,如果您的游戏将在浏览器窗口中,您可能必须使用相同的技术将wmode设置为direct或gpu。