Aggiornamento (recap)
Dato che ho scritto una risposta piuttosto prolissa, ecco cosa si riassume in:
- I namespace sono buoni, li usano quando ha senso
- Utilizzare le classi
inGameIO
e playerIO
potrebbe costituire una violazione dell'SRP. Probabilmente significa che stai accoppiando il modo in cui gestisci l'IO con la logica dell'applicazione.
- Avere un paio di classi IO generiche, che vengono utilizzate (o talvolta condivise) dalle classi del gestore. Queste classi di gestori traducono quindi l'input non elaborato in un formato in cui la logica dell'applicazione può dare un senso.
- Lo stesso vale per l'output: questo può essere fatto da classi abbastanza generiche, ma passa lo stato del gioco attraverso un oggetto handler / mapper che traduce lo stato del gioco interno in qualcosa che le classi IO generiche possono gestire.
Penso che tu stia guardando questo nel modo sbagliato. Stai separando l'IO in funzione dei componenti dell'applicazione, mentre per me ha più senso avere classi IO separate basate sul sorgente e "tipo" di IO.
Avendo alcune classi base / generiche KeyboardIO
MouseIO
per iniziare, e poi in base a quando e dove ne hai bisogno, avere sottoclassi che gestiscono diversamente detto IO.
Ad esempio, l'inserimento di testo è qualcosa che probabilmente vorresti gestire in modo diverso dai controlli di gioco. Ti troverai a voler mappare alcune chiavi in modo diverso a seconda dei casi d'uso, ma quella mappatura non fa parte dell'IO stesso, è come gestirai l'IO.
Seguendo l'SRP, avrei un paio di classi che posso usare per l'IO della tastiera. A seconda della situazione, probabilmente vorrò interagire con queste classi in modo diverso, ma il loro unico compito è quello di dirmi cosa sta facendo l'utente.
Inietterei quindi questi oggetti in un oggetto gestore che potrebbe mappare l'IO grezzo su qualcosa con cui la logica della mia applicazione può lavorare (ad esempio: pressioni utente "w" , il gestore mappa che su MOVE_FORWARD
).
Questi gestori, a loro volta, sono utilizzati per far muovere i personaggi e disegnare lo schermo di conseguenza. Una grossolana semplificazione, ma il nocciolo della questione è questo tipo di struttura:
[ IO.Keyboard.InGame ] // generic, if SoC and SRP are strongly adhered to, changing this component should be fairly easy to do
||
==> [ Controls.Keyboard.InGameMapper ]
[ Game.Engine ] <- Controls.Keyboard.InGameMapper
<- IO.Screen
<- ... all sorts of stuff here
InGameMapper.move() //returns MOVE_FORWARD or something
||
==> 1. Game.updateStuff();//do all the things you need to do to move the character in the given direction
2. Game.Screen.SetState(GameState); //translate the game state (inverse handler)
3. IO.Screen.draw();//generate actual output
Ciò che abbiamo ora è una classe che è responsabile della tastiera IO nella sua forma grezza. Un'altra classe che traduce questi dati in qualcosa che il motore di gioco può effettivamente dare un senso, viene quindi utilizzata per aggiornare lo stato di tutti i componenti coinvolti e, infine, una classe separata si prenderà cura dell'output sullo schermo. / p>
Ogni singola classe ha un singolo lavoro: la gestione dell'input da tastiera viene eseguita da una classe che non conosce / cura / deve sapere che cosa significa l'input che sta elaborando. Tutto ciò che fa è sapere come ottenere l'input (buffered, unbuffered, ...).
Il gestore lo traduce in una rappresentazione interna per il resto dell'applicazione per dare un senso a queste informazioni.
Il motore di gioco prende i dati che sono stati tradotti e li usa per notificare a tutti i componenti rilevanti che qualcosa sta succedendo. Ognuno di questi componenti fa solo una cosa, indipendentemente dal fatto che si tratti di controlli di collisione o di modifiche all'animazione del personaggio, non importa, questo dipende da ogni singolo oggetto.
Questi oggetti quindi ritrasmettono il loro stato e questi dati vengono passati a Game.Screen
, che è essenzialmente un gestore di IO inverso. Mappa la rappresentazione interna su qualcosa che il componente IO.Screen
può utilizzare per generare l'output effettivo.