Scegli la tua avventura - stack di scelte


8

Attualmente sto costruendo un gioco di avventura a scelta. Ora è abbastanza facile avere un risultato per ogni scelta e creare un flusso lineare, ma esiste un buon algoritmo per fare in modo che tutte le selezioni precedenti influiscano sul risultato successivo? Potrei ovviamente memorizzare tutte le selezioni precedenti e avere delle grandi dichiarazioni "IF" da decidere, ma mi chiedevo se ci fosse un modo migliore?

Una parte di me si chiede se ogni scelta debba avere un 'punteggio' e quindi lo uso (forse con una soglia) per determinare quale dovrebbe essere la prossima azione e ogni azione viene aggiunta al punteggio.

Lo sto facendo principalmente in swift / SpriteKit ma penso che sia più il concetto che il codice a questo punto.

In risposta al commento di Josh qui sotto:

Suppongo di essere ancora in fase concettuale al momento, ma ogni 'pagina' sarebbe o un oggetto personalizzato o un file json. Stavo pensando alla tua risposta (ora rimossa) e forse avendo ciascuna opzione ENUM un po '. Quindi ogni pagina potrebbe avere un 'punteggio'. Quindi, utilizzando le opzioni precedenti selezionate, determinare quali bit sono impostati e ciò determina quale pagina. Immagino di essermi solo chiesto se esistesse una soluzione a questo problema prima di iniziare quasi a decidere come formattare la "storia"

Indovina approssimativa nel formato:

  { "text":"You arrive in the dungeon and there are 2 doors",
   "options":[
    1: "Go left",
    2: "Go Right"
    ],
   "score" : 0 // first page
  }
  {"text" "You went left and meet a dragon",
  "options":[
    0: "Game over, you were eaten" // something to handle game over
    ],
   "score" : 1 
  }
  {"text" "You meet a mushroom who tells you the princess is in another castle",
  "options":[
    4: "Give up, game over", // something to handle game over
    8: "Jump down the pipe"
    ],
   "score" : 2 
  }

Grazie


Come rappresenti attualmente ogni "pagina" della tua avventura? Sono tutte funzioni codificate in Swift? Stai leggendo il testo / le immagini e le opzioni disponibili per ogni pagina da un file di dati? In tal caso, che aspetto ha il file?

@JoshPetrie aggiornato con qualche informazione in più
TommyBs

Il problema di fondo è che semplicemente non esiste un modo elegante per rappresentare una narrazione non lineare con un mezzo lineare come il codice sorgente. Il metodo ideale sarebbe l'IMO di avere un editor visivo simile a UML in cui i punti di trama sono rappresentati come scatole e i possibili flussi narrativi come frecce. Ma per la maggior parte dei progetti più piccoli sarebbe probabilmente più lavoro implementare un tale editor piuttosto che scrivere a mano un pasticcio di codice spaghetti pieno di if"s else", switch"s case" e spero che tu abbia finito prima di perdere la sanità mentale.
Philipp,

@Philipp Un diagramma UML non è esattamente quello che è un grafico a oggetti? Probabilmente potresti esaminare gli approcci di serializzazione del grafico a oggetti per trovare buoni modi di rappresentare un grafico di oggetti in modo linearizzato.
uliwitness

@uliwitness Esistono diversi tipi di diagrammi UML. Il più vicino a un albero di dialogo è un diagramma di attività . Ho sperimentato vari strumenti per generare una volta il codice dai diagrammi UML e sono rimasto piuttosto deluso. Di solito si ottiene un codice piuttosto disordinato che non è ancora funzionale e necessita di alcuni metodi di compilazione manuale dei metodi stub.
Philipp,

Risposte:


12

Molti giochi Adventure / RPG gestiscono questo in due modi (potrebbero essercene altri di cui non sono a conoscenza).

Uso di bandiere

Il primo è quello di impostare una bandiera se succede qualcosa (di solito una maschera di bit). Va bene se non hai molte cose da tracciare. Nella stanza / incontro potrebbe esserci un segno di spunta contro una bandiera che altera qualcosa. Nel tuo esempio potresti aggiungere una regola:

{"text" "You meet a mushroom who tells you the princess is in another castle",
"options":[
  4: "Give up, game over", // something to handle game over
  8: [64:"Jump down the pipe", "Exit stage left"]
  ],
 "score" : 2
 "setflag" : 32
}

Dove la seconda opzione appare solo se flags & 64è impostata. Potresti anche implementare l' setflagopzione se appare la scena o è stata fatta una scelta particolare.

Uso di oggetti

La seconda opzione è quella di aggiungere oggetti all'inventario del giocatore. Questi sono i "questo oggetto è necessario per completare una missione" che vedi spesso nei giochi. Fondamentalmente funzionano come "bandiere" portatili. Questo può essere implementato in due modi (o una combinazione):

  • L'oggetto è la 'bandiera': fai controllare alla scena o al dialogo se il giocatore ha un oggetto specifico nel suo inventario. Questo è molto simile al meccanico "cerca una bandiera" come descritto sopra. Il lato positivo è che potrebbe essere molto più facile per te progettare incontri mentre stai controllando oggetti familiari noti.

  • Gli oggetti hanno proprietà che funzionano come una bandiera. Ad esempio in The Witcher 3, il giocatore ottiene un oggetto in grado di dissipare i muri illusori. Quell'elemento stesso potrebbe essere una "bandiera", ma potrebbe anche essere che l'oggetto abbia una proprietà can_dispel_illusions. Il lato positivo è che è possibile implementare più oggetti che possono essere utilizzati nello stesso scenario. Quindi una scena / finestra di dialogo / porta potrebbe verificare se il giocatore ha "qualcosa" nel suo inventario che ha la proprietà can_dispel_illusions.

