Casting di incantesimi - Come ottimizzare i danni al secondo


23

Immagina di avere un mago che conosce alcuni incantesimi. Ogni incantesimo ha 3 attributi: danno, tempo di raffreddamento e tempo di lancio. Roba da gioco di ruolo piuttosto standard.

Tempo di ricarica: la quantità di tempo (t) impiegata prima di poter lanciare nuovamente quell'incantesimo. Un incantesimo si "ricarica" ​​nel momento in cui inizia a lanciare.

Tempo di lancio: la quantità di tempo (t) necessaria per usare un incantesimo. Mentre il mago lancia qualcosa, un altro incantesimo non può essere lanciato e non può essere annullato.

La domanda è: come massimizzeresti il ​​danno dato diversi set di incantesimi?

È facile calcolare il danno più alto per tempo di lancio. Ma cosa succede nelle situazioni in cui è meglio aspettare quindi rimanere "bloccati" lanciando un incantesimo a basso danno quando è disponibile uno molto più alto?

Per esempio,

  1. Palla di fuoco: 3000 danni, tempo di lancio di 3 secondi, raffreddamento di 6 secondi.

  2. Frostbolt: 20 danni, 4 secondi di tempo di lancio, 4 secondi di raffreddamento.

  3. Fireblast: 3 danni, 3 secondi di lancio, 3 secondi di raffreddamento.

In questo caso il tuo danno al secondo è maggiore se scegli di usare l'incantesimo DPCT inferiore (esplosione) invece che il gelo. Quindi dobbiamo considerare le conseguenze della scelta di un incantesimo. testo alternativo

Nel seguente esempio sono i casi di "over casting" e "wait". testo alternativo


Perché dovrei fare 1-3-1 in questa situazione? Perché non 1-2-1? Perché non 1-2-3-1, che è più efficiente di 1-3-1-X se 1-3-1 da solo non ucciderà il bersaglio?

@Joe Wreschnig: Grazie per averlo sottolineato. È stato un errore nel mio esempio. Ora è stato semplificato in soli 2 casi.
aaronfarr,

1
Avido, come in scegliere l'incantesimo dps più alto disponibile quando possibile. Ignorando altre logiche, ad es. in attesa.
aaronfarr,

1
Solo per confondere l'acqua. Considera un incantesimo che infligge ∞ danni, ma impiega 50 secondi per essere lanciato. È dps / dpct è ∞, ma non dovrebbe mai essere scelto se il bersaglio può essere ucciso con altri mezzi in meno di 50 secondi.
deft_code

1
Dovresti collegarti al duplicato
Sparr

Risposte:


23

Tutta l'IA è ricerca!

Quando entri nelle viscere dell'intelligenza artificiale è incredibile quanto sia davvero la ricerca .

  • stato : il tempo di recupero rimanente di tutti gli incantesimi disponibili.
  • fitness : danno totale fatto
  • costo : tempo totale impiegato
  • rami : qualsiasi incantesimo conosciuto. Se l'incantesimo è ancora in ricarica, aggiungi quel valore al suo tempo di lancio.
  • obiettivo : salute totale del bersaglio. L'obiettivo deve essere una quantità limitata di danni, quindi nel caso di un bersaglio sconosciuto, scegli la salute più grande possibile.
    In alternativa, l'obiettivo potrebbe essere speso meno di 50 secondi e la ricerca troverebbe il danno massimo che potrebbe essere fatto in 50 secondi.

Collega questi parametri a Uniform Cost Search (UCS) e presto, piano di battaglia ottimale garantito. Ancora meglio se riesci a trovare un'euristica, cerca con A * o IDA * e otterrai la stessa risposta molto più velocemente.

Alcuni più vantaggi dell'utilizzo di UCS è che può trovare l'ordine di lancio ottimale per situazioni molto più complicate di quella fornita con solo 3 variabili. Alcuni altri aspetti che potrebbero essere facilmente aggiunti:

  • danni nel tempo
  • aggiorna l'incantesimo per ridurre il tempo di recupero di altri incantesimi
  • incantesimo di fretta che fa lanciare più velocemente altri incantesimi.
  • il potenziamento del danno che fa sì che altri incantesimi facciano più danni.

