Non sono sicuro che stai leggendo questo, ma ho lottato con questo tipo di problema per molto tempo.
Ho progettato numerosi tipi diversi di sistemi affettivi. Li esaminerò brevemente ora. Tutto si basa sulla mia esperienza. Non pretendo di conoscere tutte le risposte.
Modificatori statici
Questo tipo di sistema si basa principalmente su interi semplici per determinare eventuali modifiche. Ad esempio, da +100 a Max HP, +10 per attaccare e così via. Questo sistema potrebbe anche gestire anche le percentuali. Devi solo assicurarti che l'impilamento non esca dal controllo.
Non ho mai memorizzato nella cache i valori generati per questo tipo di sistema. Ad esempio, se volessi visualizzare la massima salute di qualcosa, genererei il valore sul posto. Ciò ha impedito che le cose fossero soggette a errori e che fossero più facili da capire per tutti i soggetti coinvolti.
(Lavoro in Java, quindi quello che segue è basato su Java ma dovrebbe funzionare con alcune modifiche per altri linguaggi) Questo sistema può essere fatto facilmente usando enum per i tipi di modifica, e quindi numeri interi. Il risultato finale può essere inserito in una sorta di raccolta che ha coppie chiave, valore ordinate. Questa sarà una ricerca rapida e calcoli, quindi le prestazioni sono molto buone.
Nel complesso, funziona molto bene con modificatori statici completamente piatti. Tuttavia, il codice deve esistere nei posti corretti per i modificatori da utilizzare: getAttack, getMaxHP, getMeleeDamage e così via e così via.
Dove questo metodo fallisce (per me) è un'interazione molto complessa tra i buff. Non esiste un modo molto semplice per interagire se non ghettandolo un po '. Ha alcune semplici possibilità di interazione. Per fare ciò, è necessario apportare una modifica al modo in cui si memorizzano i modificatori statici. Invece di usare un enum come chiave, usi una stringa. Questa stringa sarebbe il nome Enum + variabile extra. 9 volte su 10, la variabile extra non viene utilizzata, quindi manterrai comunque il nome enum come chiave.
Facciamo un rapido esempio: se vuoi essere in grado di modificare il danno contro creature non morte, potresti avere una coppia ordinata come questa: (DAMAGE_Undead, 10) Il DAMAGE è l'Enum e il Undead è la variabile extra. Quindi durante il tuo combattimento, puoi fare qualcosa del tipo:
dam += attacker.getMod(Mod.DAMAGE + npc.getRaceFamily()); //in this case the race family would be undead
Ad ogni modo, funziona abbastanza bene ed è veloce. Ma fallisce in interazioni complesse e ha un codice "speciale" ovunque. Ad esempio, si consideri la situazione del "25% di probabilità di teletrasportarsi sulla morte". Questo è "abbastanza" complesso. Il sistema sopra può gestirlo, ma non facilmente, poiché è necessario quanto segue:
- Determina se il giocatore ha questa mod.
- Da qualche parte, disporre di un codice per eseguire il teletrasporto, in caso di successo. La posizione di questo codice è una discussione in sé!
- Ottieni i dati giusti dalla mappa Mod. Cosa significa il valore? È la stanza in cui si teletrasportano anche? Cosa succede se un giocatore ha due mod di teletrasporto su di loro ?? Gli importi non verranno sommati insieme ?????? FALLIMENTO!
Quindi questo mi porta al prossimo:
Il massimo sistema di buff complesso
Una volta ho provato a scrivere un MMORPG 2D da solo. Questo è stato un terribile errore ma ho imparato molto!
Ho riscritto il sistema di affetto 3 volte. Il primo utilizzava una variante meno potente di quanto sopra. Il secondo era quello di cui parlerò.
Questo sistema aveva una serie di classi per ogni modifica, quindi cose come: ChangeHP, ChangeMaxHP, ChangeHPByPercent, ChangeMaxByPercent. Ho avuto un milione di questi ragazzi, anche cose come TeleportOnDeath.
Le mie lezioni avevano cose che avrebbero fatto quanto segue:
- applyAffect
- removeAffect
- checkForInteraction <--- importante
Applicare e rimuovere si spiegano da soli (anche se per cose come le percentuali, l'affetto avrebbe tenuto traccia di quanto aumentava l'HP per assicurarsi che quando l'effetto si fosse esaurito, avrebbe rimosso solo la quantità aggiunta. Era buggy, lol e mi ci è voluto molto tempo per assicurarmi che fosse giusto. Non mi sentivo ancora bene.).
Il metodo checkForInteraction era un pezzo di codice orribilmente complesso. In ciascuna delle classi degli affetti (es.: ChangeHP), avrebbe il codice per determinare se questo dovrebbe essere modificato dall'affetto dell'input. Quindi, ad esempio, se avessi qualcosa come ...
- Buff 1: Infligge 10 danni da fuoco in attacco
- Buff 2: Aumenta tutti i danni da fuoco del 25%.
- Buff 3: Aumenta tutti i danni da fuoco di 15.
Il metodo checkForInteraction gestirà tutti questi effetti. Per fare ciò, è stato necessario controllare ogni effetto su TUTTI i giocatori vicini !! Questo perché il tipo di affetti che avevo affrontato con più giocatori nell'arco di un'area. Ciò significa che il codice non ha MAI AVUTO alcuna dichiarazione speciale come sopra - "se siamo appena morti, dovremmo verificare il teletrasporto sulla morte". Questo sistema lo gestirà automaticamente correttamente al momento giusto.
Cercare di scrivere questo sistema mi ha richiesto circa 2 mesi e fatto esplodere a testa in diverse volte. TUTTAVIA, era DAVVERO potente e poteva fare una quantità folle di roba - specialmente quando prendi in considerazione i seguenti due fatti per le abilità nel mio gioco: 1. Avevano range di destinazione (cioè: singolo, sé, solo gruppo, PB AE stesso , Target PB AE, AE targetizzato e così via). 2. Le abilità possono avere più di 1 effetto su di esse.
Come accennato in precedenza, questo è stato il 2 ° del 3 ° sistema di affetto per questo gioco. Perché mi sono allontanato da questo?
Questo sistema ha avuto le peggiori prestazioni che abbia mai visto! Era terribilmente lento perché doveva fare così tanto controllo per ogni cosa che succedeva. Ho provato a migliorarlo, ma lo ho ritenuto un fallimento.
Quindi arriviamo alla mia terza versione (e un altro tipo di sistema buff):
Classe di affetto complessa con gestori
Quindi questa è praticamente una combinazione delle prime due: possiamo avere variabili statiche in una classe Affect che contiene molte funzionalità e dati extra. Quindi chiama solo i gestori (per me, praticamente alcuni metodi di utilità statici invece di sottoclassi per azioni specifiche. Ma sono sicuro che potresti voler utilizzare sottoclassi per azioni se lo desideri anche tu) quando vogliamo fare qualcosa.
La classe Affect avrebbe tutte le cose succose, come tipi di target, durata, numero di usi, possibilità di esecuzione e così via.
Dovremmo ancora aggiungere codici speciali per gestire le situazioni, ad esempio il teletrasporto sulla morte. Dovremmo ancora verificare manualmente questo nel codice di combattimento, e quindi se esistesse, otterremmo un elenco di affetti. Questo elenco di affetti contiene tutti gli affetti attualmente applicati sul giocatore che ha avuto a che fare con il teletrasporto alla morte. Quindi guarderemmo ciascuno e verificheremmo se fosse eseguito e se avesse avuto successo (ci saremmo fermati al primo con successo). Se avesse avuto successo, avremmo semplicemente chiamato l'handler per occuparci di questo.
L'interazione può essere fatta, se vuoi anche tu. Dovrebbe solo scrivere il codice per cercare buff specifici sui giocatori / ecc. Poiché ha buone prestazioni (vedi sotto), dovrebbe essere abbastanza efficiente farlo. Avrebbe solo bisogno di gestori più complessi e così via.
Quindi ha molte prestazioni del primo sistema e ancora molta complessità come il secondo (ma non tanto). Almeno in Java, puoi fare alcune cose difficili per ottenere le prestazioni di quasi il primo nella maggior parte dei casi (ad esempio: avere una mappa enum ( http://docs.oracle.com/javase/6/docs/api/java /util/EnumMap.html ) con Enums come chiavi e ArrayList di affetti come valori. Ciò ti consente di vedere se hai rapidamente degli affetti [poiché l'elenco sarebbe 0 o la mappa non avrebbe l'enum] e non avere per iterare continuamente sugli elenchi degli affetti del giocatore senza motivo. Non mi dispiace iterare gli affetti se ne abbiamo bisogno in questo momento. Ottimizzerò più tardi se diventa un problema).
Attualmente sto riaprendo (riscrivendo il gioco in Java anziché nella base di codici FastROM in cui era originariamente) il mio MUD che si è concluso nel 2005 e recentemente mi sono imbattuto in come voglio implementare il mio sistema buff? Userò questo sistema perché ha funzionato bene nel mio precedente gioco fallito.
Bene, si spera che qualcuno, da qualche parte, troverà utili alcune di queste intuizioni.