Molti giochi Android non sono nemmeno abbastanza grandi da giustificare il salvataggio / caricamento o le opzioni / preferenze, non importa i personaggi personalizzati e simili semplicemente perché vengono giocati a mano per 10 minuti sul treno di casa.
Non commettere l'errore che ho fatto di intraprendere qualcosa con un ampio scopo per un primo gioco Android. Crea un gruppo di giochi più piccoli, quindi scegli qualcosa di più grande
Caratteristiche specifiche di Android:
Struttura:
Consiglierei di avere quasi tutto il gioco in una classe di attività. Android funziona sull'idea che ogni attività è come una mini-app, semi-indipendente dalle altre attività nell'app. L'app è essenzialmente una serie di attività, con l'utente che vede quale è sempre in cima.
Quando ne fai uscire uno in alto, generalmente viene distrutto e verrà ricreato la prossima volta che l'utente avvia una nuova attività (intento startActivity). Ciò rende difficile mantenere gli stati tra le attività e porta a un'unica architettura di attività
Potresti voler avere un'attività di tipo schermata principale con un menu "Nuova partita / Carica partita / Opzioni" su di essa e fare quella attività di lancio. Tuttavia, alla fine dovrai avere un menu di gioco anche nella tua attività di gioco, che avrà la maggior parte delle stesse funzioni al suo interno
La mia app, ho creato un "MenuActivity" che ha le funzioni che lanciano un nuovo gioco, salvano, caricano, cambiano opzioni. Quindi la mia HomeActivity lo estende, così come la mia GameActivity.
Dal momento che tutto è in una classe Activity, consiglierei di creare una gerarchia di classi di attività e utilizzare lotti di ambito privati, protetti e predefiniti. In questo modo, almeno puoi dividere le cose in file diversi per evitare di avere un file attività ingestibile. Ad esempio per la mia app:
GraphicsEngine extends MenuActivity
.
PhysicsEngine extends GraphicsEngine
.
GameLogicActivity extends PhysicsEngine
.
UIActivity extends GameLogicActivity
.
Dal momento che la mia app è in 3D, molte cose che faccio non funzionano tra le attività, quindi tutto è nella stessa attività, quindi forse sono distorto verso l'uso di un'architettura di attività
-
Threading
Per l'attività di gioco, hai due thread (o 3 se stai facendo cose 3D opengl). Un thread è l'interfaccia utente / thread principale. Questo è il thread in cui l'attività inizia e viene eseguita e ti viene data da Android.
Questo thread dell'interfaccia utente è l'unico in cui è possibile aggiornare gli elementi dell'interfaccia utente (viste, layout ecc.). È anche quello in cui verranno eseguiti tutti i listener per l'input dell'utente. Non vedi nessuno dei meccanismi del thread dell'interfaccia utente, solo che viene eseguito da qualche parte in un ciclo in background.
Il secondo thread, te lo fai (consiglierei di usare AsyncTask , nonostante tutte le sue carenze). Questo fa tutte le cose che non fai nell'interfaccia utente in un normale ciclo di gioco, come l'aggiornamento dei movimenti, il calcolo delle collisioni, i calcoli del combattimento e così via.
Rendi questo thread / classe AsyncTask come una classe interna della tua attività. In questo modo, è possibile disporre di alcuni oggetti ( Vector<Spaceship>
) a portata di attività a cui è possibile accedere sia dal thread dell'interfaccia utente sia dal thread del loop di gioco.
Dal momento che la logica di gioco è in corso nel thread del loop di gioco, questo è l'unico thread che dovrà effettivamente cambiare i valori delle variabili (aggiornare la velocità del serbatoio, ridurre gli HP dei giocatori). Il thread dell'interfaccia utente legge solo i valori, quindi dovrebbero esserci problemi di concorrenza minimi.
Il problema è che il thread dell'interfaccia utente esegue aggiornamenti su richiesta del thread del loop di gioco. Ci sono un paio di modi per farlo. Se leggi la documentazione di AsyncTask, ha il metodo publishingProgress () / onProgressUpdate (). Questo in realtà sta aggiungendo elementi alla coda di thread del thread dell'interfaccia utente per eseguire il ciclo successivo.
Handler fa esattamente la stessa cosa, in cui si implementa il metodo handleMessage () e quel metodo viene effettivamente eseguito dal thread successivo dell'interfaccia utente.
Infine, qualsiasi input dell'utente, trovandosi nel thread dell'interfaccia utente, è possibile aggiornare immediatamente gli elementi dell'interfaccia utente (quindi all'interno dell'implementazione di tutti i listener onClick / onTouch). Se è necessario aggiornare gli oggetti di gioco, è possibile utilizzare cose come la sincronizzazione o è possibile implementare la propria coda di aggiornamenti in AsyncTask che, come il thread dell'interfaccia utente, passa alla successiva esecuzione del ciclo di gioco
Guida ai thread Android .
-
UI
Per quanto riguarda l'attuale struttura dell'interfaccia utente all'interno della singola attività, ti consiglio di avere un layout di frame come layout di base. Gli elementi figlio in un layout di frame funzionano come una coda. Il primo elemento viene disegnato per primo, il secondo viene disegnato in cima al primo, il terzo in cima al secondo.
In questo modo, è possibile disporre di più file di layout XML e, gestendo i figli del layout della cornice, è possibile scambiare facilmente set di viste dentro e fuori.
Se hai sempre SurfaceView in basso (primo figlio nel layout della cornice), puoi utilizzare tutte le solite viste / widget Android (pulsanti, viste di testo, viste di scorrimento) ecc. Sopra la vista di superficie, che fa la parte grafica del gioco.
Quindi, ad esempio, se qualcosa si sta caricando, puoi mettere in pausa il loop del gioco / farlo saltare per saltare tutto, aggiungere una schermata di 'caricamento' opaca come ultimo figlio al layout della cornice e l'utente vedrà apparire 'caricamento' sullo schermo , del tutto inconsapevole che dietro ci siano altre opinioni. In questo modo non è necessario rimuovere le visualizzazioni che richiedono molto tempo per essere configurate o causare complicazioni ogni volta che vengono aggiunte / rimosse.
Consiglierei anche di utilizzare i lotti View.setVisibility. Ad esempio, è possibile aggiungere un intero layout di "inventario" al layout del frame di base e quindi impostareVisibility (View.Visible) su di esso quando l'utente fa clic per visualizzare il proprio inventario e setVisibility (View.Gone) quando lo chiudono di nuovo. In questo modo, non stai nemmeno gestendo i figli del layout del frame, ma semplicemente aggiungendo tutto e rendendo le cose visibili / invisibili come e quando l'utente fa cose diverse
Questo aiuta di nuovo con il threading; quando l'utente fa clic per aprire il proprio inventario, onCLickListener viene gestito nel thread dell'interfaccia utente, l'inventario viene reso visibile al suo interno e il metodo updateInventory viene chiamato, sempre dal thread dell'interfaccia utente, con solo getter su tutti gli oggetti di gioco chiamati
Ecco il diagramma che ho fatto per una domanda precedente sull'idea di layout di singola attività / frame: