Problèmes avec les threads Android

9

J'ai du mal à me concentrer sur la conception du jeu. Sur la plate-forme Android, j'ai une activité et je définis sa vue de contenu avec une vue de surface personnalisée. La vue de surface personnalisée agit comme mon panneau et je crée des instances de toutes les classes et j'y fais tout le dessin et le calcul.

Question: Dois-je plutôt créer les instances d'autres classes de mon activité?

Maintenant, je crée une classe de threads personnalisée qui gère la boucle de jeu.

Question: Comment utiliser ce cours unique dans toutes mes activités? Ou dois-je créer une instance distincte de la classe de thread étendue à chaque fois?

Dans mon jeu précédent, j'avais plusieurs niveaux qui devaient créer une instance de la classe de thread et dans la classe de thread, je devais définir des méthodes de constructeur pour chaque niveau distinct et dans la boucle utiliser une instruction switch pour vérifier le niveau dont il avait besoin pour le rendu et mettre à jour. Désolé si cela semble déroutant.

Je veux juste savoir si la méthode que j'utilise est inefficace (ce qu'elle est probablement) et comment procéder pour la concevoir correctement. J'ai lu de nombreux didacticiels et j'ai toujours beaucoup de problèmes avec ce sujet particulier. Peut-être un lien vers des tutoriels qui expliquent cela? Merci.

semajhan
la source

Réponses:

13

Je recommande fortement d'avoir un thread de rendu (l'utilisation de Canvas/ OpenGL ES, Canvasest probablement un peu plus facile à configurer) et un thread de jeu où vous mettez votre logique de jeu.

Pour réellement "charger" le jeu, vous pouvez créer une classe GameEngine et en faire le point central de votre application. Lorsque votre moteur de rendu est prêt à fonctionner, vous pouvez créer un rappel vers l'instance GameEngine qui créera et démarrera deux threads en utilisant un Runnablepour le rendu et un autre Runnablepour la logique du jeu.

Exemple de code:

Début de l'application

private GameEngine engine;
private CanvasRenderer renderer;

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   // Create instances of your two Runnable classes and pass that into
   // the GameEngine constructor.
   // Create an instance of the game engine.
   engine = new GameEngine(canvasRunnable, gamelogicRunnable);
   renderer = new CanvasRenderer(this, engine); 
   setContentView(renderer); 
}

CanvasRenderer

private GameEngine engine;    

// Save your instance from the GameEngine reference in your constrcutor and make
// a global initializion for your GameEngine instance.  

@Override
public void surfaceCreated(SurfaceHolder holder) {  
   // One time setup here.
   // When your view is ready, make this callback to the 
   // GameEngine.
   engine.surfaceIsReady();
}

GameEngine

private Thread canvasThread;
private CanvasRunnable canvasRunnable;
// You should be able to figure out how to create a second thread
// where you should put your game logic. :)

// Constructor stuff like creating instances of your threads
// and passing references as you wish to those.
// Don't start the threads here.
// Remember to set references from your Runnable's into your Thread's 
// instances here!

/**
 * Callback. Now your renderer is ready and you
 * can start your threads.
 */
public void surfaceIsReady() {
   thread.setName("Canvas");
   thread.start();
   // Same for game logic.
}
Wroclai
la source
Wow merci. J'ai aimé la façon dont tu l'as expliqué. Cette seule explication éclaire tout le concept pour moi.
semajhan
@semajhan: Demandez simplement si vous avez plus de problèmes. :)
C'est ce que j'ai dans ma tête: la classe GameEngine qui agit comme un "lien" ou une "référence" à toutes les autres classes avec le panneau. Activité> Panel> GameEngine> toutes les autres classes.
semajhan
@semajhan: Exactement. Pour votre seule connaissance: si vous décidez d'aller avec, OpenGL ESvous devez savoir que le moteur de rendu OpenGL ESpossède déjà son propre thread et dans ce cas, vous n'avez pas besoin de créer et de démarrer manuellement un nouveau Threadet Runnablepour ce système.
Ignorez ce commentaire.
semajhan
3

En règle générale, votre boucle de jeu est autonome dans une seule activité.

lorsque vous changez d'activité, vous mettez en pause / tuez votre boucle de jeu. Les activités distinctes doivent de toute façon correspondre à une pause du jeu (par exemple parce que vous êtes passé à une activité "envoyer un e-mail à des amis" ou "menu principal")

Pour les niveaux supplémentaires, vous ne devriez pas créer ou détruire de nouveaux threads ... à moins que vous ne soyez passé à une activité "niveau terminé, chargement du niveau suivant, veuillez patienter" et vous devrez redémarrer le "jeu principal" "Activité quand même. Mais même dans ce cas, vous ne faites pas vraiment de fils "supplémentaires", vous faites juste un fil dans cette activité, et vous tuez / redémarrez / tuez / redémarrez séquentiellement ... etc cette activité. chaque fois qu'un niveau est terminé.


la source
3

Si vous comprenez l'allemand, ce tutoriel est très agréable.

Pour la langue anglaise, je peux recommander ce tutoriel

Concernant la classe des threads: je ne sais pas s'il est vraiment nécessaire que vous puissiez faire référence à toutes les classes de votre application. Dans mon jeu, je l'ai résolu de cette façon:

La classe chargée de dessiner l'interface graphique principale a une méthode de rendu surchargée. Dans cette méthode, une classe de threads est appelée, qui met à jour tous les éléments de l'interface graphique et traite les entrées utilisateur.

Le fil est également chargé de maintenir un taux de rafraîchissement constant. Selon le jeu que vous développez, cela peut être important.

RoflcoptrException
la source
Ce tutoriel allemand est sympa mais il a été grossièrement traduit vai google donc c'est un peu difficile à comprendre.
semajhan