2009-04-28 15 views
11

Sto creando un gioco basato sulla griglia in Java e voglio implementare la registrazione e la riproduzione del gioco. Non sono sicuro di come fare questo, anche se ho pensato di 2 idee:Il modo migliore per implementare la riproduzione del gioco?

  1. Più volte ogni secondo, mi piacerebbe registrare l'intero stato del gioco. Per riprodurlo, scrivo un renderer per leggere gli stati e provare a creare una rappresentazione visiva. Con questo, tuttavia, probabilmente avrei un grande file di salvataggio, e qualsiasi tentativo di riproduzione avrebbe probabilmente un lag evidente.

  2. Potrei anche scrivere ogni pressione di tasto e fare clic con il mouse sul file di salvataggio. Questo mi darebbe un file più piccolo e potrei riprodurre con meno lag. Tuttavia, il minimo errore all'inizio del gioco (ad esempio, sparare 1 millisecondo dopo) si tradurrebbe in uno stato di gioco molto diverso nel gioco.

Qual è, quindi, il modo migliore per implementare la riproduzione del gioco?

Modifica- Non sono sicuro di quanto deterministico sia il mio gioco, quindi non sono sicuro che l'intero gioco possa essere riunito esattamente registrando solo i tasti e i clic del mouse.

risposta

14

Un buon meccanismo di riproduzione non è qualcosa che può essere semplicemente aggiunto a un gioco senza gravi difficoltà. La cosa migliore sarebbe progettare l'infrastruttura del gioco pensando a questo. È possibile utilizzare lo command pattern per ottenere un'infrastruttura di gioco del genere.

Ad esempio:

public interface Command{ 
    void execute(); 
} 
public class MoveRightCommand implements Command { 
    private Grid theGrid; 
    private Player thePlayer; 

    public MoveRightCommand(Player player, Grid grid){ 
     this.theGrid = grid; 
     this.thePlayer = player; 
     } 

    public void execute(){ 
    player.modifyPosition(0, 1, 0, 0); 
    } 
} 

