Se fai una chiacchierata con un fan dei giochi di ruolo, non ci vorrà molto per sentire una sfuriata su risultati e bottini casuali e su quanto frustranti possano essere. Molti giocatori hanno reso nota questa irritazione, e mentre alcuni sviluppatori hanno creato soluzioni innovative, molti ci stanno ancora costringendo a superare le esasperanti prove di perseveranza.
C'è un modo migliore. Modificando il modo in cui noi sviluppatori utilizziamo numeri casuali e i loro generatori, siamo in grado di creare esperienze coinvolgenti che spingono per quella "perfetta" difficoltà senza spingere i giocatori oltre il limite. Ma prima di entrare in questo, andiamo oltre alcune nozioni di base sui generatori di numeri casuali (o RNG in breve).
I numeri casuali sono intorno a noi, usati per aggiungere variazioni al nostro software. In generale, gli usi principali degli RNG sono rappresentare eventi caotici, mostrare volatilità o comportarsi come un limitatore artificiale.
Probabilmente interagisci con numeri casuali, o i risultati delle loro azioni, ogni giorno. Sono utilizzati in prove scientifiche, videogiochi, animazioni, arte e quasi tutte le applicazioni sul tuo computer. Ad esempio, un RNG è probabilmente implementato nelle animazioni di base sul telefono.
Ora che abbiamo parlato di cosa sia un RNG, diamo un'occhiata alla sua implementazione e a come può migliorare i nostri giochi.
Quasi tutti i linguaggi di programmazione utilizzano un RNG standard nelle funzioni di base. Funziona restituendo un valore casuale tra due numeri. Gli RNG standard possono essere implementati in dozzine di modi diversi su sistemi diversi, ma generalmente hanno lo stesso effetto: restituire un numero casuale in cui ogni valore nell'intervallo ha la stessa possibilità di essere restituito.
Per i giochi, questi sono comunemente usati per simulare i dadi rotanti. Idealmente, dovrebbero essere usati solo in situazioni in cui si desidera che ogni risultato si verifichi un numero uguale di volte.
Se vuoi sperimentare con rarità o diversi tassi di randomizzazione, questo metodo successivo è più adatto a te.
Questo tipo di RNG è la base per qualsiasi gioco di ruolo con rarità di oggetti. Nello specifico, quando hai bisogno di un risultato randomizzato ma vuoi che alcuni si presentino con meno frequenza di altri. Nella maggior parte delle classi di probabilità, questo è comunemente rappresentato con un sacchetto di biglie. Con gli RNG pesati, la tua borsa potrebbe avere tre biglie blu e una rossa. Dal momento che vogliamo un solo marmo, ne otterremo uno rosso o uno blu, ma è molto più probabile che sia blu.
Perché la randomizzazione ponderata è importante? Usiamo gli eventi di gioco di SimCity come esempio. Se ogni evento è stato selezionato usando metodi non ponderati, allora il potenziale per ogni evento che si verifica è statisticamente lo stesso. Ciò rende altrettanto probabile che tu possa ottenere una proposta per un nuovo casinò per sperimentare un terremoto in-game. Aggiungendo la ponderazione, possiamo garantire che questi eventi si verifichino in una quantità proporzionale che preserva il gameplay.
In molti corsi di informatica o libri, questo metodo viene spesso definito una "borsa". Il nome è bello sul naso, usando classi o oggetti per creare una rappresentazione virtuale di una borsa letterale.
Funziona fondamentalmente in questo modo: c'è un contenitore in cui gli oggetti possono essere collocati nel punto in cui sono memorizzati, una funzione per posizionare un oggetto nella 'borsa' e una funzione per selezionare casualmente un oggetto dal 'sacchetto'. Per riferirti al nostro esempio di marmo, questo significa che dovresti trattare la tua borsa come contenente un marmo blu, un marmo blu, un marmo blu e un marmo rosso.
Utilizzando questo metodo di randomizzazione, possiamo determinare approssimativamente la velocità con cui si verifica un risultato per aiutare a omogeneizzare l'esperienza di ciascun giocatore. Se dovessimo semplificare i risultati su una scala da "Molto male" a "Molto buono", ora abbiamo reso molto più praticabile che un giocatore possa sperimentare una serie inutile di risultati indesiderati (come ricevere il risultato "Molto cattivo" 20 volte di seguito).
Tuttavia, è ancora statisticamente possibile ricevere una serie di risultati negativi, solo sempre meno. Daremo un'occhiata a un metodo che va leggermente oltre per ridurre i risultati indesiderati a breve.
Ecco un rapido esempio di pseudocodice di come potrebbe apparire una classe di borsa:
Class Bag // Mantieni un array di tutti gli elementi presenti nella borsa Array itemsInBag; // Riempi il sacchetto con gli oggetti quando è stato creato Constructor (Array startingItems) itemsInBag = startingItems; // aggiungi un oggetto alla borsa passando l'oggetto (quindi spingilo semplicemente sull'array) Funzione addItem (oggetto Object) itemsInBag.push (item); // Per ottenere un elemento casuale restituito, utilizzare una funzione casuale incorporata per afferrare un elemento dall'array Funzione getRandomItem () return (itemsInBag [random (0, itemsInBag.length-1)]);
Analogamente all'implementazione del raggruppamento di prima, lo slot rarità è un metodo di standardizzazione per determinare i tassi (in genere per semplificare il processo di progettazione del gioco e la ricompensa del giocatore).
Invece di determinare individualmente il tasso di ogni oggetto in un gioco, creerai una rarità rappresentativa, in cui il tasso di un "Comune" potrebbe rappresentare un 20 in X probabilità di un determinato risultato, mentre "Raro" potrebbe rappresentare un 1 in X possibilità.
Questo metodo non cambia molto nella funzione effettiva della borsa stessa, ma piuttosto può essere usato per aumentare l'efficienza alla fine dello sviluppatore, consentendo ad un numero esponenzialmente elevato di oggetti di essere rapidamente assegnato ad una possibilità statistica.
Inoltre, lo slargamento delle rarità è utile per modellare la percezione di un giocatore, consentendo facilmente loro di capire la frequenza con cui un evento può accadere senza eliminare la loro immersione attraverso il crunch del numero.
Ecco un semplice esempio di come potremmo aggiungere rarity slotting alla nostra borsa:
Class Bag // Mantieni un array di tutti gli elementi presenti nella borsa Array itemsInBag; // aggiungi un oggetto al sacco passando l'oggetto Function addItem (oggetto Object) // tieni traccia del loop relativo alle slot di rarità Int timesToAdd; // Controlla la variabile rarity sull'elemento // (ma prima crea quella variabile rarità nella classe item, // preferibilmente con un tipo enumerato) Switch (item.rarity) Case 'common': timesToAdd = 5; Caso "non comune": timesToAdd = 3; Caso "raro": timesToAdd = 1; // Aggiungi istanze dell'articolo al sacchetto secondo la rarità While (timesToAdd> 0) itemsInBag.push (item); timesToAdd--;
Abbiamo parlato di alcuni dei metodi più comuni per gestire la randomizzazione nei giochi, quindi analizziamone uno più avanzato. Il concetto di utilizzare tassi variabili inizia in modo simile a quello di prima: abbiamo un determinato numero di risultati e sappiamo quante volte vogliamo che si verifichino. La differenza con questa implementazione è che vogliamo regolare il potenziale per i risultati non appena si verificano.
Perché dovremmo farlo? Prendi, ad esempio, giochi con un aspetto da collezione. Se hai dieci risultati possibili per l'oggetto che ricevi, essendo nove "comuni" e uno "raro", allora le tue probabilità sono piuttosto semplici: il 90% delle volte, un giocatore otterrà il comune e il 10% del totale. tempo avranno il raro. Il problema arriva quando prendiamo in considerazione più estrazioni.
Diamo un'occhiata alle tue possibilità di disegnare una serie di risultati comuni:
Mentre il rapporto iniziale di 9: 1 sembrava inizialmente un tasso ideale, finiva solo per rappresentare il risultato medio e lasciava 1 su 10 giocatori che spendevano il doppio del tempo previsto per ottenere quel raro. Inoltre, il 4% dei giocatori spenderebbe tre volte il tempo per ottenere il raro, e uno sfortunato 1,5% spenderebbe quattro volte più a lungo.
La soluzione sta implementando un intervallo di rarità sui nostri oggetti. A tale scopo, definisci sia una rarità massima e minima per ogni oggetto (o slot di rarità, se desideri combinarlo con l'esempio precedente). Per esempio, diamo al nostro oggetto comune un valore minimo di rarità di 1, con un massimo di 9. Il raro avrà un valore minimo e massimo di 1.
Ora, con lo scenario di prima, avremo dieci voci e nove di queste sono un'istanza di un comune, mentre una di esse è rara. Alla prima estrazione, c'è il 90% di possibilità di ottenere il comune. Con i tassi variabili ora, dopo che è stato disegnato il comune, abbasseremo il suo valore di rarità di 1.
Questo fa sì che il nostro prossimo sorteggio abbia un totale di nove elementi, otto dei quali sono comuni, con una probabilità dell'89% di pescare un comune. Dopo ogni risultato comune, la rarità di quell'oggetto diminuisce, rendendo più probabile che tiri il raro fino a quando non ci tocchiamo con due oggetti nella borsa, uno comune e uno raro.
Mentre prima c'era il 35% di possibilità di pescare 10 commons di fila, ora c'è solo una possibilità del 5%. Per i risultati anomali, come il disegno di 20 beni comuni di seguito, le probabilità sono ora ridotte allo 0,5% e ancora più in basso. Questo crea un risultato più coerente per i nostri giocatori e previene quei casi limite in cui un giocatore ha ripetutamente un cattivo risultato.
L'implementazione più basilare del tasso variabile sarebbe quella di rimuovere un oggetto dalla borsa, piuttosto che semplicemente restituirlo, in questo modo:
Class Bag // Mantieni un array di tutti gli elementi presenti nella borsa Array itemsInBag; // Riempi il sacchetto con gli oggetti quando è stato creato Constructor (Array startingItems) itemsInBag = startingItems; // aggiungi un oggetto alla borsa passando l'oggetto (quindi spingilo semplicemente sull'array) Funzione addItem (oggetto Object) itemsInBag.push (item); Funzione getRandomItem () // seleziona un oggetto casuale dalla borsa Var currentItem = itemsInBag [random (0, itemsInBag.length-1)]; // riduci il numero di istanze di quell'elemento se è sopra il minimo If (instancesOf (currentItem, itemsInBag)> currentItem.minimumRarity) itemsInBag.remove (currentItem); return (currentItem);
Mentre una versione così semplice porta con sé alcuni problemi (come la borsa che alla fine raggiunge uno stato di randomizzazione standard), rappresenta le modifiche minori che possono aiutare a stabilizzare i risultati della randomizzazione.
Mentre questo copre l'idea di base dei tassi variabili, ci sono ancora alcune cose da considerare per le tue implementazioni:
Rimuovere gli oggetti dalla borsa aiuta a creare risultati coerenti, ma alla fine ritorna ai problemi della randomizzazione standard. Come potremmo modellare le funzioni per consentire sia aumenti che diminuzioni degli articoli per evitare questo?
Cosa succede quando abbiamo a che fare con migliaia o milioni di articoli? Utilizzare una borsa piena di borse potrebbe essere una soluzione per questo. Ad esempio, la creazione di una borsa per ogni rarità (tutti gli elementi comuni in una borsa, rara in un'altra) e il posizionamento di ciascuno di questi in una grande borsa può fornire un ampio numero di nuove possibilità di manipolazione.
Molti giochi utilizzano ancora la generazione di numeri casuali standard per creare difficoltà. In questo modo, viene creato un sistema in cui metà delle esperienze giocatore cade su entrambi i lati del previsto. Se lasciato deselezionato, questo crea il potenziale per i casi limite di ripetere le cattive esperienze a una quantità non voluta.
Limitando le gamme di quanto i risultati possono allontanarsi, è assicurata un'esperienza utente più coesa, consentendo a un numero maggiore di giocatori di godersi il gioco senza problemi..
La generazione di numeri casuali è un punto fermo del buon design del gioco. Assicurati di ricontrollare le tue statistiche e di implementare il miglior tipo di generazione per ogni scenario per migliorare l'esperienza del giocatore.
Ti piace un altro metodo che non ho coperto? Hai domande sulla generazione di numeri casuali nella progettazione del tuo gioco? Lasciami un commento qui sotto e farò del mio meglio per tornare da te.