Alla ricerca di informazioni dettagliate sulla progettazione della programmazione per gli attacchi e i tipi di attacco in un gioco


14

Quindi, sto iniziando a introdurre l'attacco al nostro spazio RTS 2D (questo è in Unity, quindi è guidato dai componenti). Inizialmente era semplice come "nemico nel raggio d'azione, danno applicato". Tuttavia, ci saranno più "tipi" di armi / attacchi associati alla loro nave o struttura particolare. Oltre ad altri fattori coinvolti oltre il danno grezzo come il tipo di danno, e possibilmente l'inerzia in futuro.

Ragazzi, ogni unità e ogni tipo di struttura ha il proprio tipo di attacco. Significa che crei uno script per ogni unità / struttura che definisce il tipo di attacco, il danno, gli effetti, il raggio, le particelle, gli sprite ... ecc. E lo colleghi come componente?

Oppure crea uno script che definisce un tipo di attacco, uno script per il tipo di proiettile associato a quello ... ecc. E poi estendi quelli e modifica quelli per ogni unità, allegando ogni script all'unità / struttura.


Spero di avere un senso, ci sto riflettendo da così tanto tempo, non sono sicuro di risolvere un problema, o semplicemente di risolvere i miei problemi e scavare me stesso in un buco.

Quando si dispone di un gioco che può avere una moltitudine di tipi di attacco che possono o meno essere limitati a una specifica unità / struttura, come si progetta il framework che lo ha legato insieme alle unità / strutture specifiche in un ambiente di progettazione guidato da componenti ?

Se questo non è abbastanza chiaro fammelo sapere.

Modifica: grandi risposte, grazie.

Domanda estesa:

Le risposte sembrano variare da "ogni oggetto può avere il proprio script di attacco" a "Avere i tipi di attacco come propri script e assegnarlo a ciascun oggetto per una soluzione più riutilizzabile". Diciamo che ho un attacco "blaster", spara un proiettile rosso a una certa velocità. Il danno, la velocità di fuoco e le dimensioni del proiettile dipendono dall'unità che lo ha sparato. È meglio creare uno script di attacco per quell'unità o provare a modificare un "attacco blaster" per adattarlo allo scopo di ogni unità che vuole usarlo?


1
Per idee generali sulla programmazione di giochi, mi piace fare riferimento alle specifiche complete del gioco di ruolo FFV - gamefaqs.com/snes/588331-final-fantasy-v/faqs/30040
Code Whisperer,

Risposte:


12

Beh, onestamente non sono un esperto in questo, ma ... penso che dipenda da quanto complesso e vario pensi che diventeranno gli attacchi. Dato che è un RTS, suppongo che avrai forse 10-50 unità o strutture diverse con i loro tipi di attacco.

Opzione 1: se c'è un numero relativamente basso di unità che avranno attacchi che sono in qualche modo simili, metterei semplicemente tutto in un unico grande script e definirei i parametri usati nell'ispettore.

Opzione 2: se, d'altra parte, immagini un gran numero di tipi di attacco con un comportamento diverso, puoi rompere tutto in modo che ogni unità e edificio ottenga il proprio script di attacco unico. Sto pensando che se lo fai, potresti voler creare uno script "helper" che definisce blocchi di codice comunemente usati che molti dei singoli script possono prendere. In questo modo non dovrai riscrivere tutto e saprai dove si trova tutto.

Opzione 3: Probabilmente ciò che non dovresti fare è avere determinati raggruppamenti di unità che condividono script, questo probabilmente ti confonderà e diventerà un disastro se il codice necessario per un attacco è in 10 script diversi.

Ecco, ti ho disegnato una foto.

inserisci qui la descrizione dell'immagine


2
Grazie mille per la risposta Per qualche ragione stavo iniziando a puntare all'opzione 3 e stavo facendo fatica a trovare un modo per giustificarlo. Probabilmente seguirò la seconda via, ogni unità ottiene il proprio script di attacco personalizzato con il codice comune condiviso condividendo il codice comune come componente di ogni unità / edificio. Non sono sicuro di dove stavo andando con il treno di pensieri che mi ha portato all'opzione 3, grazie. Lascio questo aperto fino a quando mi alzo nel mattino nel caso in cui ci siano altri poster che vogliono entrare.
Douglas Gaskell,

