Il modo migliore per gestire gli eventi di gioco?


13

Sto lavorando a un gioco in cui alcuni eventi di gioco devono accadere di tanto in tanto. Un bell'esempio sarebbe un tutorial. Inizi il gioco e in diversi punti del gioco si verifica un evento:

  • Incontri il tuo primo nemico, il gioco fa una pausa e ricevi una spiegazione su come ucciderlo.
  • Hai ucciso il primo nemico, ricevi un messaggio di "buon lavoro".
  • Ottieni un nuovo oggetto, un menu con il popup delle statistiche degli oggetti.
  • ecc ecc.

Il gioco a cui sto lavorando è un puzzle game in cui le regole del gioco sono praticamente tutte uguali, quindi sembra inefficiente codificare tutti questi eventi in livelli separati.

Dovrei in qualche modo definire questi eventi in una fonte esterna, come XML? Quindi scrivere un interprete che legge l'XML e imposta i requisiti degli eventi per il livello? Non sono sicuro di come definire un evento che dovrebbe verificarsi quando, ad esempio, hai ucciso due nemici.

Giusto per essere chiari, non sto cercando il miglior linguaggio di programmazione o linguaggio di scripting per farlo, ma piuttosto il metodo migliore per gestirlo.

Grazie!


Modifica: un secondo esempio poiché la mia domanda era piuttosto difficile da capire:

Il problema che sto avendo è quello di mettere alcune azioni extra nel gioco in una procedura che è sempre più o meno la stessa. Come in una battaglia di ruolo, ognuno ha un turno, sceglie un'abilità ecc. È sempre lo stesso. E se ci fosse un caso in cui mi piacerebbe mostrare una scena da qualche parte nel mezzo. Modificare l'intera struttura del gioco per passare in una classe di battaglia alterata con la scena inclusa sembra molto inefficiente. Mi chiedo come si fa di solito.


8
Non tentare di generalizzare eccessivamente le cose, ad esempio i tutorial sono molto specifici e vengono forniti con molti trigger / eventi diversi. Niente di male con hardcoding / scripting.
Maik Semder,

1
@Maik Se lo metti in una risposta Id +1 esso .. Semplice e risolto è meglio che bello ogni giorno.
James,

Il tuo secondo esempio rende molto più chiaro che un sistema di messaggistica astratto sarebbe una grande vittoria. Per un tutorial puoi semplicemente codificare le cose poiché accadono solo una volta all'inizio, ma per eventi in corso che possono accadere in qualsiasi momento durante l'intera durata del gioco, ben diverso.
scherzare il

È ancora un po 'vago, si prega di elencare almeno 3 trigger per 3 diverse scene. è molto difficile rispondere in generale. Fondamentalmente devi trovare un modello comune per capire come implementarlo al meglio.
Maik Semder,

Cosa vuoi? Vuoi mettere in pausa le azioni e fare il extra, quindi riprendere le azioni?
user712092

Risposte:


7

Questo dipende molto da come gli eventi vengono effettivamente comunicati tra gli oggetti nel tuo gioco. Ad esempio, se si utilizza un sistema di messaggistica centrale, è possibile disporre di un modulo tutorial che ascolti determinati messaggi e crei popup tutorial ogni volta che sente determinati messaggi. Quindi puoi impostare quale messaggio ascoltare, insieme a quale popup mostrare, in un file XML o qualcosa che viene analizzato dal modulo tutorial. Avendo un oggetto tutorial separato che monitora lo stato del gioco e visualizza i popup del tutorial quando nota qualcosa nel gioco, puoi cambiare l'oggetto tutorial a piacimento senza dover cambiare nient'altro sul tuo gioco. (È questo il modello Observer? Non ho familiarità con tutti i modelli di progettazione.)

Nel complesso, tuttavia, dipende dalla complessità del tutorial se vale la pena preoccuparsene. La codifica degli eventi nel tuo codice e / o livello non mi sembra un grosso problema per una manciata di popup di tutorial. Sono curioso di sapere esattamente cosa hai in mente che ti faccia pensare che sarà inefficiente, dal momento che tutto ciò che dovresti fare ogni trigger è semplicemente inviare un messaggio al modulo tutorial, qualcosa come TutorialModule.show ("1st_kill");


