Przed zastosowaniem ekstrapolacji do ruchu mojego duszka, moje zderzenie działało idealnie. Jednak po zastosowaniu ekstrapolacji do ruchu mojego duszka (aby wygładzić rzeczy) kolizja nie działa.
Oto jak działało to przed ekstrapolacją:
Jednak po zaimplementowaniu mojej ekstrapolacji procedura kolizji zostaje zerwana. Zakładam, że dzieje się tak, ponieważ działa on na nową współrzędną utworzoną przez procedurę ekstrapolacji (która znajduje się w moim wywołaniu renderowania).
Po zastosowaniu mojej ekstrapolacji
Jak poprawić to zachowanie?
Próbowałem poddać się dodatkowej kontroli kolizji zaraz po ekstrapolacji - wydaje się, że to rozwiązuje wiele problemów, ale wykluczyłem to, ponieważ logika w moim renderowaniu nie wchodzi w rachubę.
Próbowałem również wykonać kopię pozycji spritesX, ekstrapolując ją i rysując używając tego, a nie oryginału, pozostawiając nienaruszony oryginał, aby logika mogła go zaakceptować - wydaje się to lepsza opcja, ale nadal daje dziwne efekty podczas zderzenia ze ścianami. Jestem prawie pewien, że to też nie jest właściwy sposób, aby sobie z tym poradzić.
Znalazłem tutaj kilka podobnych pytań, ale odpowiedzi mi nie pomogły.
To jest mój kod ekstrapolacji:
public void onDrawFrame(GL10 gl) {
//Set/Re-set loop back to 0 to start counting again
loops=0;
while(System.currentTimeMillis() > nextGameTick && loops < maxFrameskip){
SceneManager.getInstance().getCurrentScene().updateLogic();
nextGameTick+=skipTicks;
timeCorrection += (1000d/ticksPerSecond) % 1;
nextGameTick+=timeCorrection;
timeCorrection %=1;
loops++;
tics++;
}
extrapolation = (float)(System.currentTimeMillis() + skipTicks - nextGameTick) / (float)skipTicks;
render(extrapolation);
}
Stosowanie ekstrapolacji
render(float extrapolation){
//This example shows extrapolation for X axis only. Y position (spriteScreenY is assumed to be valid)
extrapolatedPosX = spriteGridX+(SpriteXVelocity*dt)*extrapolation;
spriteScreenPosX = extrapolationPosX * screenWidth;
drawSprite(spriteScreenX, spriteScreenY);
}
Edytować
Jak wspomniałem powyżej, próbowałem wykonać kopię współrzędnych duszka, aby narysować ... to ma swoje problemy.
Po pierwsze, bez względu na kopiowanie, gdy duszek się porusza, jest super gładki, gdy się zatrzymuje, kołysze się lekko w lewo / w prawo - ponieważ wciąż ekstrapoluje swoją pozycję na podstawie czasu. Czy to jest normalne zachowanie i czy możemy je „wyłączyć”, gdy duszek się zatrzyma?
Próbowałem mieć flagi dla lewej / prawej i ekstrapolować tylko, jeśli którakolwiek z nich jest włączona. Próbowałem również skopiować ostatnie i bieżące pozycje, aby zobaczyć, czy jest jakaś różnica. Jednak w przypadku kolizji nie pomagają.
Jeśli użytkownik naciska powiedz, prawy przycisk, a duszek porusza się w prawo, gdy uderza o ścianę, jeśli użytkownik nadal przytrzymuje prawy przycisk, duszek będzie animował w prawo, zatrzymując się przy ścianie ( dlatego tak naprawdę się nie porusza), jednak ponieważ ustawiono prawą flagę, a także dlatego, że procedura kolizji stale przesuwa duszka ze ściany, nadal wydaje się kodowi (nie graczowi), że duszek wciąż się porusza, a zatem ekstrapolacja trwa. Tak więc gracz zobaczy, że duszek jest „statyczny” (tak, animuje, ale tak naprawdę nie porusza się po ekranie) i co jakiś czas trzęsie się gwałtownie, gdy ekstrapolacja próbuje to zrobić… .. Mam nadzieję, że to pomoże
Odpowiedzi:
Nie mogę jeszcze opublikować komentarza, więc opublikuję to jako odpowiedź.
Jeśli dobrze rozumiem problem, wygląda to tak:
Mogę wymyślić 3 możliwe rozwiązania. Wymienię je w kolejności najbardziej pożądanej dla najmniej IMHO.
Przykładowy kod dla # 2.
Myślę, że numer 2 byłby prawdopodobnie najszybszym i najłatwiejszym do uruchomienia, chociaż numer 1 wydaje się być bardziej logicznym rozwiązaniem. W zależności od tego, jak poradzisz sobie z rozwiązaniem delta w czasie, rozwiązanie nr 1 może zostać złamane w podobny sposób przez dużą deltę, w którym to przypadku może być konieczne jednoczesne użycie obu # 1 i # 2.
EDYCJA: Źle zrozumiałem twój kod wcześniej. Pętle mają renderować tak szybko, jak to możliwe i aktualizować w ustalonych odstępach czasu. Dlatego interpolowałbyś pozycję duszka, aby obsłużyć przypadek, w którym rysujesz więcej niż aktualizowanie. Jeśli jednak pętla pozostanie w tyle, odpytujesz aktualizację, dopóki nie zostaniesz złapany lub nie przeskoczysz maksymalnej liczby losowań klatek.
Biorąc to pod uwagę, jedynym problemem jest to, że obiekt porusza się po zderzeniu. W przypadku kolizji obiekt powinien przestać się poruszać w tym kierunku. Jeśli więc dochodzi do kolizji, ustaw jego prędkość na 0. To powinno powstrzymać funkcję renderowania od dalszego przesuwania obiektu.
źródło
Wygląda na to, że musisz całkowicie oddzielić renderowanie i aktualizację fizyki. Zwykle podstawowa symulacja będzie przebiegać w dyskretnych odstępach czasu, a częstotliwość nigdy się nie zmieni. Na przykład możesz symulować ruch swojej piłki co 1/60 sekundy i to wszystko.
Aby umożliwić zmienną szybkość klatek, kod renderowania powinien działać na zmiennej częstotliwości, ale każda symulacja powinna nadal odbywać się w ustalonym czasie. Pozwala to grafice odczytać pamięć z symulacji jako tylko do odczytu i pozwala ustawić interpolację zamiast ekstrapolacji.
Ponieważ ekstrapolacja próbuje przewidzieć, gdzie będą przyszłe wartości, nagłe zmiany w ruchu mogą spowodować ogromne błędy ekstrapolacji. Lepiej zamiast tego renderować scenę wokół ramki za symulacją i interpolować między dyskretnymi znanymi pozycjami.
Jeśli chcesz zobaczyć szczegóły implementacji, napisałem już krótką sekcję na ten temat w artykule tutaj . Zobacz sekcję „Pomiar czasu”.
Oto ważny kod psuedo z artykułu:
RenderGame
Funkcja jest najbardziej interesujące. Chodzi o użycie interpolacji między dyskretnymi pozycjami symulacji. Kod renderujący może tworzyć własne kopie danych tylko do odczytu z symulacji i używać do renderowania tymczasowej wartości interpolowanej. Zapewni to bardzo płynny ruch bez żadnych głupich problemów, takich jak to, co wydaje się mieć!źródło