Wie codiere ich Time Stop oder Bullet Time in einem Spiel?

11

Ich entwickle einen Einzelspieler-RPG-Plattformer in XNA 4.0. Ich möchte eine Fähigkeit hinzufügen, die die Zeit "stoppt" oder verlangsamt und nur den Spielercharakter mit der ursprünglichen Geschwindigkeit bewegen lässt (ähnlich dem Zeitstopp-Zauber aus der Baldur's Gate-Serie). Ich suche keine genaue Implementierung, sondern einige allgemeine Ideen und Designmuster.

EDIT: Vielen Dank für den tollen Input. Ich habe die folgende Lösung gefunden

    public void Update(GameTime gameTime)
        {

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

oder so ähnlich. Auf diese Weise kann ich eine andere Zeit für die Player-Komponente und eine andere für den Rest einstellen. Es ist sicherlich nicht universell genug, um für ein Spiel zu arbeiten, bei dem eine solche Verzerrungszeit ein zentrales Element wäre, aber ich hoffe, dass es für diesen Fall funktionieren sollte. Ich mag die Tatsache nicht, dass es die Haupt-Update-Schleife verschmutzt, aber es ist sicherlich der einfachste Weg, es zu implementieren. Ich denke, das ist im Wesentlichen das gleiche wie von Tesselode vorgeschlagen, also werde ich ihm das grüne Häkchen geben :)

David Miler
quelle

Antworten:

8

Dies könnte eine schlechte Lösung sein, aber nicht unbedingt. Wenn Sie die Deltazeit verwenden, können Sie dies ändern, um die Geschwindigkeit bestimmter Dinge zu ändern.

Beispielsweise:

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

Dies funktioniert natürlich nur, wenn Sie erkennen können, wann Sie den Feind aktualisieren, und nicht etwas anderes. Sie können auch einfach alles mit einem Geschwindigkeitswert versehen und Folgendes tun:

x = x + xspeed * dt * speed
tesselode
quelle
Der erste Teil macht vollkommen Sinn, der zweite Teil ist nicht klar
AturSams
2
Geben Sie einfach jedem Objekt, das sich bewegt, eine Geschwindigkeitsvariable an, die Sie ändern können, und multiplizieren Sie bei einer Transformation (z. B. von x) die Größe mit der Geschwindigkeitsvariablen.
Tesselode
Macht jetzt Sinn. :)
AturSams
Die zweite Idee klingt ... aus. Das Skalieren der Bewegung um den "Geschwindigkeits" -Faktor kann für physikalisch angetriebene Objekte funktionieren, aber die KI könnte mit normaler Geschwindigkeit reagieren, wobei nur ihre Bewegung verlangsamt / beeinträchtigt wird.
Was meinst du damit, dass die KI mit normaler Geschwindigkeit reagieren kann? Welchen Code hätte die KI, auf den keine Geschwindigkeitsvariable angewendet werden könnte?
Tesselode
3

Die Verwendung der Deltazeit (Millisekunden, die seit dem letzten Frame vergangen sind) reicht möglicherweise nicht aus, um Gegner zu verlangsamen. Dinge wie die Angriffsrate können basierend auf der letzten Angriffszeit implementiert werden. Während es die Bewegung verlangsamt, wenn es zeitbasiert ist, wird es vernachlässigen, die Angriffsrate, das Wirken von Zaubersprüchen und andere Effekte (Gesundheitsregeneration, Dauer der Zaubereffekte) zu verlangsamen

Wenn Sie eine große Gruppe von Spielelementen in einem Einzelspielerspiel verlangsamen möchten, können Sie für jede Kreatur eine zweite interne Uhr erstellen. Die Uhr beginnt zum aktuellen Zeitpunkt, zu dem die Kreatur erscheint. Wenn in jedem Frame ein langsamer Zauber gewirkt wird, wird die Uhr um x% der tatsächlich verstrichenen Zeit erhöht. Das gesamte Verhalten der Monster wird dann durch die interne Uhr bestimmt. Wenn verschiedene Monster Widerstand gegen Verlangsamung haben, können sie ihre eigene Uhr verwenden. Dies ist im Grunde eine Ganzzahl, die nicht viel Platz oder Rechenaufwand erfordert.

Wenn der langsame Effekt aufhört, werden die Uhren weiterhin verwendet und um 100% der tatsächlich verstrichenen Zeit erhöht.

Dies könnte auch für beschleunigte Zauber funktionieren.