UCS non è onnipotente. Non può modellare i benefici degli incantesimi di protezione. Per questo dovrai passare alla ricerca alpha-beta o minimax.
Inoltre non gestisce molto bene l'area di influenza e le lotte di gruppo. UCS può essere ottimizzato per fornire soluzioni ragionevoli in queste situazioni, non è garantito trovare la soluzione ottimale.


2

Questo è un problema di ottimizzazione combinatoria specializzato. All'aumentare del numero di incantesimi, la difficoltà nel trovare la combinazione / modello ottimale di incantesimi aumenta in modo significativo. Euristiche simili a quelle utilizzate per il problema degli zaini sarebbero utili per risolvere questo problema.


1

Devi pensare in termini di "danno per unità di tempo di lancio" (DPCT) - per esempio, una palla di fuoco con un lancio di 3 secondi e un danno di 3000 farebbe 1000 DPCT.

Se dovessi attendere 3 secondi per il tempo di recupero prima di lanciarlo, questo lo ridurrebbe a 500 DPCT (3000 danni, divisi per 6 secondi in totale, inclusa l'attesa)

Quindi devi solo determinare il danno per tempo di lancio di ogni incantesimo, inclusa l'eventuale attesa rimanente per il tempo di recupero. Scegli quello con il DPCT più alto, aspetta se necessario, quindi lancialo. Ripeti fino a quando il boss è morto :)


il problema è che DPCT può essere molto fuorviante. Supponiamo ad esempio di aggiungere altri 2 incantesimi al mix Palla di fuoco: 3000 danni, 3 secondi di lancio, 6 secondi di recupero, DPCT: 1000 Incantesimi # 2: 20 danni, 4 secondi di lancio, 4 secondi di recupero, DPCT: 5 Incantesimi # 3: 3 danno, 3 secondi di lancio, 3 secondi di tempo di recupero, DPCT: 1 (ricorda, il tempo di recupero inizia nel momento in cui l'incantesimo viene lanciato) Anche se l'incantesimo n. 3 ha un DPCT inferiore, si otterrà un DPS più alto (1-3-1-3 .. .) dell'incantesimo n. 2 (1-2-1-2 ...).
aaronfarr,

1

Usando il tuo esempio, probabilmente vorresti che i due incantesimi fossero più vicini in termini di efficacia, ma forse ti daranno un vantaggio diverso. Avere un breve tempo di lancio (o nessun tempo di lancio per quella materia) sarebbe molto utile, quindi potrebbe valere la pena usarlo anche se fa meno danni e impiega più tempo per riutilizzarlo.

Potresti sempre imporre un altro elemento nell'equazione. I punti Mana / Magic possono servire a questo scopo, consentendo al giocatore di determinare se l'uso di questi punti vale il vantaggio.

Nel complesso, tuttavia, come ha detto bluescrn, il DPCT (o DPS come viene chiamato in molti giochi che sono altamente sintonizzati e discussi dai giocatori che cercano il miglior mix) è davvero l'elemento principale che vorresti avere bilanciato, specialmente se hai qualche tipo di alberi tecnologici / di abilità che consentono a diversi giocatori di progredire con abilità diverse, ma con l'abilità di fare simili danni in una data posizione nel gioco.


0

Ho capito questo algoritmo che funziona bene per i miei scopi.

Le persone hanno sollevato alcuni punti importanti. Dandogli i parametri finali dell'obiettivo consentirebbe ai normali algoritmi di ricerca di fare la propria parte. vale a dire. fai un danno ottimale in t secondi, fai un danno x in un tempo ottimale.

Il mio algoritmo restituisce semplicemente la sequenza di incantesimi con il DPS più alto. È un algoritmo veloce poiché riduce le dimensioni dell'insieme che stai attraversando, non richiede la conoscenza di altre tecniche dell'albero di ricerca.

Il primo passo è identificare l'incantesimo con il danno più alto per tempo di lancio. Questo incantesimo diventa l'incantesimo "base" poiché garantirà il danno più alto al secondo. Significato, dovresti sempre lanciare questo incantesimo se sono soddisfatte le seguenti 2 condizioni: 1) L'incantesimo di base è disponibile (non in ricarica). 2) Al momento non stai lanciando un incantesimo.

