• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Zrozumienie funkcji requestAnimationFrame

Object Storage Arubacloud
0 głosów
1,373 wizyt
pytanie zadane 3 czerwca 2018 w JavaScript przez Riddick Bywalec (2,600 p.)
Witam, zwracam się dzisiaj do was z prośbą o pomoc w zrozumieniu jak działa funkcja requestAnimationFrame oraz sposobu jej użycia.

Może najpierw powiem co już rozumiem. Wiem, że ta funkcja uruchamia się domyślnie 60 razy na sekundę jednak w większości przeglądarek jest to wartość odświeżania monitora. Wiem też, że zwraca jakąś wartość jednak nie bardzo rozumiem co ta wartość oznacza i co można z nią zrobić.

A teraz czego nie rozumiem i co chciałbym się dowiedzieć.Nie rozumiem jak za pomocą tej funkcji można tworzyć animacje względem czasu rzeczywistego a nie względem sztywno ustalonego czasu odświeżania jak ma to miejsce w np setInterval. Nie wiem jak wydobyć czas który minął od poprzedniego wywołania funkcji. Widziałem, że się da ale trudno mi zrozumieć kod bo na tutorialach które widziałem kod nie jest praktycznie w ogóle opisany. Same ogólniki ale nie ma wytłumaczone co robi konkretna linijka kodu i za co odpowiada jaka zmienna. Chciałbym się dowiedzieć jak napisać pętle programu która działa identycznie jak w prawdziwych grach. Czyli odświeża się z maksymalną prędkością a obiekt w trakcie animacji niezależnie od liczby powtórzeń pętli przesunie się o określoną odległość mniej lub bardziej płynnie w zależności od ilości klatek na sekundę.

Również interesuje mnie temat animacji po klatkowej jednak jeśli zrozumiem podstawy powinienem już umieć to zrobić. np mam 30 klatek animacji postaci i chcę je odtworzyć w sekundę, jeśli framerate będzie niższy niż 30 niektóre klatki animacji trzeba będzie pominąć a jeśli jest np 144 na dobrym monitorze to kolejne klatki animacji odpali się co określoną liczbę odświeżeń.

Być może powinienem to szybko zrozumieć może to jest łatwe ale pierwszy raz mam taką sytuacje że mnie pewna rzecz w programowaniu przerasta a zapewniam że podstawy mam solidne przepracowane. Może to z powodu zmęczenia, nie wiem. Ale bardzo mi zależy aby całkowicie zrozumieć zasadę działania tej funkcji i chciałbym aby ten wątek zawierał w komentarzach jak najwięcej informacji dla osób, które również mają problem  w zrozumieniu tego sposobu na tworzenie animacji. Chętnie też podyskutuje o różnych sposobach na wykorzystanie requestAnimationFrame w aplikacjach internetowych.

1 odpowiedź

+1 głos
odpowiedź 3 czerwca 2018 przez rafal.budzis Szeryf (85,260 p.)

Myślę ze uda ci się samemu poszperać w necie. Pętla do tworzenia gier którą można zrobić w JS za pomocą requestAnimationFrame nazywana jest "pętlą czasu rzeczywistego" a najbardziej popularną techniką jest wyliczanie delta time czyli różnicy w czasie między końcem poprzedniej klatki a nową klatką. 

Gdy masz już delta time to robisz sobie licznik który będzie co klatka dodawał sobie delta time do siebie. Następnie robisz warunek (pętla while) jeśli ten licznik jest większy od interesującego cie czasu to wykonuj daną operacje i odejmuj interesujący cie czas dopóki warunek będzie spełniony. Wówczas gdy FPSy będą trzymać poziom pętla z warunkiem wykona się raz na klatkę jeśli nie wykona sie dwa razy tak chyba najłatwiej to obejść. Dobrym podejściem jest dzielenie klatki na funkcje update oraz draw. Wówczas podwójne obliczanie występować powinno tylko w funkcji update przed wyświetleniem czegokolwiek. 

Znalazłem kod który powinien cie interesować : 

var now, dt,
    last = timestamp();

function frame() {
  now   = timestamp();
  dt    = (now - last) / 1000;    // duration in seconds
  update(dt);
  render(dt);
  last = now;
  requestAnimationFrame(frame);
}

requestAnimationFrame(frame);

Cały artykuł https://codeincomplete.com/posts/javascript-game-foundations-the-game-loop/

komentarz 3 czerwca 2018 przez Riddick Bywalec (2,600 p.)

Dobrze mniej więcej już rozumiem. Napisałem sobie taki prosty kod i chciałem przypisać sobie dynamiczną prędkość obiektu zależną od liczby klatek na sekundę jednak coś mi nie chce to działać.

 

var canvasElem = document.getElementById('ctx');
var ctx = canvasElem.getContext('2d');
var fpsElem = document.getElementById('fps');

canvasElem.width = window.innerWidth-50;
canvasElem.height = window.innerHeight-50;

var right = true, bottom = true;
var spd = 10;

