Sto imparando alcuni programmi di grafica e sono nel bel mezzo del mio primo progetto di questo genere. Ma, in questo momento, sto davvero lottando per come architettarlo in modo pulito. Lasciami spiegare.
Per visualizzare una grafica complicata nella mia lingua preferita (JavaScript - ne hai sentito parlare?), devi disegnare il contenuto grafico su un elemento <canvas>
. E per fare l'animazione, devi cancellare <canvas>
dopo ogni fotogramma (a meno che non rimanga la grafica precedente).
Pertanto, la maggior parte dei demo JavaScript correlati al canvas che ho visto hanno una funzione simile a questa:
function render() {
clearCanvas();
// draw stuff here
requestAnimationFrame(render);
}
render
, come si può ipotizzare, incapsula il disegno di un singolo fotogramma. Che cosa contiene un singolo fotogramma in un momento specifico, beh ... questo è determinato dallo stato del programma. Quindi, per fare in modo che il mio programma faccia la sua cosa, ho solo bisogno di guardare lo stato e decidere cosa renderizzare. Giusto?
destro. Ma è più complicato di quanto sembri.
Il mio programma si chiama "Critter Clicker". Nel mio programma, vedi diverse simpatiche critters rimbalzare sullo schermo. Cliccando su uno di loro lo agita facendolo rimbalzare ancora di più. C'è anche una schermata iniziale, che dice "Clicca per iniziare!" prima che vengano visualizzate le creature.
Ecco alcuni degli oggetti con cui sto lavorando nel mio programma:
StartScreenView // represents the start screen
CritterTubView // represents the area in which the critters live
CritterList // a collection of all the critters
Critter // a single critter model
CritterView // view of a single critter
Niente di troppo eclatante per questo, penso. Tuttavia, quando ho deciso di arricchire la mia funzione render
, mi blocco, perché tutto ciò che scrivo sembra assolutamente brutto e ricorda un certo piatto popolare italiano. Qui ci sono un paio di approcci che ho provato, con il mio processo di pensiero interno incluso, e pezzi non correlati esclusi per chiarezza.
Metodo 1: "Le condizioni sono fino in fondo"
// "I'll just write the program as I think it, one frame at a time."
if (assetsLoaded) {
if (userClickedToStart) {
if (critterTubDisplayed) {
if (crittersDisplayed) {
forEach(crittersList, function(c) {
if (c.wasClickedRecently) {
c.getAgitated();
}
});
} else {
displayCritters();
}
} else {
displayCritterTub();
}
} else {
displayStartScreen();
}
}
Questo è un esempio molto semplificato. Tuttavia, anche con solo una frazione di tutte le condizioni di rendering visibili, render
sta già iniziando a sfuggire di mano. Quindi, non esitare e prova un'altra idea:
Approach 2: Under the Rug
// "Each view object shall be responsible for its own rendering.
// "I'll pass each object the program state, and each can render itself."
startScreen.render(state);
critterTub.render(state);
critterList.render(state);
In questa configurazione, ho essenzialmente spinto queste pazzesche condizioni nidificate a un livello più profondo del codice, nascondendole dalla vista. In altre parole, startScreen.render
controllerebbe state
per vedere se effettivamente doveva essere disegnato o meno, e prendere l'azione corretta. Ma questo sembra più che solo risolva un problema estetico del codice.
Il terzo e ultimo approccio che sto considerando di condividere è l'idea che potrei inventare la mia "ruota" per occuparmi di questo. Sto immaginando una funzione che prende una struttura dati che definisce ciò che dovrebbe accadere in un dato punto della chiamata di render
- rivelando le condizioni e le dipendenze come un tipo di albero.
Approach 3: Mad Scientist
renderTree({
phases: ['startScreen', 'critterTub', 'endCredits'],
dependencies: {
startScreen: ['assetsLoaded'],
critterTub: ['startScreenClicked'],
critterList ['critterTubDisplayed']
// etc.
},
exclusions: {
startScreen: ['startScreenClicked'],
// etc.
}
});
Sembra un po 'fico. Non sono esattamente sicuro di come funzionerebbe, ma posso vedere che è un modo piuttosto elegante per esprimere le cose, specialmente se fletto alcuni degli eventi di JavaScript.
In ogni caso, sono un po 'perplesso perché non vedo un modo ovvio per farlo. Se non si riusciva a capirlo, sono arrivato a questo dal mondo dello sviluppo web e scoprire che fare animazione è un po 'più esotico di organizzare un'applicazione MVC per gestire richieste semplici - > risposte.
Qual è la soluzione chiara e consolidata per questo problema comune di I-would-think?