Quindi diventa una questione di riempimento di altri incantesimi mentre l'incantesimo di base è in ricarica. Tra (tempo di lancio) e (tempo di recupero - tempo di lancio). Tuttavia, possono verificarsi alcune sovrapposizioni (la regola 2 sopra è falsa).

Diventa quindi una questione di ricorrere a tutti gli incantesimi non di base per trovare tutte le sequenze di incantesimi che non violano le 2 regole.

Per gli incantesimi che si sovrappongono, devi penalizzarli per il potenziale danno che l'incantesimo di base avrebbe potuto fare (fino al suo massimo danno).

Prendi ad esempio 2 incantesimi

Danno 1: 300, tempo di lancio 3s, tempo di recupero 10s

2: 290 danni, 3s tempo di lancio, 3s tempo di recupero

Il maggior danno deriva dalla sequenza 1 - 2 - 2 - 2. Il che provoca una sovrapposizione di 2 secondi in un potenziale lancio n. 1. Tuttavia, questo è ancora utile poiché se non lanci il terzo incantesimo (es. 1 - 2 - 2) infliggerai 880 danni con 1 secondo di riserva. Se lanci l'incantesimo n. 2 aggiuntivo, infliggerai 1170 - 2 secondi del n. 1 che è 200. Quindi il danno relativo è 970.


-2

Si potrebbe fare un semplice caso switch stile "livello di sicurezza".

Questo è appena fuori dalla mia testa, quindi fai attenzione agli errori logici oltre il livello di pensiero del mio stato stanco, ma spero che questo possa iniziare.

Supponendo che il tempo sia fatto in numeri interi a blocchi -

// after casting spell
int remainingTime = (coolDown - castTime);
switch(spellJustCast)
{
  // assuming the cast method will have some input validation for whether the spell
  // is off cooldown or not, pass the time as a parameter
  case 3 : castSpell1(remainingTime);
           castSpell2(remainingTime);
           break;
  case 1 : castSpell2(remainingTime);
           castSpell3(remainingTime);
           break;
  case 2 : castSpell1(remainingTime);
           castSpell3(remainingTime);
           break;
  default: System.out.println("Debug!");
           break;
}

Alcune delle chiamate al metodo non sono necessarie a causa dei tempi degli incantesimi, ma c'è sempre spazio per gli aggiornamenti in questo modo.

Modifica: mi sono appena reso conto che sarebbe necessario reimpostare il tempo rimanente dopo il lancio del nuovo incantesimo, probabilmente è meglio renderlo un attributo / campo di classe e impostarlo da una chiamata all'interno dei metodi castSpell.


Non ho davvero idea di cosa stai cercando di ottenere qui, ma nessun motore di gioco moderno ha funzioni come castSpell1 e castSpell2.

1
@Joe Wreschnig li intendevo come i suoi metodi nelle sue classi di gioco personalizzate, questo è solo un esempio astratto, non dettagliato.
kymully,

1
Bene, non è così che funzionano gli incantesimi nei motori moderni. C'è una funzione castSpell che accetta un oggetto i cui campi vengono letti da un file. Una simile dichiarazione switch sarebbe impossibile da mantenere in qualsiasi motore reale ed è richiesto un qualche tipo di algoritmo di pianificazione.

@Joe Wreschnig ho capito. Stavo semplicemente dando un modo per risolvere il problema. Questo esempio è scritto in Java, non inteso per un motore o un framework specifico. Ma se non può essere implementato come dici tu, la mia risposta è nulla.
kymully,
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.