Come legare un rilascio di proiettile con un'animazione di fuoco


15

Diciamo che hai un'animazione che vuoi che accada quando spari un proiettile. Come faresti apparire il proiettile alla fine dell'animazione. L'unica cosa che riesco a capire è conoscere la durata del tempo dell'animazione e ritardare l'impostazione della posizione dei proiettili e l'attivazione finché non è trascorso tale intervallo di tempo. Mi chiedevo solo se questo è l'approccio migliore, come lo gestiscono tutti gli altri?

EDIT: penso di avere problemi a formulare correttamente la domanda.

La mia domanda


Grazie! Molte buone idee da parte di tutti voi, mi piace l'idea di utilizzare un callback. Penso che proverò ad implementarlo, non volevo davvero fare affidamento sul monitoraggio del tempo.
tp0w3rn,

Risposte:


8

Fondamentalmente sei sulla buona strada: devi sapere quanto dura un'animazione per fare questo genere di cose. Le animazioni sono più di una semplice raccolta di cornici, ci sono ogni sorta di altre informazioni che ti servono. Ad esempio, quanti fotogrammi ci sono, il loop di animazione, quanto velocemente viene riprodotto (ad es. 10 fotogrammi di animazione al secondo o 25 o 60?). Ogni animazione può essere definita in termini di alcuni dati, che alcuni codici di animazione generalizzati possono visualizzare e riprodurre. Dovresti incapsulare la parte di animazione nel suo bit di codice, che non è a conoscenza di nulla tranne queste definizioni di animazione e di come visualizzare i singoli fotogrammi dell'immagine. Cioè, disporre di un oggetto animazione che è possibile caricare, avviare la riproduzione, interrompere la riproduzione e dire di eseguire il rendering in una determinata posizione sullo schermo.

Un approccio flessibile consiste nell'utilizzare una sorta di definizione di animazione per incapsulare questo tipo di informazioni. Quindi, piuttosto che dire semplicemente "l'animazione X è tutti questi fotogrammi, basta riprodurli", ottieni qualcosa di un po 'più complesso.

Ad esempio con una sorta di formato dati deriso

animazioni =
{
  {name = "walk", files = "walk * .png", frameCount = "12", loop = "true"},
  {name = "fire" files = "fire * .png" frameCount = "6",
       eventi = {
           {name = "bulletLeavesGun", frame = "4", param1 = "43", param2 = "30"}
       }
  }
}

Quindi il tuo codice dice qualcosa del tipo:

currentAnimation = animations.Get("fire");
currentAnimation.Play();