Penso che dal momento che è un puzzle game la sua logica è in una posizione per più livelli e così, facendo i controlli per fare un tutorial per questo è qualcosa che dura dappertutto. Onestamente, se si tratta di un puzzle game, non credo che questo avrà un grande successo, anche se non è il codice più carino, e alla fine della giornata il codice che funziona in un gioco che viene spedito è sempre -sempre- 100% migliore del grazioso codice che non vede mai la luce del giorno;)
James,

Non ho mai pensato a qualcosa come il modello di osservatore, sembra una bella soluzione. Ci proverò, grazie :)
omgnoseat

7

Ecco i vincoli di progettazione come li capisco:

  1. Il codice di gioco principale non tiene conto dei requisiti di livello e non deve essere associato al codice che li tratta.

  2. Allo stesso tempo, è il codice di gioco principale a sapere quando si verificano gli eventi specifici che soddisfano tali requisiti (ottenere un oggetto, uccidere un nemico, ecc.)

  3. Livelli diversi hanno insiemi di requisiti diversi e quelli devono essere descritti da qualche parte.

Dati questi, probabilmente farei una cosa del genere: in primo luogo, creare una classe che rappresenti un livello di gioco. Incapsulerà l'insieme di requisiti specifici di un livello. Ha metodi che possono essere chiamati quando si verificano eventi di gioco.

Fornisci al codice di gioco principale un riferimento all'oggetto livello corrente. Quando si verificano gli eventi di gioco, vi dirà il livello chiamando i metodi su di esso: enemyKilled, itemPickedUp, etc.

Internamente, ha Levelbisogno di alcune cose:

  • Stato per tenere traccia degli eventi che si sono già verificati. In questo modo è in grado di distinguere il primo nemico ucciso dagli altri e conosce la prima volta che hai raccolto un determinato oggetto.
  • Un elenco di LevelRequirementoggetti che descrivono il set specifico di obiettivi necessari per quel livello.

Quando entri in un livello, creerai un Levelcon le LevelRequirements giuste , configurerai il codice di gioco e gli assegnerai quel livello.

Ogni volta che si verifica un evento di gioco, il gioco lo passa a Level. Che a sua volta calcola i dati aggregati (numero totale di nemici uccisi, nemici di quel tipo uccisi, ecc.) Quindi passa attraverso i suoi oggetti richiesti, fornendo a ciascuno i dati aggregati. Un requisito verifica se è soddisfatto e, in tal caso, genera qualunque comportamento risultante sia appropriato (mostrando il testo del tutorial, ecc.)

LevelRequirement fondamentalmente ha bisogno di due cose:

  1. Una descrizione di un test per dire se il requisito è stato soddisfatto. Questa può essere solo una funzione se la tua lingua lo rende così semplice, altrimenti puoi modellarla nei dati. (Vale a dire un RequirementTypeenum con cose del genere FIRST_KILLe poi un grande switchche sa come controllare ogni tipo.)
  2. Un'azione da eseguire quando viene soddisfatto il requisito.

C'è ancora la questione di dove siano descritti questi insiemi di requisiti. Potresti fare qualcosa come XML o un altro formato di file di testo. È utile se:

  1. I non programmatori saranno livelli di creazione.
  2. Volete essere in grado di cambiare i requisiti senza ricompilare e / o riavviare.

Se nessuno di questi è il caso, probabilmente li costruirò direttamente nel codice. Semplice è sempre meglio.


I primi 3 punti sono una descrizione molto ravvicinata del metodo che sto usando ora, impressionante! Sì, la cosa con cui sto lottando di più è dove descrivere il requisito e come tradurlo nel gioco (dal momento che molto probabilmente sarà qualcosa di esterno). Grazie per la spiegazione approfondita :)
omgnoseat

5

