Jak zaimplementować pętlę gry w reactive-banana?

To pytanie jest specyficzne dla symulacji reaktywno-bananowych i w czasie rzeczywistym z komponentem fizycznym i wizualnym (np., gry).

Zgodnie z Napraw swój Timestep! idealny sposób na skonfigurowanie pętli gry (zakładając, że fizyka musi być powtarzalna), wymaga stałego czasu między klatkami. Po rozważeniu wielu prawdziwych komplikacji , autor przybywa do tej pętli gry:

double t = 0.0;
const double dt = 0.01;

double currentTime = hires_time_in_seconds();
double accumulator = 0.0;

State previous;
State current;

while ( !quit )
{
     double newTime = time();
     double frameTime = newTime - currentTime;
     if ( frameTime > 0.25 )
          frameTime = 0.25;   // note: max frame time to avoid spiral of death
     currentTime = newTime;

     accumulator += frameTime;

     while ( accumulator >= dt )
     {
          previousState = currentState;
          integrate( currentState, t, dt );
          t += dt;
          accumulator -= dt;
     }

     const double alpha = accumulator / dt;

     State state = currentState*alpha + previousState * ( 1.0 - alpha );

     render( state );
}

Streszczenie jest takie, że symulacja fizyki jest zawsze karmiona tym samym przyrostem czasu (dt) dla stabilności numerycznej. Organizując to, należy wziąć pod uwagę, że fizyka i grafika mogą być aktualizowane z różnymi częstotliwościami i nie chcesz być zbyt daleko w tyle.

Na przykład możesz chcieć aktualizacji z częstotliwością 20 Hz, ale wizualnej aktualizacji z szybkością klatek 60 Hz. Ta pętla wykonuje liniową interpolację fizyki, aby uzupełnić różnicę między aktualizacjami fizyki a aktualizacjami graficznymi.

Dodatkowo, gdy różnica w czasie między klatkami jest znacznie większa niż {[1] } istnieje pętla do obsługi stopniowania aktualizacji w kawałkach dt. Notatka o spirali śmierci odnosi się tylko do przypadku, gdy obliczenia fizyki po prostu nie mogą nadążyć z żądaną częstotliwością aktualizacji, więc pozwalasz mu pominąć niektóre aktualizacje.

W tej dyskusji najbardziej interesuje mnie ułożenie tak, aby wywołanie silnika fizyki (wywołanie do integrate) było zawsze poprzedzone dt. Czy reactive-banan pozwala użytkownikowi napisać ten styl pętla? Jeśli tak, to w jaki sposób? Może przykład wykonywania symulacji fizyki w czasie rzeczywistym jest w porządku (lub już istnieje)?

Author: Jason Dagit, 2012-10-02

1 answers

W tej dyskusji najbardziej interesuje mnie zorganizowanie tak, aby wezwanie do silnika fizyki (wezwanie do integracji) było zawsze poprzedzone dt. Czy reactive-banan pozwala użytkownikowi na zapisanie tej pętli stylu?

Tak, reaktywny-banan może to zrobić.

Chodzi o to, że piszesz niestandardową pętlę zdarzeń i hookujesz do niej reactive-banana. Biblioteka nie stawia żadnych założeń co do tego, skąd pochodzą Twoje wydarzenia, "tylko" rozwiązuje problem zgrabnie opisywanie nowych wydarzeń w kategoriach już istniejących. W szczególności, można użyć funkcji newAddHandler, aby utworzyć dwie funkcje wywołania zwrotnego, które są wywoływane w odpowiednich miejscach w pętli zdarzeń. Zasadniczo, reactive-banan jest po prostu oszałamiającą metodą pisania zwykłych funkcji zwrotnych, które utrzymują stan. Kiedy i jak wywołasz te funkcje, zależy od Ciebie.

Oto ogólny zarys:

-- set up callback functions
(renderEvent, render) <- newAddHandler
(stateUpdateEvent, stateUpdate) <- newAddHandler

-- make the callback functions do something interesting
let networkDescription = do
    eRender      <- fromAddHandler renderEvent
    eStateUpdate <- fromAddHandler stateUpdateEvent
    ...
    -- functionality here

actuate =<< compile networkDescription

-- event loop
while (! quit)
{
    ...
    while (accumulator >= dt)
    {
        stateUpdate (t,dt)      -- call one callback
        t += dt
        accumulator -= dt
    }
    ...
    render ()                   -- call another callback
}

W rzeczywistości napisałem przykład pętli gry w tym stylu dla starsza wersja reactive-banana, ale nie doszła do polerowania i opublikowania go na hackage. Ważne rzeczy, które chciałbym zobaczyć zakończone są:

  • wybierz silnik graficzny, który jest łatwy w instalacji i działa w GHCi. Koncepcja wykorzystuje SDL, ale jest to naprawdę dość niewygodne, ponieważ nie można go używać z GHCi. Coś w rodzaju OpenGL + GLFW byłoby miłe.
  • Zaproponuj małą abstrakcję, aby ułatwić pisanie fazy interpolacji. Prawdopodobnie tylko dwie rzeczy: Zdarzenie eTimer :: Event t (), które reprezentuje regularne aktualizacje fizyki i zachowanie bSinceLastTimer :: Behavior t TimeDiff, które mierzy czas od ostatniej aktualizacji fizyki, które można wykorzystać do wykonania interpolacji. (Jest to zachowanie zamiast zdarzenia, więc wewnętrzne " narysuj to!"aktualizacje są przejrzyste.)
Klon Blackout Andreasa Bernsteina używając reactive-banana Może być doskonałym przykładem do implementacji w tym stylu.
 19
Author: Heinrich Apfelmus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-02 17:14:22