Il modo in cui rilevi gli eventi può essere sia con il codice di animazione che ti richiama (ovvero quando rileva un nuovo evento perché l'animazione ha riprodotto un determinato frame, chiama il tuo codice di gioco per dirlo del nuovo evento), oppure eseguendo il polling del animazione così:

List<Event> events = currentAnimation.EventsSinceLastCheck();
foreach (AnimationEvent event in events)
{
    if (event.name == "bulletLeavesGun")
    {
        Vector2 bulletPosition = new Vector2(event.param1, event.param2);
        Vector2 actualBulletPosition = new Vector2(
                 character.x + bulletPosition.x, 
                 character.y + bulletPosition.y);
        CreateBulletAt(actualBulletPosition);
    }
}

Punti da notare:

  • Il codice di animazione dovrebbe esistere separatamente dal codice di gioco. Non vuoi davvero che il tuo codice di gioco sia strettamente legato ai dettagli della riproduzione dell'animazione.
  • Il codice di animazione sa se eseguire il loop in base alla definizione dell'animazione
  • Il codice di animazione sa quando l'animazione è terminata e può richiamare un altro codice per dire 'ehi, l'animazione chiamata "fuoco" è appena finita, cosa vuoi fare adesso? "
  • Il codice di animazione non è a conoscenza di eventi diversi da quello a cui sono associati un nome e alcuni dati arbitrari (param1 e param2)
  • Il codice di animazione sa quale frame è attualmente attivo e quando passa a un nuovo frame, può controllare e dire 'oh, sono sul frame 4 ora, ciò significa che questo evento chiamato "fuoco" è appena accaduto, aggiungilo a la mia lista di eventi recenti in modo da poterlo dire a chiunque ne faccia richiesta '.

Se non è necessario che il proiettile si attivi all'interno dell'animazione, ma solo una volta terminato, è possibile cavarsela con un sistema molto meno complesso senza la nozione di eventi. Ma vorrai comunque un sistema in cui le animazioni vengano riprodotte da sole, sappiano quanto durano e possono richiamare il codice di gioco una volta completata l'animazione.


Non sono d'accordo con il mantenimento di animazioni consapevoli della logica (nel frame 4 ora, ciò significa che questo evento chiamato "fuoco" è appena accaduto). Le animazioni dovrebbero essere cieche e stupide. Ho dovuto fare alcune logiche lato server e strappare animazioni e l'interfaccia utente da un gioco è qualcosa che non voglio fare di nuovo. Consiglio vivamente di utilizzare animazioni molto brevi e segmentate, riprodurle in parallelo alle logiche per consentire alle logiche di attivare sequenze di animazioni alla velocità definita dalle logiche. Non fare mai test di logica per lo stato di un'animazione.
Coyote,

Dividere l'animazione in pezzi sembra abbastanza inutile. Concordo con il non sondaggio per lo stato dell'animazione, ma ciò lascia comunque la sua prima raccomandazione. Non so se intendesse un sistema di eventi separato per disaccoppiare il codice di animazione dal resto del gioco (modello di osservatore?) Ma è così che lo farei. Né le "logiche", come dici tu, dovrebbero sapere del codice di animazione, o viceversa.
jhocking

@Coyote Direi che stai mescolando due cose separate. Sì, la logica lato server dovrebbe essere sempre indipendente dagli elementi visivi (perché non si desidera eseguire il sistema di animazione solo per capire quando viene sparato un proiettile), ma questo non ti aiuterà a costruire un sistema di animazione sul client . Sul client, non vuoi assolutamente che gli oggetti visivi vengano schiavizzati insensatamente sul server, perché sembrerebbe terribile - i proiettili appaiono in tempi strani e non sincronizzati con il personaggio perché c'è stato un picco tra il gioco e il server . Non c'è motivo per cui non si possano avere entrambi (cont ...)
MrCranky,

@Coyote (cont ...), il gameplay può essere guidato dal server disaccoppiato dalla grafica. Quindi il proiettile viene lanciato al momento X sul server e il client rispecchia quell'azione iniziando a riprodurre immediatamente l'animazione del fuoco, con il proiettile che spara visivamente in ritardo di alcuni fotogrammi dietro la simulazione del gameplay del proiettile. Bisogna fare ogni sorta di compromesso tra fedeltà visiva e simulazione del gameplay, quindi dire che "le animazioni dovrebbero essere cieche e stupide" è semplicemente ingenuo. A volte gli eventi devono assolutamente essere collegati ai frame di animazione, perché nessun altro metodo li farà apparire o suonare bene.
MrCranky,

@Coyote In realtà ora ci penso, il fuoco dei proiettili è un terribile esempio per questo, principalmente a causa della risposta del thedaian di seguito. Il licenziamento dovrebbe avvenire immediatamente. Un esempio migliore sarebbe un polverizzazione di VFX quando un personaggio atterra: il server e il client si sincronizzerebbero quando il personaggio inizia a saltare, ma la visualizzazione visiva viene lasciata al client. E quando l'animazione colpisce il telaio giusto in cui il piede colpisce il suolo, l'evento VFX dovrebbe attivarsi. Allo stesso modo, sono necessari eventi se è necessario prendere una decisione su un determinato frame di animazione se passare a un'altra animazione.
MrCranky,

3

In qualche modo, dovrai aspettare fino al termine dell'animazione e creare il punto elenco in quel punto.

L'impostazione di un timer funzionerà, se sei sicuro che la frequenza di animazione sia fissa. Come variante minore, potresti avere un codice interno al proiettile che lo fa attendere invisibilmente per un momento prima di apparire e spostarsi.

A seconda della piattaforma di sviluppo, potresti avere una sorta di funzione di aggiornamento dell'animazione o callback che ti consentirà di rispondere nel momento esatto in cui l'animazione raggiunge il punto desiderato. Questo è come lo farei con Flixel, per esempio.


1
Il addAnimationCallbackmetodo di Flixel può essere usato sull'entità che spara. Nella funzione di richiamata, puoi vedere se il frame corrente dell'animazione di attivazione è il frame che dovrebbe creare un'entità bullet. In tal caso, puoi aggiungere un punto elenco sullo schermo.
Snow Blind,

2

Risposta diretta: supponendo di avere un'animazione che si desidera riprodurre quando il giocatore preme il pulsante 'fuoco', e quindi far uscire un proiettile dopo aver finito di giocare. Idealmente, dovresti evitare di codificare il tempo di animazione e lanciare il proiettile al termine dell'animazione (utilizzando una funzione di callback o qualcosa del genere, a seconda della piattaforma). Non riesco a pensare a nessun altro metodo per farlo che non sia eccessivamente complesso.

Risposta alternativa al design del gioco: a meno che non ci sia una ragione davvero, davvero buona per farlo, eviterei di avere un ritardo dalla pressione del pulsante 'fuoco' e la comparsa del proiettile. A meno che l'animazione non sia davvero molto breve (uno o due fotogrammi, massimo, in pratica un flash di museruola), la risposta del pulsante di fuoco sembrerà lenta e diventerà fastidiosa per un tipico giocatore. Anche se decidi di utilizzare un'animazione prima che vengano proiettati i proiettili (i giochi di ruolo a turni e i giochi tattici sarebbero motivi accettabili per farlo), penserei di includere da qualche parte l'opzione "Disattiva animazioni", per consentire gioco per muoversi più velocemente se il giocatore vuole.


Sì, non far reagire il fuoco lentamente. Questo è proprio come il problema comune con il salto; gli animatori effettuano un grande windup, ma i giocatori si aspettano di essere in volo non appena toccano il pulsante.
jhocking

2

Come dice MrCranky; mantenere separati animazione e logica.

Ma soprattutto, la logica deve rimanere la parte principale .

  • Quando si preme il pulsante di fuoco, è necessario attivare "l' azione " di sorteggio nello stato del personaggio (logiche).
  • Questa azione dovrebbe attivare l' animazione del disegno con tutti i parametri (tempo di vivere ecc.).
  • Una volta terminata l' azione di pesca , puoi attivare l' azione di fuoco (potrebbe sparare una o più volte a seconda dell'arma)
  • Questa azione può generare proiettili e attivare l' animazione del fuoco .

Tieni presente che il controllo dell'interfaccia utente dalle logiche è l'unico modo per assicurarti di poter conservare, riutilizzare e condividere le tue logiche in un secondo momento (nuovo renderer, nuovo gioco, versione del server senza renderer ...)


1

Prima di tutto, userei un sistema di eventi (modello di osservatore?) Per disaccoppiare parti del codice. Questo non è solo per l'animazione, ma sicuramente si applica lì. Quindi il codice di animazione può semplicemente dire dispatchEvent (evento) e alcune altre parti del codice ascoltano quell'evento, senza che nessuna delle parti del codice debba conoscersi.

Ora il codice di animazione deve avere effettivamente un riferimento al dispatcher di eventi (facilmente eseguibile con l'iniezione delle dipendenze) ed è necessario disporre di XML o JSON che definiscono effettivamente le animazioni. Qualcosa di simile a:

{
  animation: {
    name: shoot,
    length: 12,
    spritesheet: shoot.png
    event: {
      frame: 4,
      name: bulletLeavesGun,
    },
  },
}

Leggere i dati quando si carica l'animazione e fare in modo che il codice di animazione invii l'evento quando si trova su quel fotogramma durante la riproduzione.

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.