Salut les lecteurs !
Aujourd'hui j'ai fait une grosse, grosse, avancée dans le développement du jeu...
J'aimerais vous montrer plein d'images, de vidéos et de trucs cool, vous faire comprendre à quel point c'est génial et à quel point c'est un vrai soulagement d'enfin avoir trouvé une solution facile à ce problème qui me stresse depuis quasiment le tout début du projet mais...
...Mais cette avancée est un peu nulle en fait vue du côté utilisateur... Bref, c'est une news technique aujourd'hui donc si vous n'êtes pas intéressés par ce genre de billets, retenez juste que j'ai travaillé sur la sauvegarde et partez donc regarder Kung Fury pendant que je raconte ma vie ;)
Pour ceux qui restent, la sauvegarde !
C'est un soucis assez épineux sur lequel je réfléchis depuis un moment. Comment gérer le chargement d'une sauvegarde quand le joueur a amené des objets d'un niveau dans un autre ? Comment rendre son équipement au joueur lors du chargement d'une partie ?
Ben quoi, tu l'as pas déjà fait pour What Lies Beneath ?
Oui et non. Dans What Lies Beneath, je pense vous en avoir déjà parlé mais les objets sont simplement représentés par des chaines de caractères, ou des mots si vous préférez ("epeeFer", "bouclierBois",...). Ce qui les rend assez simples à gérer puisque du coup sauvegarder et charger l'inventaire du joueur consiste simplement à écrire ces mots dans un fichier, puis lorsqu'on charge une partie, lire le fichier et écrire les mots dans l'inventaire du joueur.
Mais dans Beyond, un objet est beaucoup plus complexe que ça puisque~
Bah c'est débile, t'aurais du utiliser le même système que dans WLB !
Hé non^^. Ce qu'on gagne en simplicité dans WLB, on le perd en complexité et en flexibilité. Dans WLB, une épée en fer ne sera jamais différente d'une autre. Comme je l'ai dit, le jeu ne retiens que "epeeFer". Lorsqu'on la ramasse sur le corps encore
Bref, dans What Lies Beneath, les objets sont figés, ils n'ont pas vraiment d'existence physique en dehors de l'interface et des effets qu'ils ont sur les stats de notre perso. C'est donc extrêmement simple de les "transporter" d'une scène à une autre (un coffre ne contient par exemple qu'une liste de mots, qu'on va effacer si on le loot).
Mais dans Beyond, on a besoin que certains objets soient uniques, sans s'amuser à ré-écrire une liste de caractéristiques pour chacune de ses formes. Courage, je vais m'expliquer^^. Pour reprendre l'exemple de notre épée en fer, dans Beyond, le stuff a une durabilité. Notre épée va s’abîmer en combat, puis on va la réparer, ce qui va baisser sa durabilité totale mais l'empêcher de se casser tout de suite, etc... Les objets n'ont plus des valeurs figées qu'on peut aller lire dans une liste, ils sont dynamiques.
Imaginez que je veuille créer une épée en fer un peu spéciale. C'est celle de notre père. Elle est en tous points identique à une épée en fer normale, sauf qu'au lieu de s’appeler "Epée en fer", elle s'appelle "Epée de papa".
Dans WLB, je devrais éditer ma liste d'objets, copier/coller tout ce qui concerne "epeeFer" dans un nouveau truc "epeeFerPapa" juste pour changer le nom (bon en vrai je m'y prendrais un peu différemment mais vous voyez l'idée: pour chaque épée un tout petit peu différente, je devrais aller éditer un script, recompiler le projet, etc...). Imaginez le bordel absolu si je commence à ajouter la possibilité d'enchanter son équipement, sa durabilité comme dans Beyond, etc...
Bref, dans Beyond, il n'y a pas de listes décrivant un objet, les infos sont directement écrites dans l'objet.
Cliquez pour voir en grand
Ça permet de faire pleiiiin de chouettes choses, et ça rend l'ajout d'objets en jeu beaucoup plus rapide et agréable :)
...et ça rend la sauvegarde difficile, apparemment...
Oui. On ne peut donc plus se contenter d'écrire des mots dans un fichier... On va écrire toutes les stats des objets du joueur dans un fichier. Ce n'est pas très difficile à faire, c'est exactement la même chose pour la sauvegarde des stats, skills, etc dans WLB.
Avec juste un soucis... Comment va-t-on faire pour que l'objet apparaisse en jeu ? C'est ça la vraie "difficulté" (bon en vrai c'était facile mais il a fallu apprendre comment faire^^). En gros, comment savoir au moment où on recharge la partie, quel préfab (modèle d'objet, une épée en fer, par exemple^^) on doit spawner pour ensuite lui appliquer les caractéristiques enregistrées (genre le fait que l'objet soit à moitié pété contrairement au modèle par défaut ou qu'il ait une description différente) avant de la mettre dans l'inventaire du joueur ?
Il y a deux solutions :
La première, la plus classique dans la manière dont on travaille avec Unity, serait de garder une liste de tous les objets pouvant être manipulés par le joueur... Et ensuite lier cet objet (ce préfab) à quelque chose qu'on écrirait dans notre fichier de sauvegarde... Comme... un mot !
Ça voudrait dire donner un nom unique à chacun de mes objets, comme "epeeFerPapa" puis établir dans un script que l'objet "epeeFerPapa" est lié au prefab de l'épée en fer... Hé mais ! Mais c'est pas ce qu'on voulait éviter ?!
Si si^^. Ça fonctionnerait mais ça serait (presque) aussi contraignant que tenir à jour la liste des objets de What Lies Beneath ! Heureusement il y a une deuxième solution, sinon je n'écrirais pas ce billet ;)
On va apprendre à l'objet quel est le préfab (qui est en fait un fichier) qui lui est lié. Et lorsqu'on sauvegardera toutes les infos sur l'objet, on va sauvegarder ce nom de fichier avec les autres infos (puissance, nom, description,...).
Problème réglé !
Au moment où on charge la partie, on lit les infos de l'inventaire du player. Pour chaque objet on trouve le nom de son prefab (de fichier) on charge ce prefab dans le monde puis on a plus qu'à lui appliquer toutes ses caractéristiques et à le mettre dans l'inventaire. Yay!
La seule contrainte c'est d'écrire le nom du fichier dans l'objet, ce qui se résume à un copier/coller vite fait. C'est mieux que de tenir une liste de tous les objets existants à jour, pas vrai ?^^
Mais euh, au final c'est si terrible d'utiliser une liste comme dans WLB ?
OUI ! WLB est devenu un gros projet avec le temps, le temps de compilation (temps pour que je puisse lancer le jeu dans l'éditeur après avoir modifié un script) est assez conséquent et c'est vraiment pénible de devoir patienter plusieurs dizaines de secondes sans pouvoir rien faire simplement parce que j'ai corrigé une faute d’orthographe dans la description d'un objet.
A force d'ajouter des objets, la fameuse liste est aussi devenue très très grosse, ce qui pose des soucis lorsque je veux compiler le jeu en version navigateur web (pour The Sorcerer donc).
Enfin, du fait que tout soit hardcodé dans un script, ça ne laisse aucune place au modding. Je ne pense pas que Beyond sera moddable, mais cette manière de gérer les objets est un premier pas dans cette direction, un jour mes jeux seront moddables, c'est promis^^
Conclusion
Et voilà. Il reste encore pas mal de travail pour que la sauvegarde soit opérationnelle mais l'étape la plus difficile est passée et c'est un vrai soulagement pour moi :)
Désolé pour ce billet très technique, je pense qu'il y en aura encore pas mal vu qu'il reste pas mal à faire au niveau du core du jeu.
Je crée un peu de contenu aussi pendant ce temps là mais je suis arrivé à un point où il et difficile de progresser sans implémenter des changements de scène corrects (si je passe d'une carte à une autre, je dois éviter que les objets ramassés par le joueurs réapparaissent, que les PNJ reprennent leur dialogue à zéro comme si on ne leur avait jamais parlé, etc...).