Come gestire più thread della trama in un gioco di ruolo?


26

Ho progettato un gioco di ruolo con più thread della trama, il che significa che, a seconda della scelta dell'utente, alcune cose possono o meno accadere, puoi ottenere la stessa cosa in diversi modi, il finale può essere diverso e così via.

Ho implementato un semplice motore decisionale, che funziona bene ma ha un enorme difetto, nel momento in cui prendi una decisione la storia viene immediatamente influenzata dalla tua decisione, il che significa che non puoi prendere una decisione che ti influenzerà nel lontano futuro . Questo perché la storia si svolge come un ramo in una struttura ad albero e deve sempre sapere quale nodo è il prossimo. Sotto il cofano, le decisioni vengono implementate usando una coda: ogni nodo conosce il nodo precedente e il nodo successivo (o se è un nodo decisionale attende che l'input dell'utente imposti il ​​nodo successivo)

Ho visto molti giochi con complessi motori decisionali e mi chiedo come sono fatti? Esiste un design speciale che rende le cose davvero facili? Qualcuno ha fatto qualcosa di simile e può darmi un suggerimento su come affrontare questo?

AGGIORNAMENTO 1:

Un aspetto importante è riuscire a mantenere in qualche modo il codice della storia indipendente, in modo che possa essere manipolato da un file esterno. Ho intenzione di utilizzare questo come motore, quindi anche le possibili scelte devono provenire da un file esterno. Il codice deve essere totalmente astratto.

Inoltre, sono interessato a una soluzione di design, un bel modo di farlo, come gli altri lo fanno o lo hanno fatto.


1
Quando vengono prese le decisioni importanti, basta tenerne traccia in una variabile accessibile a livello globale (una matrice di queste variabili sarà più facile da gestire). A queste variabili è quindi possibile fare riferimento da parti successive del programma di gioco per agire o visualizzare le cose nel modo appropriato. Ad esempio, il giocatore decide di piantare un piccolo albero, e in seguito quell'albero appare molto grande - se non hanno piantato l'albero, quell'albero non sarebbe affatto lì nello stesso punto successivo del gioco.
Randolf Richardson,

Sì, è quello che inizialmente pensavo, tuttavia, ho bisogno che questo sia indipendente dal codice. Ciò significa che la storia può essere completamente manipolata da un file esterno. Quindi, devo trovare un modo per generalizzare ciò che hai appena detto e farlo in modo tale da non perdere il controllo del progetto (ci sono alcune decisioni). Aggiornerà la domanda. Grazie!
Valentin Radu,

Quindi, per essere più specifici, non posso controllare if (isTree)o mantenere un isTreevar globale perché la storia potrebbe o meno avere quella scelta. Sai cosa intendo? È più come un motore di scelta che servirà più storie.
Valentin Radu,

