Comment puis-je implémenter un état persistant pour des objets définis dans un niveau?

17

Je développe une Metroidvania 2D qui consiste en une série de niveaux interconnectés qui peuvent être revisités.

Chaque niveau est représenté par un fichier Tiled TMX dans lequel j'ai spécifié où divers objets de différentes classes de sprites apparaissent (par exemple, ennemis, micros, leviers, etc.). Lors du démarrage d'une nouvelle partie, du chargement d'une partie enregistrée ou de la modification d'un niveau, ma boucle de jeu parcourt le fichier TMX approprié et génère tous les objets de ce niveau.

Je gère les changements de niveau de la manière suivante: Si l' Playerobjet croise un Portalobjet, une change_map()méthode est appelée qui charge une nouvelle carte (celle associée au portail intersecté) et positionne le joueur à la position appropriée sur la nouvelle carte.

Certains de mes objets ont des états que j'aimerais persister à travers les changements de niveau et la sauvegarde et la fermeture du jeu. Par exemple, si un joueur déverrouille une porte et que l'attribut d'état de la porte est défini sur "ouvert", je voudrais que la porte soit ouverte lorsque le joueur revient. Je veux quelque chose de similaire pour les leviers, qui peuvent être réglés à gauche ou à droite, et divers autres objets. De plus, le joueur aura parfois récupéré des objets que je ne veux pas réapparaître lorsque le joueur revisite la zone.

Ma question est donc comment puis-je gérer ce type de persistance?

Je travaille en Python, bien que je pense que vous pouvez vous en éloigner.

GoldenGremlin
la source

Réponses:

27

Je pense que ne pas trop réfléchir à ce problème donnera les meilleurs résultats.Je voudrais donc simplement implémenter un système de sauvegarde de valeur-clé simple dans votre jeu que vous stockez avec vos autres données de sauvegarde, puis chargez à la demande lorsque vous devez accéder à un état précédent.

Le flux pourrait ressembler à ceci:

  1. Charger le niveau à partir du fichier
  2. Avant de placer une tuile / objet, vérifiez si elle a une propriété "persistante".
    1. Si oui: vérifiez la paire clé-valeur enregistrée pour la clé correspondant à la propriété et récupérez la valeur appropriée.
    2. Si non: placez l'objet normalement
  3. Lorsque le joueur quitte le niveau / enregistre la boucle de jeu à travers tous les objets avec une propriété "persistante" et les enregistre en tant que paire clé-valeur.

Voici un exemple de pseudo-code basé sur ce que j'utilise pour mon jeu 2D simple:

def load_map(map):
    for y in range(0, height):
        for x in range(0, width):
            tile = map[x, y]

            for property in tile.properties:
                if is_persistent(property.name):
                    // Name prefixed with "persistent" means that it's persistent
                    // so we load the value from out persistent storage
                    property.value = persistent_values[property.name]

def save_map(map):
    ... everything in load_map ...
    if (property.name.matches("persistent_*")):
        // Name prefixed with "persistent" means that it's persistent
        // so we save the value to persistent storage
        persistent_values[property.name] = property.value

def is_persistent(name):
    return name.matches("persistent_*") and persistent_values.contains(name)

Ensuite, je peux simplement vérifier l'état en utilisant cette propriété:

def draw():
    if properties["persistent_is_pressed"].value:
        draw_sprite(button_pressed)
    else:
        draw_sprite(button_unpressed)

def on_pressed():
    properties["persistent_is_pressed"].value = not properties["persistent_is_pressed"].value

Si vous utilisez un éditeur de carte en mosaïque comme Tiled, l' ajout de propriétés comme celle-ci est très simple:

ajout d'une propriété

J'espère que cela vous donnera une idée sur la façon d'implémenter l'état persistant le plus simplement possible!

Charanor
la source
Ceci est très utile, même si j'ai du mal à voir exactement comment l'appliquer à ma situation. J'y penserai un peu plus.
GoldenGremlin
Je pense que j'ai du mal à voir comment je peux faire en sorte que la sauvegarde des valeurs fonctionne. Lorsque j'économise, je n'itérerai pas sur les tuiles dans les données TMX. Je vais plutôt parcourir les objets sprite de mon groupe all_sprites. Lorsque je charge les cartes, j'utilise les propriétés TMX des objets TMX comme paramètres lors de l'instanciation de mes objets sprite, mais après cela je ne touche pas ces propriétés, donc elles ne suivent pas les changements dans les objets sprite.
GoldenGremlin
1
@dietestus Vous devriez probablement simplement donner à vos objets sprite un propertieschamp que vous modifiez à la place et utiliser uniquement les tuiles propertiescomme indication de la propriété à modifier (mais toutes les données sont stockées dans votre sprite). Vous pouvez également simplement passer la tuile à votre sprite afin que vous puissiez modifier la tuile à partir du sprite :) si ce n'est pas clair ce que je veux dire, je peux simuler un peu plus de pseudocode
Charanor
3
@dietestus Dès que vous interagissez avec une entité persistante (porte, levier), vous enregistrez le nouvel état dans la carte de valeurs-clés. Vous n'avez pas besoin de parcourir les cartes lorsque vous enregistrez, vous avez déjà tout dans votre carte.
Herr Derb
1
@dietestus Oui vous l'êtes :) c'est un dictionnaire simple où les clés sont des noms de propriétés et les valeurs sont (enfin ... des valeurs). Avoir plusieurs objets sur la même tuile ne changera rien tant que vous aurez des clés uniques.
Charanor