tutorial - pygame python 3



Est-ce que Pythonic a une classe qui garde une trace de ses instances? (4)

Prenez l'extrait de code suivant

class Missile:
    instances = []

    def __init__(self):
        Missile.instances.append(self)

Maintenant, prenez le code:

class Hero():
    ...
    def fire(self):
        Missile()

Lorsque le héros se déclenche, un missile doit être créé et ajouté à la liste principale. Ainsi, l'objet hero doit référencer la liste lorsqu'il se déclenche. Voici quelques solutions, mais je suis sûr qu'il y en a d'autres:

  • Rendez la liste globale
  • Utilisez une variable de classe (comme ci-dessus), ou
  • Avoir l'objet héros contenir une référence à la liste.

Je n'ai pas posté ceci sur gamedev parce que ma question est en fait plus générale: le code précédent est-il considéré correct? Dans une situation comme celle-ci, existe-t-il une solution plus Pythonic?

https://ffff65535.com


Des questions:

  • Est-ce que le Héros a un contrôle supplémentaire sur le missile une fois lancé?
    • Oui -> garder la liste avec l'instance de héros
    • Non -> gardez-le ailleurs
  • La classe de missiles a-t-elle besoin de connaître les missiles déjà créés pour créer un nouveau missile ou pour traiter d'autres missiles?
    • Oui -> garder la liste avec la classe de missiles
    • Non -> gardez-le ailleurs
  • Avez-vous répondu Non aux deux questions ci-dessus?
    • Oui -> garder la liste dans le cadre du jeu

Il n'y a rien d'inhabituel à garder la liste dans le cadre de la classe si vos raisons de le faire ont un sens.


Indépendamment d'être Pythonic, je dirais que la bonne pratique OO exigerait que la classe Héros maintient la liste des missiles.

(À moins qu'il me manque quelque chose, et qu'un Missile devrait être au courant des autres?)

Quelque chose comme ça pourrait être approprié:

class Hero():
    def __init__(self):
        self.missiles = []

    def fire(self):
        self.missiles.append(Missile())

Si vous avez besoin d'une liste 'globale' de missiles plutôt qu'une pour chaque Hero , je vous suggère de créer une variable membre statique à la place:

class Hero():
    missiles = []

    def fire(self):
        Hero.missiles.append(Missile())

Laisser un personnage garder une trace des projectiles qu'il a lancés peut fonctionner correctement, mais cela signifie aussi que chaque fois que vous enlevez ce personnage, ses projectiles ont disparu. Si je me souviens bien, c'est ce qui est arrivé à Tiberian Sun quand vous avez détruit un MLRS en vol stationnaire - s'il avait des missiles en vol quand il a explosé, ils disparaîtraient.

Laisser une fonction de mise à jour des caractères retourner le projectile (s) qu'il a créé, de sorte que la boucle de mise à jour peut les mettre dans une liste de projectiles, peut également fonctionner très bien. La gestion de plusieurs projectiles par mise à jour peut être aussi simple que de retourner une liste - elle peut être vide ou contenir un projectile ou plus.

Voici ce que je propose: stocker les projectiles et les personnages (héros, alliés, ennemis, etc.) dans un objet World, et transmettre une référence à cet objet à chaque personnage qui a besoin d'interagir avec lui (en lançant des projectiles dans le monde) ou en vérifiant les ennemis proches). Pour chaque missile lancé par votre héros, il appelle la fonction addProjectile de son monde. Si le héros a besoin d'effectuer d'autres actions qui affectent le reste du jeu, l'objet World peut fournir des fonctionnalités pour cela, sans que vous ayez à encombrer la boucle de mise à jour principale avec des cas spéciaux.

Bien sûr, vous n'êtes pas limité à une seule approche. Vous pouvez les combiner chaque fois que vous en avez besoin. Si vous avez des projectiles de ralliement, vous pouvez leur donner une référence à leur cible, afin qu'ils puissent mettre à jour leur vélocité à chaque appel de mise à jour. Si vous avez des projectiles qui ne peuvent pas endommager celui qui les a déclenchés, vous pouvez leur donner une référence à leur 'propriétaire'. Si un personnage ne peut avoir que 2 projectiles en même temps (comme dans certains anciens jeux), vous pouvez faire en sorte que les personnages gardent une trace de leurs projectiles actifs, afin qu'ils sachent quand s'arrêter de tirer. Vous pouvez même laisser les projectiles garder la trace de leurs «amis» s'ils sont tirés en rafale, afin qu'ils puissent coordonner leur mouvement pour former des modèles de flocage de fantaisie. ;)


Votre code est OK, et les deux premières solutions que vous avez suggérées sont acceptables (ne comprennent pas vraiment la troisième complètement: quelle liste est "la liste"?).

En fonction de vos besoins, et si de nombreuses classes ont besoin de ce type de système de suivi (puces, fusées, mines ...), vous pouvez déplacer cette logique de suivi dans une métaclasse (classes utilisées pour instancier des classes).

En substance, vous sous-classez la classe de type et créez votre propre "constructeur de classe", puis vous utilisez la syntaxe suivante:

__metaclass__ = my_metaclass_that_generate_classes_tracking_their_instantiation

dans votre classe à suivre.

EDIT: il suffit de lire votre commentaire à la question initiale. Si vous avez plus d'entités tirant des missiles de la même classe, alors le modèle le plus propre à suivre - IMO - serait d'avoir une entité ech (Hero, BadGuy, Allied ...) pour garder une liste d'objets missiles. Il modélise le monde que vous décrivez de près et facilitera la maintenance du code ...

HTH!





python