Anche questo ha un altro problema, diciamo che se l'utente decide di piantare un albero che abbiamo impostato isTree=true, in seguito, fa qualcos'altro, come, combattendo un compagno di scuola, che in cambio va e taglia il suo albero mentre l'albero è ancora giovane perché si è preso a calci nel culo. Ora, abbiamo 2 variabili che influenzano l'esistenza dell'albero isTree==true' and didFightBrat == false`. Sai cosa intendo? E la catena può continuare all'infinito, l'esistenza dell'albero può essere influenzata da un numero sconosciuto di fattori. Sai cosa intendo?
Valentin Radu,

Quindi archiviare quei dati in un file sul disco. È necessario creare due subroutine per caricare e salvare le informazioni, quindi utilizzare tali routine da ciascuna parte del codice secondo necessità.
Randolf Richardson,

Risposte:


18

È inoltre possibile generalizzare la coda in un grafico aciclico diretto (DAG). Puoi leggere queste informazioni su Wikipedia. Fondamentalmente, ogni nodo può avere uno o più nodi principali da cui "dipende". Non sono ammessi cicli, ovvero se A dipende da B, B non può dipendere da A (direttamente o tramite una catena indiretta di altri nodi).

Ogni nodo è in uno stato "attivo" o "inattivo" e può diventare attivo solo se tutti i suoi genitori sono già attivi. La struttura del grafico (quali nodi sono presenti e come sono collegati) fa parte dei dati di gioco, ma lo stato attivo / inattivo fa parte dei dati di salvataggio del giocatore.

In questo modo, puoi modellare cose come: quando pianti un albero, contrassegni un'attività "plantedTree" come attiva; poi, più avanti nel gioco, un'altra attività "treeGrown" nomina sia "plantedTree" che altri nodi (parte della storia) come suoi genitori. Quindi, "treeGrown" diventa attivo solo quando il giocatore arriva a quel punto della storia, e anche "plantedTree" è attivo.

Puoi includere altre funzionalità come nodi che si attivano se uno dei loro genitori si attiva, o nodi che sono attivati ​​da un genitore e disattivati ​​da un altro, e così via. È un quadro piuttosto generale per la creazione di storie con thread multipli e interdipendenti.


Un'ottima risposta, grazie. In realtà risolve anche altri problemi che ho, come salvare i progressi dell'utente. Questo è quello di cui ho bisogno.
Valentin Radu,

@NathanReed Perché questo non potrebbe essere ciclico? Essere aciclici non è in genere una caratteristica, ma un sottoprodotto della progettazione grafica. Non lo creerei con questa intenzione. Ad esempio, immagina se desideri che il tuo albero riconosca le stagioni. Sono per natura ciclici e il tuo arco narrativo potrebbe essere identico a seconda delle scelte disponibili durante una stagione.

Deve essere aciclico perché se c'è un ciclo, si entra in un ciclo infinito quando si cerca di capire se un nodo sul ciclo può essere attivo, perché si controlla ricorsivamente tutti i suoi antenati, incluso il nodo stesso. Se volessi modellare qualcosa come le stagioni, non lo farei nel contesto di questo grafico.
Nathan Reed,

@NathanReed Ah, scusa, ho perso la parte ricorsiva.

3

Da quello che ho capito, quello che vuoi non è solo un motore decisionale, ma anche un motore di regole. Per ogni decisione si esegue un sottoinsieme di regole definite da quella decisione. L'esecuzione di tali regole dipende spesso dallo stato di alcune entità come il tuo esempio di albero.

Fondamentalmente, quando il tuo giocatore prende una decisione, cerchi quella decisione, esegui le regole e poi fornisci il prossimo set di decisioni disponibili come normale. Tuttavia, le tue regole sono dinamiche in quanto alcune verranno eseguite solo in base ad altre regole che sono già state eseguite.

Qualche altro su Wikipedia .

Dal sottotitolo Quando usare i motori di regola (l'enfasi è mia):

  • Il problema è troppo complesso per il codice tradizionale.
  • Il problema potrebbe non essere complesso, ma non riesci a vedere un modo robusto per costruirlo.
  • Il problema va oltre ogni ovvia soluzione basata su algoritmo.
  • È un problema complesso da risolvere. Non ci sono soluzioni tradizionali ovvie o il problema non è completamente compreso.
  • La logica cambia spesso
  • La logica stessa può essere semplice ma le regole cambiano abbastanza spesso. In molte organizzazioni le versioni del software sono rare e le regole possono aiutare a fornire l '"agilità" necessaria e prevista in modo ragionevolmente sicuro.
  • Esperti di dominio e analisti aziendali sono prontamente disponibili, ma non tecnici.
  • Gli esperti di dominio hanno spesso una vasta conoscenza delle regole e dei processi aziendali. In genere sono non tecnici, ma possono essere molto logici. Le regole possono consentire loro di esprimere la logica secondo i propri termini. Certo, devono ancora pensare in modo critico ed essere capaci di pensare logicamente. Molte persone in posizioni non tecniche non hanno una formazione nella logica formale, quindi fai attenzione e lavora con loro. Codificando la conoscenza aziendale nelle regole, esporrete spesso buchi nel modo in cui le regole e i processi aziendali sono attualmente compresi.

Una cosa da notare è che occasionalmente un motore di regole viene implementato al meglio usando un "linguaggio" specifico di dominio semplificato, o qualcosa come YAML. Non vorrei suggerire XML.


1

Devi considerare che un evento non è basato esclusivamente sulla decisione dell'utente. Come hai notato, qualche evento deve essere aggiunto se quando viene presa una serie di decisioni e poi qualcosa d'altro si aggiunge (come due giorni dopo).

Quello di cui penso tu abbia bisogno è un modo per modellare gli eventi e un modo per attivarlo. Mentre il primo è più limitato al tuo caso specifico, il secondo può essere modellato da una macchina a stati gerarchica (HSM) che attiva direttamente o indirettamente i tuoi eventi.

Tieni presente che una macchina a stati soffre della Maledizione della dimensionalità che è mitigata solo da una struttura gerarchica. Presto capirai che devi modellare il significato complesso dello stato usando un HMS ma anche fornire un modo per interrogarlo.

In questo scenario sono presenti eventi di base (decisioni dell'utente, tempo, cambiamenti meteorologici e così via) che vengono elaborati sia dall'HSM che dai callback degli eventi di base. L'HSM fornisce un modello per la "memoria" e i callback forniscono un modo per descrivere come quella memoria deve essere utilizzata per calcolare le conseguenze di una sequenza di decisioni / eventi esterni.

Puoi anche finire per usare un dittonary (o qualche altra struttura di raccolta) di HMS, uno per ogni "aspetto" dello stato che devi calcolare. Un esempio potrebbe essere quello di utilizzare un evento HMS correlato e uno per le decisioni che i callback prendono per innescare eventi.

Tutta questa infrastruttura ha lo scopo di imitare il comportamento di un Dungeon Master umano: in genere registra mentalmente la situazione attuale (HMS ["esterno"]) a causa delle decisioni del giocatore e delle condizioni ambientali; quando qualcosa si aggiunge può prendere decisioni usando il suo record mentale e registrare anche un po 'di stato della strategia interna (HSM ["interno"]) al fine di evitare di reagire in modo simile se la situazione si presenta ad esempio.

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.