Pensavo che dovessi sapere come organizzare questi eventi e il resto dei post è su di esso, se vuoi semplicemente archiviare questi eventi, utilizza un database relazionale o decodificali tramite testo e usa il linguaggio di scripting (eseguirà l'analisi e la valutazione per Voi). :)

Quello che vuoi è riconoscere gli eventi accaduti (1) e quindi fare alcune azioni richieste da questi eventi (stampa messaggio, verifica la pressione dei tasti ...) (2). Vuoi anche far accadere questi eventi una sola volta (3).

Fondamentalmente si desidera verificare le condizioni e quindi pianificare alcuni comportamenti.

Come riconoscere gli eventi (1)

  • Vuoi riconoscere eventi come questi "primo nemico incontrato", "nuovo oggetto guadagnato"
  • se succede una parte generica, " nemico incontrato ", " oggetto guadagnato " Controlli la parte specifica " prima ...", " nuovo oggetto guadagnato"

Di cosa sono fatti gli eventi

In una visione più generale, ciascuno di questi eventi è composto da:

  • precondizioni , le controlli
  • azioni che verranno eseguite quando saranno soddisfatte le condizioni preliminari (dì "" Hai schiaffeggiato il primo nemico! ", dì" "crea combinazioni premendo i pulsanti A e B", dì "premi 'invio' per continuare", tasto "invio")

Come conservare questi eventi

In alcune strutture di dati:

  • avere un elenco di precondizioni (stringhe o codice se lo si sta scrivendo in un linguaggio di alto livello)
  • avere un elenco di azioni (potrebbero essere stringhe, il motore di Quake utilizza stringhe per eventi)

Puoi anche memorizzarlo nel database relazionale, anche se sembra che non sia necessario, se vuoi creare questo gioco in grande potresti averne bisogno.

Devi quindi analizzare queste stringhe / cose. Oppure puoi usare un linguaggio di scripting come Python o LUA o un linguaggio come LISP, tutti possono analizzarlo ed eseguirlo per te. :)

Come usare questi eventi nel game loop (2)

Avrai bisogno di queste due strutture di dati:

  • coda di eventi (gli eventi programmati per essere eseguiti vengono inseriti qui)
  • coda di azioni (azioni pianificate, eventi implicano quali azioni vengono eseguite)

Algoritmo:

  • Se si riconosce alcuni dei evento 's precondizioni sono soddisfatte Lo mette in coda di eventi
  • (3) Quindi dovresti assicurarti che questo evento si sia verificato solo una volta se vuoi :) (ad esempio con array booleano has_this_event_happened ["primo nemico incontrato"])
  • (se la coda delle azioni è vuota, quindi) Se c'è un evento nella coda degli eventi Metti le sue azioni nella coda delle azioni e rimuovilo dalla coda degli eventi
  • Se è presente un'azione nella coda di azioni Si inizia a fare ciò che è richiesto da essa
  • Se tale azione viene eseguita, la si rimuove dalla coda azioni

Come effettuare queste azioni (2)

Fai una lista di oggetti, che hanno la funzione "aggiorna". A volte sono chiamati entità (nel motore di Quake) o attori (nel motore di Unreal).

  1. Questi oggetti vengono avviati quando viene richiesto di avviarli nella coda di azioni.
  2. questi oggetti possono essere usati per altre cose come altri timer. In Quake queste entità sono utilizzate per l'intera logica di gioco, ti consiglio di leggere del materiale a riguardo .

Azione "dì qualcosa"

  1. Stampi qualcosa sullo schermo
  2. Vuoi che questo messaggio appaia per pochi secondi
  3. in "aggiorna":
    • rendere variabile remove_me_after e diminuirla nel tempo che è passato
    • quando la variabile è 0 Rimuovete questa azione dalla coda di azioni
    • Rimuovi anche questo oggetto (o pianificalo per la rimozione ...)

Azione "richiede chiave"

  1. Dipende da come vuoi farlo, ma penso che tu faccia un messaggio
  2. in "aggiorna" ":
    • Basta controllare l'evento keypress desiderato
    • Probabilmente avrai bisogno di qualche array / coda per contenere eventi keypress
    • quindi è possibile rimuoverlo dalla coda di azioni e rimuovere l'oggetto

Quali metodi per imparare


-1 giusto, o chiama semplicemente una funzione, sul serio, OP vuole solo una finestra di messaggio quando viene soddisfatta una certa condizione
Maik Semder

È una bella scrittura, ma non è esattamente quello che stavo cercando. Ho avuto difficoltà a spiegare cosa voglio. Ho aggiunto una seconda spiegazione: il problema che sto avendo è quello di mettere alcune azioni extra nel gioco in una procedura che è sempre più o meno la stessa. Come in una battaglia di ruolo, ognuno ha un turno, sceglie un'abilità ecc. È sempre lo stesso. E se ci fosse un caso in cui avrei mostrato una scena tagliata da qualche parte nel mezzo. Modificare l'intera struttura del gioco per passare in una classe di battaglia alterata con il cutene incluso sembra molto inefficiente. Mi chiedo come si fa di solito?
omgnoseat
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.