var x=60.0, y=350.0, r=30;


var curTime=0;
var lastTime=0;
var timeBtw=0;
var speed=spd;

function move() {
    ctx.clearRect(0, 0, canvasElem.width, canvasElem.height);
    ctx.beginPath();
    ctx.arc(x,y,r,0,2*Math.PI,false);
    ctx.fill();
    if(x>=canvasElem.width-r) right=false;
    if(x<=0+r) right=true;
    if(y>=canvasElem.height-r) bottom=false;
    if(y<=0+r) bottom=true;
    if(right) x=x+speed;
    else x=x-speed;
    if(bottom) y=y+speed;
    else y=y-speed;
}

function animation(timestamp) {
    curTime = timestamp;
    timeBtw = curTime-lastTime;
    lastTime = curTime;
    speed *= 60/timeBtw;
    move();

    requestAnimationFrame(animation);
}
animation();

Wartość x oraz y przy sprawdzeniu typeof daje wartość number ale ich wartość jest NaN. Nie rozumiem dlaczego tak się dzieje

komentarz 3 czerwca 2018 przez rafal.budzis Szeryf (85,260 p.)

Wydaje mi sie ze wystarczyu zmienic ta linijke 

speed *= 60/timeBtw;

Mnożysz zawsze poprzednią szybkość. A co jeśli poprzednia szybkość wyniesie 0 ? Nigdy się nie poruszysz ;) Wydaje mi się ze powinno być tak 

speed = spd * (timeBtw/60);


Co do kodu mam kilka uwag które na pewno ci pomogą w przyszłości. Dzięki nim na pewno poczynisz szybsze postępy. Brakuje u Ciebie w kodzie podziału na funkcje draw i update to podstawowy wzorzec tak jak MVC w stronach. Radze jak najszybciej stworzyć draw i update bo potem będzie ci trudniej naprawić ten błąd ;) Jeśli chcesz to spróbuj popatrzeć na kod mojej gierki co prawda nie jest najwyższych lotów bo czas konkursowy gonił ale być może lepiej zrozumiesz w jaki sposób dzielić kod na update (wyliczanie) i draw(rysowanie).

http://budzis.pl/Wpisy/Programy/Ostatnia+choinka/ 

Druga rzecze która sprawia ze twój kod jest nieczytelny i na pewno sprawi tobie samemu problem to brak tworzenia klamerek dla jedno linijkowych if. Wygląda to strasznie i do tego utrudnia szybkie dopisanie czegokolwiek. 

Jak będziesz miał jakieś efekty w postaci gry do pokazania polecam zawczasu https://warsztat.gd/

 

komentarz 5 czerwca 2018 przez Riddick Bywalec (2,600 p.)

Dziękuję za pomoc. Ten kod jest jakby to ująć taki testowy nie ma służyć do niczego, mój błąd, że udostępniłem taki kod publicznie. Jest on zrobiony tak żeby mi samemu wytłumaczyć zasadę działania jak krowie na miedzy :D. Mimo wszystko powinienem go odpowiednio zmodyfikować. 

 

var canvasElem = document.getElementById('ctx');
var ctx = canvasElem.getContext('2d');
var fpsElem = document.getElementById('fps');

canvasElem.width = window.innerWidth-50;
canvasElem.height = window.innerHeight-50;

var right = true, bottom = true;
var spd = 10;

var x=60.0, y=350.0, r=30;


var curTime=0;
var lastTime=0;
var timeBtw=0;
var speed=spd;

function draw() {
    ctx.clearRect(0, 0, canvasElem.width, canvasElem.height);
    ctx.beginPath();
    ctx.arc(x,y,r,0,2*Math.PI,false);
    ctx.fill();
    if(x>=canvasElem.width-r) {
        right=false;
    }
    if(x<=0+r) {
        right=true;
    }
    if(y>=canvasElem.height-r) {
        bottom=false;
    }
    if(y<=0+r) {
        bottom=true;
    }
    if(right) {
        x=x+speed;
    }
    else {
        x=x-speed;
    }
    if(bottom) {
        y=y+speed;
    }
    else {
        y=y-speed;
    }
}

function update(timestamp) {
    curTime = timestamp;
    timeBtw = curTime-lastTime;
    lastTime = curTime;
    speed = spd * (60/timeBtw);
    draw();

    requestAnimationFrame(update);
}
update();

Kiedy piszę kod tylko dla siebie wolę użyć bardziej zwięzłej składni. Dzięki za radę i przypomnienie :)

komentarz 5 czerwca 2018 przez Riddick Bywalec (2,600 p.)
A jeśli chodzi o gry to oczywiście, że mam efekty i to nawet kilka :D
Tu jest moje portfolio.

http://marcin-kalinowski.pl

Podobne pytania

0 głosów
1 odpowiedź 258 wizyt
0 głosów
1 odpowiedź 155 wizyt
0 głosów
2 odpowiedzi 599 wizyt

92,632 zapytań

141,502 odpowiedzi

319,881 komentarzy

62,015 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...