@ Sidar: Ich sehe zwei Möglichkeiten,

  1. Interne Uhr pro Kreatur. Um herauszufinden, ob die Kreatur wieder angreifbereit ist: Speichern Sie das letzte Mal, als jeder Angriff ausgeführt wurde + Ladezeit und überprüfen Sie, ob die interne Uhr diese Zeit bereits überschritten hat.

  2. Ein Timer pro Angriff: Sie wissen, wie lange das Aufladen des Angriffs dauert, und Sie stellen einfach einen Timer ein und subtrahieren die Zeit, die * (1-Verlangsamung%) pro Runde vergangen ist.

Ich persönlich bevorzuge es, das Subtrahieren mehrerer einzelner Timer und des Benutzers einer internen Uhr zu vermeiden, um Verarbeitungszeit und Komplexität zu sparen.

Es hängt wirklich von den Vorlieben ab (die Leistung wird dadurch nicht so stark beeinträchtigt).

AturSams
quelle
Die Notwendigkeit für interne Uhren wird nicht benötigt. Es kommt einfach auf einen Multiplikator an, den Sie (irgendwie) mit Ihrem Objekt verknüpfen können, der das Produkt Ihres dt (Delta-Zeit) entweder erhöht oder verringert. Sie können die Objekte nach Gruppen oder mit anderen Mitteln verwalten. Ich denke, dein Weg könnte etwas übertrieben sein. Aber hey wenn es funktioniert ... dann funktioniert es.
Sidar
@Sidar Wenn Sie dies vermeiden, benötigen Sie wahrscheinlich eine Uhr pro Angriff, um die Wiederaufladung des Angriffs, die Dauer des Zaubers und dergleichen zu bestimmen. Zumindest auf diese Weise müssen Sie nur eine Uhr aktualisieren und einfach die 'letzte Aktivierungszeit' für das Zurücksetzen der Eigenschaften beibehalten.
AturSams
Seine Frage betrifft jedoch die Verlangsamung der Umgebung mit Ausnahme des Spielers. Für mich klingt das nach der einfachsten Form, den dt einfach mit einer Zahl unter 1 zu multiplizieren, während er so bleibt, wie er für den Spieler ist.
Sidar
Nun, das Verlangsamen der Umgebungen beinhaltet das Verlangsamen ihrer Angriffsrate sowie ihrer anderen Fähigkeiten (da es sich um ein RPG handelt). Es kann verschiedene Mob-Fähigkeiten geben, die von der Ladezeit abhängen. Heilungen, Buffs, Debuffs, Zauber usw. Ganz zu schweigen von der Aktivierungszeit.
AturSams
2

Sie können mit einer einfachen Lösung beginnen, wie sie von Tesselode oder Mr Beast veröffentlicht wurde. Aber wenn Sie anfangen, komplexe Dinge zu mischen, dh eine Kugelzeit, während ein Verlangsamungszauber gewirkt wird, bleiben Sie stecken.

Ich schlage vor, Sie implementieren eine Uhrenhierarchie :

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

Alles in Ihrem Spiel sollte Delta-Zeiten von einer der Uhr verwenden: Grafikeffekte laufen auf der GFX-Uhr, KI- und Animations-Effekte laufen auf der Gameplay-Uhr, Kreaturen, die von einem Verlangsamungszauber betroffen sind, laufen auf einer temporären Verlangsamungs-Zauberuhr usw. Dann verschiedene Dinge Auswirkungen auf verschiedene Teile Ihrer Hierarchie: Ein Verlangsamungszauber erstellt und beeinflusst eine benutzerdefinierte Uhr, während eine Aufzählungszeit die gesamte 3D-Uhrhierarchie beeinflusst.

Laurent Couvidou
quelle
Danke, das ist eine wichtige Erkenntnis. Ich denke jedoch, ich werde das Denken einfach halten, da es in meinem speziellen Fall nicht sinnvoll ist, dass mehrere Verlangsamungseffekte gleichzeitig auftreten würden.
David Miler
1

Sie benötigen nur zwei verschiedene Uhren anstelle einer, eine für die für das Gameplay relevante Zeit und eine "wahre" Zeit.

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

Dann können Sie die Spielgeschwindigkeit einfach ändern, um die Zeit zu beschleunigen (> 1) oder zu verlangsamen (<1). Damit sich der Spieler mit unterschiedlicher Geschwindigkeit bewegen kann, prüfen Sie einfach, ob die Zeit verlangsamt ist oder nicht.

API-Beast
quelle