Nessun problema, non è una risposta definitiva, ma spero che sia d'aiuto.
Mir,

1
Puoi ibridare 1 e 2 inserendo attacchi simili in un unico grande script e separando attacchi diversi
maniaco del cricchetto

4
Sono sorpreso # 3 è raccomandato contro? Non è l'intero punto delle classi modulari / generiche in modo che ogni unità non debba definire il proprio tipo? Se un gioco è un RTS e il danno da assedio (di solito "a lungo raggio") è un tipo di danno, dovresti definirlo una volta e fare in modo che più unità in stile artiglieria si riferiscano ad esso quando eseguono i calcoli del danno, in modo che se il danno da assedio mai avuto bisogno di essere nerfed (ribilanciato), avresti dovuto aggiornare solo una classe?
HC_

1
"Here, I drew you a picture."mi ha ricordato questo
FreeAsInBeer il

4

Non so molto di Unity e non ho fatto lo sviluppo di giochi da un po ', quindi lascia che ti dia una risposta di programmazione generale a questa domanda. Ho basato la mia risposta sulla conoscenza che ho dei sistemi entità-componente in generale, in cui un'entità è un numero associato a N molti componenti, un componente contiene solo dati e un sistema opera su insiemi di componenti associati la stessa entità.

Il tuo spazio problematico è questo:

  • Esistono diversi modi per attaccare un nemico nel gioco nel suo insieme.
  • Ogni nave, struttura, ecc. Può avere diversi modi di attaccare (ciascuno determinato in qualche modo)
  • Ogni attacco può avere i suoi effetti particellari.
  • L'attacco deve tener conto di alcuni fattori (come l'inerzia o l'armatura, ad esempio), presenti sul bersaglio e sull'utente.

Strutturerei la soluzione come segue:

  • Un attacco ha un identificatore - questa potrebbe essere una stringa.
  • Un'entità "sa" che può usare un attacco (basato sull'identificatore dell'attacco).
  • Quando l'attacco viene utilizzato dall'entità, il componente di visualizzazione corrispondente viene aggiunto alla scena.
  • Hai qualche logica che conosce il bersaglio dell'attacco, dell'attaccante e dell'attacco in uso - questa logica dovrebbe decidere quanti danni fai (e avere accesso all'inerzia o qualunque altra entità).

È importante che il punto di contatto tra gli attacchi e le entità sia il più sottile possibile: ciò manterrà il codice riutilizzabile e ti impedirà di inventare un codice duplicato per ogni diverso tipo di entità che utilizza lo stesso tipo di attacco . In altre parole, ecco alcuni pseudo-codice JavaScript per darti un'idea.

// components
var bulletStrength = { strength: 50 };
var inertia = { inertia: 100 };
var target = { entityId: 0 };
var bullets = {};
var entity = entityManager.create([bulletStrength, inertia, target, bullets]);

var bulletSystem = function() {
  this.update = function(deltaTime, entityId) {
    var bulletStrength = this.getComponentForEntity('bulletStrength', entityId);
    var targetComponent = this.getComponentForEntity('target', entityId);
    // you may instead elect to have the target object contain properties for the target, rather than expose the entity id
    var target = this.getComponentForEntity('inertia', targetComponent.entityId);

    // do some calculations based on the target and the bullet strength to determine what damage to deal
    target.health -= ....;
  }
};

register(bulletSystem).for(entities.with(['bullets']));