E poi il comando può essere spinto in una coda di esecuzione sia quando l'utente preme un tasto della tastiera, sposta il mouse o senza un trigger con il meccanismo di riproduzione. L'oggetto comando può avere un valore di data/ora (relativo all'inizio della riproduzione) per una riproduzione precisa ...

+2

Questo è un modo elegante per gestirlo. Se il gameplay effettivo e la registrazione sono basati sullo stesso meccanismo di timing/frame, è necessario evitare errori dovuti a problemi di temporizzazione. Se hai randomizzazione nei tuoi eventi, potresti dover registrare anche il valore iniziale del seme per il tuo generatore di numeri casuali. Ecco come le funzioni "Mappa casuale" nei giochi RTS ti consentono di rigenerare una mappa casuale che ti è piaciuta. –

+0

Questo modello può anche fornire funzionalità Annulla/Ripristina. –

2

Perché non registrare più volte al secondo e poi comprimere l'output, o forse fare questo:

recordInitialState(); 
... 
runs 30 times a second: 
recordChangeInState(previousState, currentState); 
... 

Se si registra solo il cambiamento di stato con un timestamp (e ogni cambiamento è piccolo, e se non ci non cambia, quindi non registra nulla), dovresti finire con file di dimensioni ragionevoli.

3

Supponendo che il tuo gioco sia deterministico, potrebbe essere sufficiente se hai registrato gli input degli utenti (opzione 2). Tuttavia, è necessario assicurarsi di riconoscere i tempi corretti e coerenti per questi eventi, ad esempio quando è stato riconosciuto dal server. Non sono sicuro di come gestisci gli eventi nella griglia.

La mia preoccupazione è che se non si dispone di un meccanismo che possa riferirsi uniformemente a eventi temporizzati, potrebbe esserci un problema con il modo in cui il codice gestisce gli utenti distribuiti.

Considerate un gioco come Halo 3 su XBOX 360 per esempio - ogni cliente registra la sua visione del gioco, incluse correzioni basate su server.

2

Non è necessario salvare tutto nella scena per ogni fotogramma. Salvare le modifiche in modo incrementale e utilizzare alcune buone tecniche di interpolazione. Non utilizzerei realmente un approccio basato sul modello di comando, ma piuttosto effettuerei controlli a una velocità fissa per ogni oggetto di gioco e vedere se ha cambiato qualsiasi attributo. Se c'è un cambiamento, quel cambiamento è registrato in qualche buona codifica e il replay non diventerà così grande.

2

Il modo in cui ci si avvicina dipende molto dalla lingua che si sta utilizzando per il proprio gioco, ma in termini generali ci sono molti approcci, a seconda se si desidera utilizzare molta memoria o si desidera un certo ritardo. Sarebbe utile se potessi dare alcuni pensieri su quali sacrifici sei disposto a fare.

Ma, sembrerebbe l'approccio migliore potrebbe essere semplicemente salvare l'input dall'utente, come è stato menzionato, e memorizzare le posizioni di tutti gli attori/sprite nel gioco allo stesso tempo, che è così semplice come solo salvare la direzione, la velocità e le tessere x, y, o, se tutto può essere deterministico, ignorare gli attori/sprite mentre riesci a ottenere le loro informazioni.

In che modo il tuo gioco non deterministico sarebbe utile anche per dare un suggerimento migliore.

Se è presente una grande quantità di movimento dinamico, ad esempio un crash derby, è possibile che si desideri salvare le informazioni su ciascun fotogramma, poiché è necessario aggiornare i giocatori/attori a un determinato framerate.

2

vorrei semplicemente dire che il modo migliore per registrare un replay di un gioco dipende interamente dalla natura del gioco. Essere basati sulla griglia non è il problema; il problema è come il comportamento prevedibile sta seguendo un cambiamento di stato, quanto spesso ci sono nuovi input per il sistema, se ci sono dati casuali iniettati in qualsiasi momento, ecc. Puoi memorizzare un intero gioco di scacchi semplicemente registrando ciascuna mossa a turno, ma quello non funzionerebbe per uno sparatutto in prima persona dove non ci sono svolte chiare. Puoi memorizzare uno sparatutto in prima persona annotando l'ora esatta di ciascun ingresso, ma ciò non funzionerà per un gioco di ruolo in cui il risultato di un input potrebbe essere modificato dal risultato di un tiro di dadi casuale. Anche l'idea apparentemente infallibile di scattare un'istantanea il più spesso possibile non è abbastanza buona se informazioni importanti appaiono istantaneamente e non persistono in alcuna forma catturabile.

È interessante notare che questo è molto simile al problema che si ottiene con il networking. Come fa un computer a garantire che un altro computer sia informato dello stato del gioco, senza dover inviare l'intero stato del gioco a una frequenza troppo alta? L'approccio tipico finisce per essere una miscela su misura di notifiche di eventi e aggiornamenti di stato, che è probabilmente ciò di cui avrete bisogno qui.

1

L'ho fatto una volta prendendo in prestito un'idea dalla compressione video: fotogrammi chiave e fotogrammi intermedi. In sostanza, ogni pochi secondi si salva lo stato completo del mondo. Quindi, una volta per aggiornamento del gioco, salvi tutte le modifiche allo stato del mondo che sono accadute dall'ultimo aggiornamento del gioco. I dettagli (con quale frequenza salvate i keyframe? Che cosa conta esattamente come un "cambiamento nello stato del mondo"?) Dipenderà dal tipo di informazioni di gioco che è necessario conservare.

Nel nostro caso, il mondo era costituito da molti, molti oggetti di gioco, la maggior parte dei quali erano fermi in un dato momento, quindi questo approccio ci ha risparmiato un sacco di tempo e memoria nel registrare le posizioni di oggetti che non erano in movimento. Nel tuo i compromessi potrebbero essere diversi.

Problemi correlati