Jak zakodować Time Stop lub Bullet Time w grze?


11

Tworzę platformówkę RPG dla jednego gracza w XNA 4.0. Chciałbym dodać zdolność, która sprawi, że czas „zatrzyma się” lub zwolni, i sprawi, że tylko postać gracza porusza się z oryginalną prędkością (podobną do zaklęcia Czas zatrzymania z serii Baldur's Gate). Nie szukam dokładnej implementacji, a raczej ogólnych pomysłów i wzorców projektowych.

EDYCJA: Dziękuję wszystkim za wspaniały wkład. Wymyśliłem następujące rozwiązanie

    public void Update(GameTime gameTime)
        {

            GameTime newGameTime = new GameTime(gameTime.TotalGameTime,
 new TimeSpan(gameTime.ElapsedGameTime.Ticks / DESIRED_TIME_MODIFIER));
            gameTime = newGameTime;

lub coś podobnego. W ten sposób mogę ustawić inny czas dla komponentu odtwarzacza i inny dla reszty. Z pewnością nie jest wystarczająco uniwersalny, aby działać w grze, w której taki czas wypaczenia byłby centralnym elementem, ale mam nadzieję, że powinien on działać w tym przypadku. Nie podoba mi się to, że zaśmieca główną pętlę aktualizacji, ale z pewnością jest to najłatwiejszy sposób na jej wdrożenie. Myślę, że to w zasadzie to samo, co sugerował tesselode, więc dam mu zielony haczyk :)

Odpowiedzi:


8

To może być złe rozwiązanie, ale niekoniecznie. Jeśli używasz czasu delta, możesz to zmienić, aby zmienić prędkość niektórych rzeczy.

Na przykład:

player.update(dt)
dt = dt * .5 --half speed
enemy.update(dt)

Działa to oczywiście tylko wtedy, gdy wiesz, kiedy aktualizujesz wroga, a nie coś innego. Możesz też po prostu nadać wszystko wartości prędkości i zrobić coś takiego:

x = x + xspeed * dt * speed

Pierwsza część ma idealny sens, druga część nie jest jasna
AturSams

2
Po prostu daj każdemu obiektowi, który porusza zmienną prędkości, którą możesz zmienić, a kiedy masz transformację (na przykład x), pomnóż wielkość przez zmienną prędkości.
tesselode,

Ma to teraz sens. :)
AturSams

Drugi pomysł brzmi ... wyłączony. Samo skalowanie ruchu przez współczynnik „prędkości” może działać dla obiektów napędzanych fizyką, ale AI będzie w stanie zareagować z normalną prędkością, a ich ruch będzie spowolniony / osłabiony.

Co masz na myśli, że AI byłaby w stanie zareagować przy normalnej prędkości? Jaki kod miałaby AI, która nie mogłaby mieć zastosowanej zmiennej prędkości?
tesselode

3

Użycie czasu delta (milisekund, które upłynęły od ostatniej klatki) może nie wystarczyć do spowolnienia wrogów. Rzeczy takie jak szybkość ataku mogą być realizowane na podstawie czasu ostatniego ataku. Chociaż będzie spowalniać ruch, jeśli jest oparty na czasie, nie będzie spowalniał tempa ataku, rzucania zaklęć i innych efektów (regeneracja zdrowia, czas trwania efektów zaklęć) i tak dalej

Jeśli chcesz spowolnić dużą grupę elementów gry w grze dla jednego gracza, możesz stworzyć drugi zegar wewnętrzny dla każdego stworzenia, zegar rozpoczyna się w chwili, gdy pojawi się stworzenie. Kiedy rzucane jest wolne zaklęcie, każda klatka, zegar jest zwiększany o x% czasu, który faktycznie upłynął. Całe zachowanie potwora jest następnie określane przez jego wewnętrzny zegar. Jeśli różne potwory mają odporność na spowolnienie, mogą korzystać z własnego zegara, jest to w zasadzie liczba całkowita, która nie wymaga dużo miejsca ani obliczeń.

Kiedy efekt spowolnienia ustanie, zegary są nadal używane i są zwiększane o 100% czasu, który faktycznie upłynął.

Może to również działać w przypadku przyspieszenia zaklęć.

