我过去几天一直试图为我的游戏实施一个FRIM系统。我做了一些研究并发现了this article - 它似乎很简单,所以我开始了。 一切似乎工作得很好,除了我得到一些时间混叠(移动的身体似乎向前跳了一点) - 当处理更多的Box2D步骤时会发生这种情况....我想。
private const FIXED_TIMESTEP:Number = 1 / 60;
private const velocityIterations:int = 8;
private const positionIterations:int = 3;
private var fixedTimestepAccumulator:Number = 0;
private var fixedTimestepAccumulatorRatio:Number = 0;
public function Step(dt:Number):void
{
//dt - time between frames - I'm passing the e.passedTime - from the enter frame event; using Starling
fixedTimestepAccumulator += dt;
var nSteps:uint = Math.floor(fixedTimestepAccumulator / FIXED_TIMESTEP);
if (nSteps > 0)
{
fixedTimestepAccumulator = fixedTimestepAccumulator - nSteps * FIXED_TIMESTEP;
}
fixedTimestepAccumulatorRatio = fixedTimestepAccumulator / FIXED_TIMESTEP;
var nStepsClamped:int = Math.min(nSteps, MAX_STEPS);
for (var i:int = 0; i < nStepsClamped; ++i)
{
resetSmoothStates();
singleStep(FIXED_TIMESTEP);
}
world.ClearForces();
smoothStates();
}
private function resetSmoothStates():void
{
for (var bb:b2Body = world.GetBodyList(); bb; bb = bb.GetNext())
{
if (bb.GetUserData() is MyUserData && bb.GetType() != b2Body.b2_staticBody )
{
//each of my bodies have a reference to their sprite (actor) in userData
var _userdata:MyUserData=bb.GetUserData();
_userdata.x = _userdata.bodyPreviousX = bb.GetPosition().x * RATIO;
_userdata.y= _userdata.bodyPreviousY = - bb.GetPosition().y* RATIO;
_userdata.rotation = _userdata.bodypreviousRotation= _userdata.bodypreviousRotation = - bb.GetAngle();
}
}
}
private function smoothStates():void
{
var oneMinusRatio:Number = 1.0 - fixedTimestepAccumulatorRatio;
for (var bb:b2Body = world.GetBodyList(); bb; bb = bb.GetNext())
{
if (bb.GetUserData() is MyUserData && bb.GetType() != b2Body.b2_staticBody )
{
var userdata=bb.GetUserData();
userdata.x = (fixedTimestepAccumulatorRatio * bb.GetPosition().x * RATIO + oneMinusRatio * userdata.bodyPreviousX) ;
userdata.y = (- fixedTimestepAccumulatorRatio * bb.GetPosition().y * RATIO + oneMinusRatio * userdata.bodyPreviousY) ;
userdata.rotation = (- fixedTimestepAccumulatorRatio * bb.GetAngle() + oneMinusRatio * userdata.bodypreviousRotation);
}
}
}
private function singleStep(dt:Number):void
{
Input();
world.Step(dt, velocityIterations, positionIterations);
}
我做错了什么?
任何帮助,建议将受到高度赞赏。 谢谢
答案 0 :(得分:0)
我在一个正在进行的游戏中做过一次,这样我就可以将游戏锁定到一定的更新速率(这是在iOS中)。这是基于Daley的书(学习iOS游戏编程)中的代码,该书基于网络上的其他一些文章(我相信,它可能是Allen Bishop的)。代码看起来像这样:
void GameManager::UpdateGame()
{
const uint32 MAXIMUM_FRAME_RATE = Constants::DEFAULT_OBJECT_CYCLES_PER_SECOND();
const uint32 MINIMUM_FRAME_RATE = 10;
const uint32 MAXIMUM_CYCLES_PER_FRAME = (MAXIMUM_FRAME_RATE/MINIMUM_FRAME_RATE);
const double UPDATE_INTERVAL = (1.0/MAXIMUM_FRAME_RATE);
static double lastFrameTime = 0.0;
static double cyclesLeftOver = 0.0;
double currentTime;
double updateIterations;
currentTime = CACurrentMediaTime();
updateIterations = ((currentTime - lastFrameTime) + cyclesLeftOver);
if(updateIterations > (MAXIMUM_CYCLES_PER_FRAME*UPDATE_INTERVAL))
{
updateIterations = MAXIMUM_CYCLES_PER_FRAME*UPDATE_INTERVAL;
}
while (updateIterations >= UPDATE_INTERVAL)
{
// DebugLogCPP("Frame Running");
updateIterations -= UPDATE_INTERVAL;
// Set the random seed for this cycle.
RanNumGen::SetSeed(_cycleManager->GetObjectCycle());
// Dispatch messages.
_messageManager->SendMessages();
// Update all entities.
_entityManager->Update();
// Update the physics
_gameWorldManager->Update(Constants::DEFAULT_OBJECT_CYCLE_SECONDS());
// Advance the cycle clock.
_cycleManager->Update();
}
cyclesLeftOver = updateIterations;
lastFrameTime = currentTime;
}
我无法理解您的错误中的特定项目。但是,这部分是可疑的:
var nStepsClamped:int = Math.min(nSteps,MAX_STEPS);
在此之前,您使用以下内容更新了累加器:
fixedTimestepAccumulator = fixedTimestepAccumulator - nSteps * FIXED_TIMESTEP;
但是现在由于钳位(nStepsClamped),您要执行的实际步数可能会有所不同。所以你的时间累积不同于你实际执行的步数。
这有用吗?
答案 1 :(得分:0)
我决定采用另一种方法。我正在使用过滤增量时间进行物理(我知道这可能会导致一些问题)。 这就是我现在正在做的事情:
//Play around with this filter value if things don't look right
var filter:Number=0.4;
filtered_dt= time_between_frames * filter + filtered_dt * (1 - filter);
//Poll imputs and apply forces
// I use velocityIterations =6, positionIterations=3
world.Step(filtered_dt, velocityIterations, positionIterations);
//move sprites here
world.ClearForces();
你需要做的另一件事是使用filtered_dt缩放你应用于身体的力量,这样当帧率发生很大变化时,事情就不会“爆炸”。
希望这有助于其他人...这不是完美的解决方案,但它对我有用。 如果你的移动体很慢,上面的插值方法也可以正常工作。