Questo ti dà la possibilità di dare al giocatore l'illusione della scelta; se il giocatore non incontrava la strega nella prima scena, mancando così la "bacchetta di dissipazione", il giocatore poteva ottenere un "anello di dissipazione" in seguito da un mercante ombroso, impedendo uno stato di gioco inattaccabile.

Se non prevedi di dare al giocatore un inventario "reale", gli oggetti missione potrebbero andare in un elenco nascosto al giocatore.

esempio:

{"items":[
  "Wand of Dispel": { "properties": ["can_dispel_illusions","illumination"]}
]}

e:

{"text" "The corridor ends in a dead end. The wall feels cold when you touch it.",
"options":[
  4: "Turn back", 
  8: {"can_dispel_illusions": "Check if the wall is real."} 
  ],
 "score" : 2 
}

{"text" "The witch hands you an object. She observes what you're going to do next.",
"options":[
  14: "Leave the witch's house", 
  22: "Look at the object."} 
  ],
 "giveitem" : "Wand of Dispel" 
}

2

Una soluzione che ho visto che elabora il tuo approccio è quella di avere vari attributi con punteggi associati. Alcune scelte comportano la modifica di uno o più di questi punteggi. I punteggi a loro volta possono modificare le scelte disponibili per il giocatore.

Ad esempio, all'inizio della storia, potrebbero esserci degli incontri di combattimento tra opzioni. Se il giocatore si impegna in combattimento, l'attributo di coraggio aumenterebbe, mentre la fuga lo farebbe diminuire. In seguito, un determinato ramo della storia potrebbe essere disponibile solo se il punteggio di coraggio era al di sopra o al di sotto di una determinata soglia. Per aggiungere più profondità, alcune decisioni dovrebbero influenzare più di un punteggio. Ad esempio, scegliere le tasche potrebbe aumentare un punteggio invisibile e diminuire un punteggio di onestà.

In generale, ho visto questo approccio usato nella narrativa interattiva di tipo simulazione. Puoi ascoltare Dan Fabulich di Choice Of Games discutere questa soluzione in questo episodio della tavola rotonda di Game Design.

I vantaggi di questo approccio sono:

  • ogni decisione non deve fornire un finale univoco, riducendo il numero totale di finali richiesti
  • può esserci più di un modo per raggiungere un determinato finale, consentendo una maggiore varietà di stili di gioco gratificanti

Alcuni svantaggi sono:

  • se le decisioni dipendono da singoli attributi, può essere superficiale e di formula
  • viceversa, se le decisioni sono troppo complesse, il bilanciamento del gioco / della storia diventa più difficile

1

Questo è il grande problema dei giochi basati sulla trama: l'esplosione combinatoria. In quanto tale, se guardi ad esempio giochi Bioware o Telltale, scoprirai che l'approccio più comune sembra essere ancora quello di cercare di limitare la trama a essere più lineare e mantenere le conseguenze delle azioni limitate ai loro capitoli.

L'approccio che Bioware sembra utilizzare divide ogni storia in fili o sotto-archi separati. Gli archi sono praticamente indipendenti l'uno dall'altro, ma si verificano simultaneamente e possono tutti contribuire alla fine. In questo modo, non è necessario modellare ciascuna combinazione di archi, si alternano solo capitoli tra archi e le conseguenze sono limitate al particolare arco secondario con cui si ha a che fare in questo momento o al modo in cui terminare un arco. (o come terminare l'arco di un personaggio. Se non hai più bisogno di quell'NPC, ti viene spesso data la possibilità di ucciderli, arrestarli o liberarli, ad esempio, dandoti scelta, ma limitando le conseguenze al resto della storia)

La fine dell'intera storia deve quindi solo sapere come è terminato ogni arco e legare l'intera narrazione in un piccolo arco pulito.

Come lo modelleresti in un programma?

Questo semplicemente spinge il problema verso il basso di un livello (perché ogni arco secondario deve tenere traccia delle differenze come farebbe una storia semplice), ma fondamentalmente avresti una serie di flag (ad esempio un campo bit o un elenco di elementi con flag che rappresentano il capacità di effettuare determinati esiti) per ciascun arco secondario.

Inoltre, quando dici il tuo finale, di solito segui lo stesso approccio dell'alternarsi quando parli al giocatore delle conseguenze: il risultato di ogni sotto-arco ottiene il proprio nodo paragrafo / conversazione, semplificando notevolmente i tuoi condizionali.


0

Potrebbe volerci un po 'di tempo, ma lo sviluppo del tuo albero (come un albero di comportamento o un albero di dialogo, ma per le pagine) potrebbe essere utile. E potresti usarne uno come modello. Qualcosa come questo:

Come funzionano gli alberi di dialogo?

Ciò ti consentirebbe di adattarlo alle tue esigenze specifiche, ma consentirà anche al codice di gestire la maggior parte del lavoro.


0

Cosa succede se si utilizza un approccio del tipo di motore di regole? Quando un giocatore interagisce con un NPC, il gioco avvia un motore di regole ridotto che inizia con le bandiere create da scelte / comportamenti passati e lo verifica in anticipo con una serie di regole da te definite. Qualcosa come Drools è probabilmente troppo grande e ambizioso, per non parlare lento, ma un motore di regole di portata limitato potrebbe teoricamente offrirti prestazioni migliori e molta flessibilità.

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.