@ Sidar: Widzę dwie możliwości,

  1. Zegar wewnętrzny na stworzenie. Aby dowiedzieć się, czy stwór jest gotowy do ponownego ataku: zapisz ostatnie użycie każdego ataku + czas doładowania i sprawdź, czy zegar wewnętrzny już minął.

  2. Jeden licznik czasu na atak: wiesz, ile czasu zajmuje atak, aby się naładować, po prostu ustawiasz licznik czasu i odejmujesz czas, który upłynął * (1% spowolnienia) w każdej turze.

Ja osobiście wolę unikać odejmowania wielu pojedynczych timerów i użytkownika jednego wewnętrznego zegara, aby zaoszczędzić na czasie przetwarzania i złożoności.

To naprawdę zależy od preferencji (nie wpływa to tak bardzo na wydajność).


Potrzeba wewnętrznych zegarów nie jest potrzebna. Po prostu sprowadza się to do mnożnika, który możesz (w jakiś sposób) połączyć z twoim obiektem, który albo zwiększa albo zmniejsza iloczyn twojego dt (czas delta). Możesz zarządzać obiektami grupami lub w jakikolwiek inny sposób. Myślę, że twoja droga może być trochę przesadzona. Ale hej, jeśli to działa ... to działa.
Sidar

@ Sidar Jeśli tego unikniesz, prawdopodobnie będziesz potrzebować zegara na atak tylko po to, by czas ataku się naładował, czas trwania Zaklęcia i tym podobne rzeczy. Przynajmniej w ten sposób wystarczy zaktualizować tylko jeden zegar i po prostu zachować czas „ostatniej aktywacji” na zresetowanie właściwości.
AturSams

Jego pytanie dotyczy jednak spowolnienia środowiska oprócz gracza. Dla mnie to brzmi jak najprostsza forma pomnożenia dt przez liczbę mniejszą niż 1. Przy zachowaniu tego samego dla odtwarzacza.
Sidar

Cóż, spowolnienie środowiska obejmuje spowolnienie tempa ataku, a także innych umiejętności (ponieważ jest to RPG), mogą istnieć różne zdolności mobów, które zależą od czasu ładowania. Leczy, wzmocnienia, osłabienia, czary itp. Nie wspominając o czasie aktywacji.
AturSams

2

Możesz zacząć od prostego rozwiązania, takiego jak ujawnione przez tesselode lub Mr Beast. Ale jeśli zaczniesz mieszać złożone rzeczy, np. Czas pocisku, gdy rzucane jest zaklęcie spowolnienia, utkniesz.

Sugeruję wdrożenie hierarchii zegara :

.
├── Main clock
│   └── UI clock
│   └── 3D clock
│       ├── GFX clock
│       └── Gameplay clock
│           └── Slowdown spell clock 01
│           └── Slowdown spell clock 02

Wszystko w twojej grze powinno wykorzystywać czasy delta z jednego zegara: efekty graficzne działają na zegarze GFX, AI i animacja działają na zegarze gry, stworzenia dotknięte zaklęciem spowolnienia działają na tymczasowym zegarze spowolnienia itp. Następnie różne rzeczy wpływa na różne części Twojej hierarchii: zaklęcie spowolnienia tworzy niestandardowy zegar i wpływa na niego, a czas na pocisk wpłynie na całą hierarchię zegara 3D.


Dzięki, to ważny wgląd. Myślę jednak, że nadal będę myślał prosto, ponieważ w moim konkretnym przypadku nie ma sensu, aby wystąpiło wiele efektów spowolnienia w tym samym czasie.
David Miler

1

Potrzebujesz tylko dwóch różnych zegarów zamiast jednego, jednego na czas odpowiedni dla rozgrywki i jednego „prawdziwego” czasu.

currentGameTime = 0;
gameSpeed = 1.0f;
[...]
currentApplicationTime = GetTime():
timeDelta = (currentApplicationTime - lastApplicationTime)*gameSpeed;
currentGameTime += timeDelta;
lastApplicationTime = currentApplicationTime;

Następnie możesz po prostu zmienić gameSpeed, aby przyspieszyć (> 1) lub spowolnić czas (<1). Aby gracz poruszał się z inną prędkością, po prostu sprawdź, czy czas jest spowolniony, czy nie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.