Mi dispiace che questa risposta sia un po '"acquosa". Ho solo mezz'ora di pausa pranzo ed è difficile trovare qualcosa senza sapere completamente di Unity :(


3

Quando un'unità / struttura / arma attacca, probabilmente creo un Attacco (sottoclasse con tutti i tuoi dettagli divertenti) che prende l'attaccante e il difensore (o i difensori). L'Attacco può quindi interagire con il bersaglio / difensore (lento, veleno, danno, cambiare stato), disegnare se stesso (raggio, raggio, proiettile) e sbarazzarsi di se stesso al termine. Posso prevedere alcuni problemi come attacchi multipli di veleno, quindi forse i tuoi obiettivi implementerebbero un'interfaccia Damageable con cui l'attacco interagisce, ma penso che sia un approccio praticabile che è modulare e flessibile da cambiare.

Risposta estesa
Ecco come approccerei l'attacco blaster con questo approccio . Lascerò che gli altri rispondano da soli.

Vorrei che le mie unità implementassero un'interfaccia o una classe IAttacker con statistiche / metodi di attacco di base. Quando un IAttacker attacca un IDamageable, crea il suo Attacco specifico passando se stesso e il suo bersaglio (IAttacker e IDamageable, o forse una raccolta di IDamageables). L'Attacco prende le statistiche di cui ha bisogno da IAttacker (per evitare cambiamenti durante gli aggiornamenti o qualcosa del genere - non vogliamo che l'Attacco cambi le sue statistiche dopo che è già stato lanciato) e se ha bisogno di statistiche specializzate, lancia IAttacker a il tipo necessario (es. IBlasterAttacker) e ottiene le statistiche specializzate in quel modo.

Seguendo questo approccio, un BlasterAttacker deve solo creare un BlasterAttack e BlasterAttack si occupa di tutto il resto. Puoi sottoclassare BlasterAttack o creare FastBlasterAttacker separati, MegaBlasterAttacker, SniperBlasterAttacker, ecc. E il codice di attacco per ciascuno è lo stesso (e possibilmente ereditato da BlasterAttack): crea BlasterAttack e passa me stesso e il / i mio / i bersaglio / i. BlasterAttack gestisce i dettagli .


Essenzialmente, l'unità eredita da un'interfaccia IAttacker (ce l'ho già) e esiste un'interfaccia IDamageable per il "nemico" (anche questo). Quando l'attaccante attacca, viene chiamato un BlasterAttack (o classe derivata). Questo "attacco" recupererà i dati di cui ha bisogno da IAttacker e li applicherà su IDamageable quando il proiettile colpisce? Il proiettile stesso contiene la classe BlasterAttack, in modo che una volta sparato non sia più influenzato dalle modifiche a IAttacker e possa applicare i suoi danni / effetti su IDamageable solo se il proiettile effettivamente colpisce.
Douglas Gaskell,

Quando dici "si chiama un BlasterAttack (o classe derivata)" direi che viene creato un BlasterAttack. Questa istanza appena creata di BlasterAttack rappresenta il raggio (o proiettile o raggio o qualsiasi altra cosa), quindi è il proiettile. BlasterAttack copia tutte le statistiche necessarie dagli oggetti IAttacker e IDamageable: le posizioni, le statistiche dell'attaccante, ecc. Il BlasterAttack quindi tiene traccia della propria posizione e, se applicabile, applica danni al "contatto". Dovrai capire cosa fare se manca o raggiunge la sua destinazione (la vecchia posizione del bersaglio). Bruciare il terreno? Scomparire? La tua chiamata.
ricksmt

Per un Attacco ad area d'effetto, potresti voler accedere a una raccolta globale di unità (nemiche) poiché chi è a portata e chi è fuori portata può cambiare tra fuoco e impatto. Certo, una discussione simile potrebbe essere fatta per il BlasterAttack: manchi il tuo obiettivo iniziale, ma colpisci il ragazzo dietro di lui. La mia unica preoccupazione è che potresti avere molti Attacchi che ripetono molti nemici cercando di capire se e cosa colpiscono. Questa è una preoccupazione per le prestazioni.
ricksmt

Ah, ha senso. Per un attacco mancato il proiettile avrà il suo intervallo / durata preimpostati. Se colpisce qualcos'altro prima della fine di quella vita riceverà un riferimento a qualunque oggetto possieda il corpo rigido con cui si scontra, e il danno sarà applicato in quel modo. In realtà è così che funzioneranno tutti i proiettili, non sanno "verso cosa" stanno viaggiando, solo che stanno viaggiando (escludendo proiettili simili a quelli come i missili). Gli effetti AEO possono semplicemente abilitare un collisore di sfere sulla destinazione e ottenere tutti gli oggetti che si trovano al suo interno. Grazie per l'aiuto.
Douglas Gaskell,

Nessun problema. Sono contento di averlo potuto. Dimenticato che Unity semplifica tutte queste cose di collisione.
ricksmt
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.