2013-11-25 2 views
1

Я пытался внедрить FRIM-систему для своей игры последние пару дней. Я провел некоторое исследование и натолкнулся на this article - он казался достаточно простым для реализации, поэтому я получил начал. Все, кажется, работает нормально, за исключением того, что я получаю временное сглаживание (движущиеся тела, похоже, немного продвигаются вперед) - это происходит, когда обрабатываются все шаги Box2D .... Я думаю.Box2D - FRIM (независимое от частоты кадров движение)

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); 

} 

Что я делаю неправильно?

Любая помощь, предложения будут высоко оценены. Thanks

ответ

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 так вещи не «взрываются», когда частота кадров меняется много.

Надеюсь, это поможет кому-то еще ... это не идеальное решение, но оно работает для меня. Если у вас медленные движущиеся тела, метод интерполяции выше должен работать отлично.

0

Я сделал это один раз в игре, над которой я работал, чтобы я мог заблокировать игру до определенной скорости обновления (это было в iOS). Это было основано на коде в книге Дейли (Learning iOS Game Programming), которая была основана на какой-то другой статье в Интернете (я считаю, это может быть Аллен Бишопс). Код выглядит следующим образом:

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). Таким образом, ваше накопление времени отличается от количества выполненных вами шагов.

Было ли это полезно?

+0

Я только шаг (обновляю) физику с помощью фиксированного шага времени (FIXED_TIMESTEP) .... так что nSteps - это количество шагов, которые я могу вместить за время, которое накопилось .... nStepsClamped - это просто предел, не выходят из строя, когда частота кадров падает (выполняется только максимум 5 шагов физики). – Iansen

+0

Моя проблема, скорее всего, с интерполяцией позиций спрайтов ... но я не могу понять, что случилось. – Iansen

+0

Хммм ... как правило, в Box2D, позиции спрайтов задаются с чем-то вроде: Vec2 bodyPos = body.GetPosition(); Vec2 spritePos (bodyPos.x * PTMRatio, bodyPos.y * PTMRatio). PTMRatio обычно 32 или переменная (см. Http://nonlinearideas.com/viewports/), но не 1: 1 в руководстве. Странно, что это вызовет скачок, если он не будет обертывать ... – FuzzyBunnySlippers

Смежные вопросы