Ajout de gardes dans les villages
dans la rubrique La boîte à idées
←
/ #71
/ rss
/ →
Maintenant que l'affichage des murs des cavernes se fait bien, je vais pouvoir passer aux premiers PNJ, les gardes à l'entrée des villages. Problème, le code tel que conçu actuellement ne permet pas de gérer simplement le déplacement de PNJ ou de monstres entre plusieurs zones différentes.
Explications et passage en revue des changements à venir...
Le monde et les zones
Chaque monde de Lands of Elderlore est créé à partir d'un nom unique et d'une taille donnée (cette valeur est stockée dans monde.taille). Pour chaque case du monde, on fait correspondre une zone de taille par défaut de 6 dans elderlore.ini, ce qui correspond à un carré de 64 cases de côté (cette valeur est stockée dans jeu.cfg.taille_zone). Ces zones ne sont calculées qu'au moment où on a besoin d'avoir des informations dessus; par exemple quand le joueur se déplace et qu'il faut afficher un case d'une zone qui était jusque là inconnue.
Une exception à cette règle : à l'arrivée du joueur dans un nouveau monde, on calcule les 9 zones autour du joueur et on les met en mémoire dans la liste Joueur.zones_connues grâce aux fonctions Joueur.Init_Zones et Joueur.Ajoute_Zone_Inconnue :
def Init_Zones(self):
"""Mise en mémoire des 9 zones autour du joueur"""
for dir in el.dirs9:
pos = [self.monde.Replace(self.pos_monde[0]+dir[0]), \
self.monde.Replace(self.pos_monde[1]+dir[1])]
self.Ajoute_Zone_Inconnue(pos)
def Ajoute_Zone_Inconnue(self, pos):
"""Ajoute une zone inconnue à la liste des zones connues autour du joueur"""
# Création de la zone
zone = el_zone.Zone(self.jeu, self.monde, pos)
#self.partie.Ajoute_Message("Nouvelle zone : %s", pos)
# Mise en mémoire de la zone
if len(self.zones_connues) < self.nb_zones_connues:
# la liste n'est pas pleine, on ajoute la zone en queue de liste
self.zones_connues.append(zone)
self.id_zones_connues.append(zone.id)
# la nouvelle zone est la plus populaire, on la met en tête de self.idord_zones_connues
self.idord_zones_connues.insert(0, zone.id)
else:
# la liste est pleine, on supprime la zone la moins populaire :
# on supprime le dernier element de self.idord_zones_connues (avec la fonction pop),
# et on cherche sa position dans self.id_zones_connues
pos_index = self.id_zones_connues.index(self.idord_zones_connues.pop())
# on remplace l'élement trouvé par la nouvelle zone
self.zones_connues[pos_index] = zone
self.id_zones_connues[pos_index] = zone.id
# on ajoute zone.id au début, elle devient la plus populaire
# et toutes les autres voient leur popularité baisser d'un cran
self.idord_zones_connues.insert(0, zone.id)
Le principe est simple; supposons qu'au début du jeu, le joueur soit entouré de neuf zones qu'on appellera z1, z2, ..., z9 :
+----+----+----+ | z1 | z2 | z3 | +----+----+----+ | z4 | z5 | z6 | +----+----+----+ | z7 | z8 | z9 | +----+----+----+
(Le joueur est ici situé dans la zone z5)
Ces zones dont d'abord ajoutées à la liste Joueur.zones_connues grâce à la fonction Joueur.Init_Zones. Cette liste Joueur.zones_connues contient ainsi l'ensemble des zones connues par le joueur. Quand une case d'une nouvelle zone est évaluée, on la met en position 0 de la liste, ce qui décale toutes les autres d'une position. Si la liste dépasse un nombre maximal de zones connues, la dernière est supprimée. Ainsi la liste Joueur.zones_connues contiendra les zones connues du joueur classées de la plus populaire à la moins populaire.
Cette méthode présente l'avantage de ne garder en mémoire qu'une partie utile du monde autour du joueur, et de calculer les nouvelles zones que si cela s'avère vraiment utile.
Inconvenients
Cette méthode présente malheureusement plusieurs inconvénients, qui vont devenir bloquant pour les développements à venir :
- chaque case de zone doit être évaluée pour savoir si elle fait partie d'une nouvelle zone ou pas; cela alourdit les algorithmes de gestion des objets et de calcul de champs de vision, et ralentit la vitesse d'affichage de la vue isométrique et de la vue de la carte;
- les animaux sont créés en même temps que la zone, ce qui empêche de les déplacer simplement d'une zone à l'autre;
- l'ajout de PNJ sera également problématique pour les mêmes raisons si on veut qu'ils puissent bouger entre les zones.
Solution possible
Une solution possible serait d'ajouter à la mémoire du joueur un tableau Joueur.zone_3x3 qui contiendraient les valeurs des 9 zones autour du joueur; un peu comme si le monde se résumait à ces 9 zones. Tant que le joueur reste dans la zone z5, tous les calculs du jeu se font sur Joueur.zone_3x3. Et si le joueur sort de z5, par exemple par l'est, on met à jour le tableau comme suit :
+----+----+----+ +----+----+----+ +----+----+----+ | z1 | z2 | z3 | | z2 | z3 | .. | | z2 | z3 | z10| +----+----+----+ +----+----+----+ +----+----+----+ | z4 | z5 | z6 | -> | z5 | z6 | .. | -> | z5 | z6 | z11| +----+----+----+ +----+----+----+ +----+----+----+ | z7 | z8 | z9 | | z8 | z9 | .. | | z8 | z9 | z12| +----+----+----+ +----+----+----+ +----+----+----+
Plusieurs implications :
- si des animaux ou des PNJ poursuivaient le joueur, et qu'ils étaient dans une des zones z1, z4 ou z7, ils sont effacés de la mémoire;
- si la taille des zones est très petite, et la taille à l'écran est très grande, il y a un risque d'afficher les zones au-delà de Joueur.zone_3x3, ce qui provoquera un plantage;
- au moment du changement de zone, il faudra calculer 3 nouvelles zones, et en plus mettre à jour Joueur.zone_3x3, ce qui provoquera probablement un gros ralentissement, et demandera certaines optimisations.
Un moteur d'évènements
Pour contourner le dernier point, il sera possible de créer un moteur d'évènements du jeu, qui traitera de manière séquentielle les différentes requêtes, à raison d'une requête pour chaque action du joueur. Ainsi, on aura :
- Tour 1 : le joueur se déplace à l'est; changement de zone ? Si oui, alors on met dans le moteur d'évènement :
- Tour + 1 : calculer la zone z10
- Tour + 2 : calculer la zone z11
- Tour + 3 : calculer la zone z12
- Tour + 4 : Mettre à jour Joueur.zone_3x3
- Tour 2 : le joueur se déplace : on calcule la zone z10
- Tour 3 : le joueur se déplace : on calcule la zone z11
- Tour 4 : le joueur se déplace : on calcule la zone z12
- Tour 5 : le joueur se déplace : on met à jour Joueur.zone_3x3
Les tours pourront être remplacés par des évènements threadés une fois que j'aurais compris comment ils fonctionnent ;-). En attendant, il faudra s'assurer que dans le pire des cas, le joueur ne peut pas se déplacer jusqu'au point d'afficher une case de zone qui n'a pas été encore calculée (cas du déplacement en diagonale : cela demande la mise à jour de 5 zones).
Ce moteur d'évènements sera plus tard utile pour calculer les trajets des monstres et des PNJ, pour ajouter de nouveaux monstres, en fait pour toute tâche qui peut être différée dans le temps. On pourra alors associer à chaque évènement du moteur un cout directement proportionnel au temps pris pour le traiter, pour mieux répartir les différents temps de traitement.
Ce moteur pourra même être intégré comme élément de gameplay, en autorisant sous certaines conditions l'accès aux évènements à venir pour le joueur, pour simuler l'intuition (un dragon va bientôt apparaitre dans ces montagnes !), voire même des visions du futur (la voyante m'a dit que dans un mois cette ville sera envahie par une horde de gobelins !!!).









Commentaires
Aucun commentaire pour le moment.
Ajouter un commentaire