CHAPITRE 3

Maintenant que tout est prêt, on peut démarrer. Chaque équipe (programmation et graphiste) a sa liste de tache, le document "technical design" pour les méthodes et contraintes et le "game design" pour savoir qu'est ce qu'on doit obtenir au final. On peut donc tous travailler en parallèle maintenant.

Je vais décrire si dessous les étapes importantes.

Méthodes de travail à distance

Pour le projet "le monde des ronrons", différentes équipes vont travailler à distance. En effet je n'ai pas de locaux et de toute façon mes collaborateurs sont dispersés un peu partout en France : Eric le programmeur est à Marseille, Tokkun est a Annecy dans l'est et l'artiste qui bosse pour eux est encore ailleurs. Je suis à Saint Quentin en Yvelines dans la région parisienne.

La travail à distance nécessite une organisation importante et des règles strictes. En effet dans un projet, il est important que les gens communiquent. MSN sera principalement utilisé pour communiquer, ainsi que le mail et le téléphone si besoin. L'important c'est de bosser ensemble même si l'on est pas à coté physiquement.

J'ai donc défini des règles pour le travail à distance :

Cliquez ICI pour lire les règles.

Celles ci s'appliquent pour les indépendants que j'emploi directement et à plein temps (c'est à dire pour le moment Eric).

En ce qui concerne la société Tokkun, il est convenu que chaque soir, le travail de la journée sera envoyé pour être validé. Sur un projet aussi court, il est en effet important de gérer le travail à la journée. Je ferais donc des retours journaliers sur le travail artistique.

Code : Le coeur de jeu (2 semaines)

Au niveau de la programmation, le langage utilisé est le C++.

J'ai d'abord mis en place un squelette d'architecture avec les diffèrents modules principaux.

Eric commence par le coeur de jeu. C'est à dire crée l'objet créature et le faire évoluer dans le décor. Le coeur du jeu est en 2D vue du dessus. Je lui ai préparé un environnement qui affiche un décor simple en fil de fer, et une créature en sprite. Avec cela ça doit suffire pour mettre au point les déplacement de la créature ainsi que son comportement, ce qui représente déjà un gros morceau. L'affichage 3D viendra bien après puisque ce n'est qu'un simple "habillage" (en effet le coeur de jeu tourne toujours en 2D).

La gestion du jeu est entièrement découplée de l'affichage. On commence par définir notre monde qui aura une taille de 16 unités de large et 4 de profondeur. Même si l'affichage est séparé de la gestion de notre monde, on a quand même besoin d'un affichage pour commencer à bosser. Une camera 2D est donc crée, et des fonctions de traçages de droites et d'affichage de sprites sont mis en place. Ces fonctions prennent en compte les paramètres de la camera qui sont position (centre de l'écran) ainsi que le zoom.

Pour l'affichage (et d'autres choses), j'ai choisi d'utiliser le moteur Game Incubator. Ce sont les libs persos de Jeremy Chatelaine qu'il a noblement décidé de rendre publique. Ce qui m'a plu dans ce moteur, c'est la simplicité d'écriture et la facilité pour charger et afficher des images et objets 3D. J'ai envie de passer un maximum de temps sur le jeu en lui même et non sur la technique donc ce moteur est parfait pour ce que je veux faire.

Le Game Incubator est une surcouche de directx proposant des fonctions simples pour l'affichage (2D/3D), le son et les entrée sorties. Le squelette d'un programme de base est très simple : trois fonctions init / gameloop / destroy. Le GI a son propre format d'objet 3D et d'animation. L'exporteur 3ds Max est fourni (c'est le seul problème pour moi puisque j'ai décidé d'utiliser maya). Enfin le GI est open source, donc facilement customisable si besoin. La compilation du moteur se fait aisément sous Visual Studio 2005 (Express ou pas), c'est parfait.

Donc me voila parti dans les premières fonction d'affichage : tracer des lignes 2D. Ca a l'air de rien, mais bon c'est quand même le tout premier visuel du jeu :

Les premières zones dessinées sous MAYA :

Les lignes sont sauvées au format "collada" depuis maya et converties en fichier .txt par une moulinette maison. Dans le chapitre suivant, je donne plus de détails sur cette moulinette.

Le fichier .txt avec les zones est relu par notre moteur et les zones sont affichées. J'ajoute des fonctions pour afficher des images :

Ensuite reprise du plan du jeu pour avoir des zones plus représentatives :

Les zones sont toutes transformées en zones convexes. C'est à dire que si on trace une ligne entre n'importe quel points de la zone, jamais un point de la ligne ne sortira de la zone. Pour faire des zones complexes, j'ai crée plusieurs zones simples (comme le lac). L'algorithme pour déterminer si un point est dans une zone est alors simple car les segments d'une zone sont toujours crées dans le même sens (sens inverse des aiguilles d'une montre). Ainsi on peut dire qu'un point fait partie d'une zone si le point en question est à la gauche de chaque droite définie par les segments de la zone. Pour définir si un point est d'un coté ou de l'autre d'une droite, il suffit d'insérer dans l'équation de la droite les coordonnées de ce point. (résultat négatif = à gauche, 0 = sur la droite, positif = à droite ). Les équations sont précalculées au début du programme ainsi les tests de zones sont très rapides.

Et hop cela suffit pour commencer à bosser le coeur du moteur :

Les zones servent à deux choses : Elles déterminent les endroits non accessibles (type "collision") et elle permettent aussi de déterminer le type de sol à un endroit donné : herbe, eau, sable. Enfin on s'en servira pour délimiter des zones particulières comme le ponton.

Ci joint un extrait du fichier :

Border
5
11.8254 45.4999
16.7042 50.6251
14.6846 58.5930
7.3394 56.6915
5.9595 54.7695

Loo
9
15.0167 38.3470
16.3608 38.7715
16.7381 39.9506
16.2665 41.2004
15.0167 41.5777
13.7197 41.0825
13.4131 39.9506
13.7904 38.9837
14.3564 38.5357

Border19
5
6.5274 44.1244
11.7860 45.4922
10.4998 57.3089
3.0412 55.1897
1.8622 54.3408

SmallFontain
10
11.2200 27.8119
11.8723 27.9276
11.9472 28.2965
11.9605 29.0979
11.8752 29.5853
11.2465 29.7596
10.5725 29.5385
10.5190 29.0846
10.5142 28.1796
10.7330 27.9123

Nest
7
8.1991 20.2660
11.0007 20.5392
11.9961 23.1185
8.6034 23.5552
5.6641 22.4299
5.6057 21.0540
6.5681 20.4612

Toboggan
6
20.1073 21.5327
20.7015 22.1432
20.8921 22.9186
20.0726 23.4304
18.8515 22.8316
19.1838 21.7034

Food
6
19.8020 8.6521
20.3479 9.1189
21.1048 10.3501
19.6400 11.0147
18.5763 10.2601
18.9613 9.3473

...

Note : Les coordonnées seront agrandies par la suite, d'où les valeurs plus grande que 16 dans le fichier.

Je travaille beaucoup avec des fichiers textes. Ils sont plus facilement lisible à l'oeil nu et pour ce genre de données je n'ai pas besoin que ce soit forcement rapide à lire pendant l'exécution.

D'une manière générale quasiment rien n'a été optimisé pendant le développement du jeu. La règle veut que 80% du temps soit pris par 20% du code donc vaut mieux attendre la fin du dev pour identifier ces 20% et travailler dessus.

Le fichier est donc une simple suite de zones. Chaque zone est composée d'un nom, d'un nombre de points et des points (2D). Le type de la zone est défini par le début du nom. "Waterxxx" c'est un type de sol d'eau, "Sandxxx " c'est du sable, et tout le reste c'est de la collision. Dans le jeu on a la possibilité de demander le nom des zones, ça permettra de savoir si telle ou telle action est possible suivant la zone dont on est proche.

Les premiers tests de path finder :

Le contournement d'obstacle :

Le path finder va chercher à contourner les obstacles. Il commence donc par tracer une ligne droite entre le départ et l'arrivée souhaitée. Si cette ligne traverse une zone de collision, il calcule deux itinéraires (de chaque coté de l'obstacle) et ensuite prend le plus court des deux. Un point de passage est ajouté après l'obstacle, ensuite le path finder réitère l'opération tant que l'itinéraire traverse des zone de collisions. Certaines zones tordues (comme la grande barrière ou le ponton) sont traitées en cas particulier.  On avait besoin de quelque chose de simple, cela suffit.

Code : Le format collada (3 semaines)

Pour ma part je commence par créer la moulinette qui va convertir les objets 3D exportés au format collada, vers les formats des moteurs PC et PS2. Comme on a plus d'énergie au début de projet,  je commence par les trucs difficiles.

Collada ( www.collada.org ) est un format gratuit, open source, qui a été défini par les grands groupes fabricants de modeleurs 3D ainsi que Sony. Ce format permet de décrire des objets 3D, animations et autres effets.  Ce format est censé devenir dans le futur une référence unique pour tout les échanges de données 3D (on verra si ça marche). Ainsi tout les modeleurs (Max, Maya, SoftImage, Blender) peuvent exporter/importer des objets au format collada (fichier .dae).

Le format collada est un format ascii. Les données sont écrits en xml (avec des balises). Il existe une librairie C++ (Collada DOM sourceforge.net/projects/collada-dom ) qui permet de parcourir facilement des fichiers DAE. La librairie s'utilise comme une base de données. Genre "Donne moi la liste des objets" ensuite "donne moi l'objet numéro 3", "donne moi sa géométrie" et "donne moi la texture numéro 5". Au final la notation est un poil lourde, mais la librairie permets de relire toutes les données, c'est déjà ça en moins à faire.

Pour les objets statiques, le travail s'est relativement bien passé. Après quelque jours d'effort j'arrivais à afficher des objets faits dans MAYA dans le moteur PC et PS2.

Ensuite je suis passé aux objets skinnés et aux animations. Ca a été largement plus dur. En effet, il a fallu comprendre comment était stockées les information dans le fichier collada (la doc est pas top) et ensuite comprendre comment les même information étaient stockées dans le format du moteur PC (merci à Jeremy pour son aide et ses sources). Je suis resté presque trois semaines sur ce problème. Le principe des objets skinnés est le suivant : Un objet est composé d'un squelette, qui est un ensemble d'os reliés entre eux. Les "enfants" sont solidaires des "parents". C'est à dire que si l'on bouge un os (en général "bouger" veut dire "tourner") alors tous les enfants reliés à cet os bougent aussi. Ci dessous un exemple simple de squelette composé de 5 os :

Chaque vertex ( les points 3D de l'objet en lui même, ici une bande colorée) est positionné dans l'espace en ensuite on l'associe avec 1 ou 2 os avec un coefficient pour chaque. Ainsi quand un os bouge, il influence tous les points qui lui sont relié. On peut ainsi animer des centaines de points, en bougeant simplement quelques os. C'est ensuite bien plus simple pour réaliser des animations, on anime que le squelette, les points suivent tout seuls. Ci joint le résultat quand tourne chaque os d'un petit angle (le même pour chaque os).

Le mouvement étant relatif pour chaque os, le dernier os se retrouve avec le mouvement des tous les autres os précèdent, plus le sien.

Le format collada :

Le format du Game Incubator :

Et quand tout a commencé à fonctionner avec des objets simples, j'ai pu faire des test avec des squelette plus complexes proche du jeu :

Ci joint le tout premier essai d'export de perso :

Dans la vie on a pas toujours ce qu'on attend et les premières fois sont souvent loupées. J'en ai eu beaucoup des problèmes comme ça, l'important c'est de jamais baisser les bras.

Bon c'est pas encore ça, mais ça se rapproche du cylindre que c'est censé représenté :)

Voila donc mon ronron dans le moteur 3D (c'est un objet test que j'ai fait, donc normal qu'il soit laid). Au niveau des anims, ça fonctionne à peu prés, cependant il reste beaucoup de bug qui seront découverts au moment d'animer les vrais modèle. En fait le debug de l'export d'anim a duré quasiment jusqu'à la fin du projet par petite touche. C'est de loin le sujet le plus complexe de l'ensemble du projet.

Graphiste : Modélisation du décor (1 semaine)

L'artiste choisi par Tokkun pour faire les graphismes 3D est Julien Noel (julienno.free.fr ). Julien a commencé par une mise à l'échelle du monde. Pour mes premiers tests j'avais fait un monde sous maya qui avait une largeur de 16 unités. Ce n'étais pas pratique pour le travail artistique, donc on a tout multiplié par 9. Le monde fait maintenant 140 unités de larges et 40 de profondeur. A partir de la, Julien a commencer à faire un décor au brouillon, en insérant des personnages et objets fait rapidement pour régler les échelles. C'est important de se mettre d'accord sur ce genre de choses importantes avant d'attaquer le gros boulot.

Une fois que l'échelle est bonne, la modélisation plus fine des objets à été faite :

La balançoire.

Le ponton, revu plusieurs fois et elargi.

La nourriture.

La phase modélisation de décor s'est bien passée. Julien a bien compris comment retranscrire les éléments de décor tout en respectant le contraintes.

Code : Architecture (1 semaine)

Le code est architecturé en modules. Chaque module a pour but de gérer une chose et une seule (on appellera ça des "managers"). Tous les modules possèdent 3 fonctions de base : "Init", "Update" et "Destroy".  Certains modules ont aussi une fonction "Display".

"Init" est appelé une fois quand le jeu est lancé. C'est la dedans qu'on initialise tous ce qui a besoin de l'être (initialisation des variables, chargement de données).

"Update" est appelé à chaque boucle de jeu. C'est la dedans que la gestion est faite.

"Display" est appelé à chaque boucle de jeu (après update). C'est la dedans que l'affichage se fait.

"Destroy" est appelé une fois en fin de jeu lorsque l'utilisateur sort et détruit toutes les choses qui ont été chargées/allouées par la fonction "Init".

Au niveau des gros modules, c'est à peu près comme cela :

Le "Game Manager" est le module qui appelle tous les autres. On trouve en dessus un module pour :

- gérer le décor (background)

- la camera

-  les entités (c'est a dire les ronrons)

-  les effets spéciaux

- les menus

- les interfaces.

On a aussi ajouté des modules pour :

- les zones

- les fontes

- les entrées (touches claviers)

- traduction

- sons en général

- musiques (pour savoir quelles musiques jouer)

- mini jeux

- les données générales

- la sauvegarde

- les scripts

- les trajectoires.

Chaque module est unique. Pour être sur de cela, j'utilise des "singletons". Tous ces modules ne peuvent être instanciés (le constructeur est privé). Pour y accéder, il faut obligatoirement passer par une fonction "getInstance()" qui s'appelle directement au niveau de la classe comme ceci :

MyManager::getInstance()

Le fonction getInstance a pour but de renvoyer un pointeur vers l'instance unique de l'objet. Si l'objet n'existe pas, elle le crée automatiquement.

Les singletons sont également pratiques car ils peuvent être appelés depuis n'importe quel bout de code (ça ressemble en gros a des variables globales, ce qui est très bien pour des objets uniques).

Tout le code qui est spécifique au PC est à part. Sur le schéma c'est la dernière ligne, en dessous des pointillés. J'ai déjà en tête de faire le portage PS2, donc il faut garder un moteur de jeu aussi indépendant de la plateforme que possible (NOTE : et au final ça marchera bien puisqu'en une semaine le coeur de jeu tournera sur PS2 lors du portage).

Gfx : Sol decor (1 semaine)

Les objets du décor ont donc été fait, il est maintenant temps de faire le sol. Sur mon plan j'ai demandé un sol quasi plat. Les artistes ont cependant pris l'initiative de faire des dénivelés pour donne plus de vie. Ils me proposent plusieurs version avec plus ou moins de dénivelés. L'idée est très bonne on a gardé.

La première version du décor complet :

Ce décor respecte le plan qui est dans le game design, en gardant des zones plates pour les activités. Cependant ici, le centre est trop vallonnée et la zone plate autours du grand arbre n'est pas assez grande.

Le décor sera retouché pour devenir au final celui ci :

Un peu plus plat, mais gardant toujours des dénivelés sympathiques.

Le décor vu sous un autre angle :

Le maillage du décor :

Code : Affichage 3D (1 semaine)

Pour des raisons de commodité de modélisation, les échelles du décor ont été augmentés. Le décor a donc une dimension de 144 unités de large au lieu de 16 et de 50 de profondeur au lieu de 4. Nous adaptons ces unités dans notre code pour garder une cohérence entre le coeur du jeu et l'affichage (plus simple pour debugger ensuite).

Une camera 3D est mise en place dans le moteur 3D. Elle est orientée pour voir le décor d'avant vers arrière, et elle est légèrement incliné vers l'avant. Le sol étant modélisé autours de l'altitude zéro, je place la camera à quelques unités au dessus du sol et ainsi le décor apparaît enfin :

Le décor étant pas encore texturé, le moteur place des textures par défaut.  C'est pas beau, mais quelle joie de voir enfin le décor 3D.

Dans le même temps Eric continue toujours à travailler avec l'affichage 2D, il a maintenant mis en plus un début d'interface (avec des graphs provisoires).

CODE : Altitude du decor (1 semaine)

Pour gérer la collision du ronron avec le sol, j'ai décidé d'utiliser un simple tableau 2D contenant des altitudes (aussi appelé "heightmap"). En effet, le décor est relativement rectangulaire et jamais deux endroits de superposent. On peut donc faire une carte vue du dessus contenant la hauteur du sol. Dans le décor, le sol varie entre l'altitude -1.0 et +4.0. Pour des raisons d'économie de mémoire, je vais utiliser un octet pour stocker une altitude. Un octet pouvant représenter 255 valeurs, la valeur "0" correspondra à -1.0 et la valeur 255 correspondra à l'altitude +4.0.  Entre le deux on a tous les intermédiaires par pas de 0.02 unités (en gros).

Avec un nombre entier, je peux donc stocker une altitude précise.

Au niveau du tableau 2D, tout le décor est représenté par un tableau de 466 cases par 166. Avec ce découpage le tableau des altitudes tiendra dans 75Ko.

Au niveau précision, une altitude est stockée toutes les 0.3 unités. Dans le code, ces valeurs seront interpolées (c'est à dire que si l'on demande l'altitude entre deux points de la grille alors on calcule la valeur intermédiaire entre les deux altitudes les plus proches, selon une ligne droite).

Un convertisseur spécial est écrit pour convertir des polygones exportés (en collada toujours) en grille d'altitude.

Le résultat est le suivant :

Les parties sombres représentent les parties les plus basses. Les parties claires les parties les plus hautes. On voit bien les montagnes dans le fond du décor (en haut de l'image), la zone élevée du centre du décor, les rochers, le lac à droite (noir) et le ponton.

Avec ceci, nous allons donc pouvoir placer nos ronrons 3D sur le sol avec précision.

Un programme rapide sous le GI permet de tester que nos altitudes sont bien stockées et bien relues :

Gfx texturage du decor (1 semaine)

Pendant ce temps, l'artiste qui a terminé la modélisation du décor attaque la création des textures et le mapping.

Le ponton :

Le gros arbre :

Le nid :

voici la texture utilisée :

Des plantes :

Les toilettes :

Les trucs qui flottent sur le lac.

Les rochers dans leur forme finale.

La balançoire :

Avec la texture utilisée :

Et la douche :

Les textures respectent bien les contraintes de tailles et de regroupement d'éléments.

Maintenant l'artiste attaque le texturage du décor.

Comme convenu, les grandes surfaces sont texturés avec des texture d'une seule couleur (aplat). Quelques face verticales sont utilisées pour faire des brins d'herbe et donner un peu de variété. Sur le sol on trouve des variation plus foncés d'herbe et un peu de terre au pied du toboggan. Dans le fond on vois que les reliefs un peu abrupt on été texturés avec une image de talus. Très bonne idée.

Ici on voit une version plus final d'éléments comme les ombres sur le sol (herbe plus foncées), des arbres (tronc 3D, feuillage composées de plusieurs billboards), des herbes et buissons. On voit que les éléments n'ont pas encore la bonne couleurs et la bonne orientation, cela fait un peu étrange pour le moment.

Voici une version plus avancée. La barrière est faite et de nouveaux éléments viennent enrichir le sol. Le chemin a fait son apparition.

Les ombres sur l'herbe.

Une vue d'ensemble :

Et la zone du milieu encore en grand travaux :

La toute première version du lac :

Une version plus avancée :

Et voici d'autres étapes :

La zone des trous

La zone de départ, quasi finie

La première balançoire

Encore une zone de trous

Le gros arbre

Les rochers dans le fond

La seconde balançoire

Le lac, pas encore terminé

Le nouveaux motifs de rochers

La cascade

Les rochers à nouveau, avec un fond style "forêt" pour remplir le fond du décor

Encore le fond et des herbes

La zone de début terminée

La zone du milieu, presque terminée (il manque les fleurs)

La seconde balançoire bien avancée

Vue de loin

Ajout des fleurs :

fleurs de la zone du milieu

Le fleurs de la zone de droite, on ajoutera par la suite un massif de fleur au sol pour faire plus riche

Et voila le décor terminé. Il fait 39410 faces.

Voici quelques image de décor et la même version en montrant les polygones. On peut ainsi voir comment son placés les billboard et que ceux ci utilisent beaucoup la transparence pour se faire oublier et laisser place a de beaux dessins.

On voit ici les massifs de fleurs au sol

Le lac et la plage terminée

Le décor respecte bien les contraintes du technical design (40 000 triangles au lieu de 80 000, bravo pour cette prouesse).

Code : Fontes (2 jours)

Le Game Incubator gère tout seul les fonte vectoriel standard (c'est bien le GI non ? :) ), mais pour faciliter le portage, je préfère utiliser des fonte graphiques. Le principe est simple, on prend une texture, on met toutes les lettres dessus et ensuite on utilise ça dans le jeu. C'est cependant long et laborieux à faire, un petit outil est nécessaire.

J'ai trouvé sur le net un outil freeware super qui fait exactement ce que j'attendais. Il se nome "Bitmap Font generator"

A partir d'une fonte TTF (image 1), il est capable de générer une image graphique avec toutes les lettres (image 2) ainsi qu'un fichier .txt qui contient le code de la lettre et ses coordonnées dans l'image. Le code pour relire ça est assez simple a faire, donc rapidement j'ai pu avoir du code au point pour afficher du texte dans un petit exemple Game Incubator (image 3). Cette méthode fonctionnera sur PC et PS2.

Code : Affichage 3D (1 semaine)

Maintenant que le décor est terminé, c'est le moment de l'afficher. Un gros objet est exporté et voici ce que ça donne :

C'est pas mal. On remarque cependant pas mal de problème de transparence. Cela provient des faces qui ne sont pas affichées dans le bon ordre. Pour remédier à cela, le convertisseur Collada->GI va trier les face du fond vers l'avant et aussi exporter les objets composant le décor séparément. Le convertisseur crée un fichier "scene.txt" qui contient un liste triée de objets (du fond vers le devant), en commençant par les objets sans transparence (pour déterminer cela, les textures sont chargées et les pixels sont testés pour trouver de la transparence).

Ci dessous le début du fichier "scene.txt" :

Rideau_foret4 ; 51.676762 ; 121.540298 ; Sizexy ; 50.000000 ; 0.763256
Rideau_foret5 ; 50.310276 ; 73.639351 ; Sizexy ; 50.000000 ; 0.763256
Sol ; 50.154549 ; 70.885956 ; Sizexy ; 154.135742 ; 50.372097
Rideau_foret ; 50.147469 ; 25.000000 ; Sizexy ; 50.000000 ; 0.518333
TileTronc7_O ; 45.843136 ; 129.751205 ; Sizexy ; 0.343292 ; 0.329796
___Default3 ; 45.450100 ; 8.828406 ; Sizexy ; 1.705414 ; 1.528851
TileTronc8_O ; 45.110771 ; 126.189919 ; Sizexy ; 0.375305 ; 0.399055
TileTronc6_O ; 45.102455 ; 134.155853 ; Sizexy ; 0.394547 ; 0.377430
roche_chute ; 42.126575 ; 133.777512 ; Sizexy ; 2.729858 ; 1.881969
CactusPetit1_O ; 40.868252 ; 35.853333 ; Sizexy ; 0.824348 ; 0.788212
Trous ; 40.000000 ; 49.999996 ; Sizexy ; 5.000595 ; 5.000000
polySurface1099 ; 39.551128 ; 50.023064 ; Sizexy ; 4.007656 ; 2.883377
CactusPetits_O ; 38.576679 ; 101.963562 ; Sizexy ; 0.824348 ; 0.788212
Trous2 ; 37.500000 ; 82.500000 ; Sizexy ; 5.000603 ; 5.000000
Plante_O ; 37.213943 ; 60.606060 ; Sizexy ; 0.433205 ; 0.241840
BigRock_O ; 37.205605 ; 67.820908 ; Sizexy ; 4.355301 ; 3.890522
Material__260 ; 37.039890 ; 80.975761 ; Sizexy ; 0.809982 ; 0.869202
Material__261 ; 36.975868 ; 83.454994 ; Sizexy ; 1.003296 ; 0.566589
Cactus2_O ; 36.457176 ; 59.183624 ; Sizexy ; 3.158829 ; 2.480415
Material__262 ; 34.468197 ; 84.390350 ; Sizexy ; 0.376152 ; 0.311684
Plantes3_O ; 34.160847 ; 59.864384 ; Sizexy ; 3.214912 ; 0.509739
Plante1_O ; 31.649660 ; 43.724674 ; Sizexy ; 0.759987 ; 0.395037
___Default2 ; 30.865541 ; 2.180253 ; Sizexy ; 1.688677 ; 1.622765
polySurface3735 ; 30.053671 ; 11.249403 ; Sizexy ; 2.501195 ; 2.553671
Cailloux2 ; 29.218052 ; 23.930183 ; Sizexy ; 1.705414 ; 1.528849
Ponton ; 28.247255 ; 103.964241 ; Sizexy ; 4.885300 ; 2.945959
TileTronc5_O ; 26.758705 ; 134.171906 ; Sizexy ; 0.394547 ; 0.377428
TileTronc3_O ; 24.314482 ; 134.573776 ; Sizexy ; 0.357208 ; 0.314034
Cailloux1 ; 21.973316 ; 6.472112 ; Sizexy ; 1.196195 ; 1.072350
Swing ; 21.158100 ; 31.711605 ; Sizexy ; 6.833763 ; 2.016342
TileTronc2_O ; 20.461302 ; 140.364807 ; Sizexy ; 0.357208 ; 0.314034
Massif_O ; 19.251987 ; 63.053471 ; Sizexy ; 2.691643 ; 3.395579
TileTronc_O ; 18.666779 ; 141.360840 ; Sizexy ; 0.394547 ; 0.377428
roche_chute1 ; 16.966976 ; 133.502289 ; Sizexy ; 1.419785 ; 1.270615 ...

Chaque ligne représente un objet, avec son nom, la coordonnées max de sa profondeur (son Y) et sa position en X. Je sauve aussi sa taille en x et y (sera utile pour déterminer si l'objet doit être afficher ou pas suivant la position de la camera pour la version PS2).

Le décor est composé de 720 objets.

Avec cette technique d'afficher les objets du fond vers l'avant (et les objets sans transparence avant ceux qui en ont), on limite le bug de transparence (les cartes graphiques actuelles ne savent pas gérer la transparence). On le verra dans les screenshots qui suivront.

Gfx : Modelisation persos (2 semaines)

La tache suivant pour l'artiste est la modélisation des créatures.

Tout d'abord la forme des personnages est faite :

On retrouve ici les contraintes du technical design, qui sont des poils, des cheveux, et des gros nez pour certains. Le nombre de polygone est aussi respecté.

Et voici les textures qui ont servies a mapper la créature :

La bouche et les yeux sont des textures à part, pour permettre l'animation faciale (décrite plus loin).

La texture de se personnage est plus grande pour avoir du détail sur le ventre.

Comme on a vu plus haut, la bouche et les yeux sont dans des textures à part. Cela nous permettra de changer a la volée les texture pour créer des animations faciales. Dans la pratique on a donc 4 matériaux dans maya : corps, bouche, oeil droit et oeil gauche.

L'étape d'après est la création du squelette. Pour chaque créature, on doit définir un ensemble d'os reliés entre eux (on appelle ça une hiérarchie). Ce squelette est ensuite relié à la "peau" (skin). L'animation du personnage se fait au niveau du squelette (c'est plus simple d'animer 40 points que 600).

Voici le squelette de la créature bleue :

Le squelette sert donc à animer le personnage mais aussi ses cheveux.

Une fois que le squelette est fait pour la position "au repos" (bind pose), l'artiste fait le lien entre ce squelette et la peau. Chaque point (en bleu ci dessus) recevra une affectation sur les deux os les plus proches, avec un coefficient entre 1.0f et 0.0f pour chaque os. On appelle ça des influences. Ca permet de réduire le volume des données d'animation (on anime que le squelette et pas les point de la peau), mais ça permets aussi d'avoir un bon comportement des points au niveau des jointures.

Et voici la petite famille au final :

Du bon travail, comme d'habitude.

Code : Menus et Interfaces (1 semaine)

Pour les menus et interfaces, Eric a défini un objet "Widget" simple (mot qu'on peut traduire par "machin de base de l'interface graphique") qui est défini par une taille rectangulaire et une position. A ce Widget on associe une "callback" qui est une fonction qui est appelée lorsque le bouton est cliqué. Globalement ça nous suffit pour nos menus et interfaces. Chaque page de menu et chaque interface (principale et mini jeux) à sa propre classe "page" qui est dérivé d'une classe mère et possède les classiques "init", "update" et "display". Le menu manager se charge d'appeler la mise à jour de la page de menu courante, tandis que l'interface manager se charge de ...  je pense que vous avez deviné.

Voici la tout première ébauche de menu :

Pour l'interface, le cahier des charges demande aussi à ce que le joueur puisse cliquer directement sur des zones écrans. Il faut donc convertir des boites englobantes 3D en zone écran 2D. Le résultat de ce calcul est en général envoyé directement à la carte graphique , il faut donc recoder la formule dans le camera manager pour pouvoir facilement projeter des points 3D sur l'écran.

Ca donne le code suivant (conversion d'une coord 3D en coord 2D écran) :

 

// -----------------------------------------------------------------
// Name : ConvertWorld3DToScreenPos
// -----------------------------------------------------------------
f2d cCameraManager::ConvertWorld3DToScreenPos(f3d pos)
{
f3d newpos;
f2d screenpos;
// Translate point back into camera system
pos -= f3d(mPosition.x, mPosition.y, mAltitude);
// Rotate point into camera system
float angle;
angle = DEGTORAD(mTilt);
newpos.y = pos.y * cosf(angle) - pos.z * sinf(angle);
newpos.z = pos.y * sinf(angle) + pos.z * cosf(angle);
newpos.x = pos.x;
// If Z is depth :
// x’ = dx * x / z
// y’ = dy * y / z
// d = cot (anglefov)
// dx = (d / (width/height) + 1) * viewportWidth/2
// dy = (d + 1) * viewportHeight/2
float d;
float dx;
float dy;
d = (float) 1.0/tan((GI::GI_PI/4.0f));
dx = ( ( d / ( 800.0f / 600.0f ) ) + 1 ) * (SCREENX/2); // GI use these values
dy = ( d + 1 ) * (SCREENY/2);
float mynear;
float myfar;
float DepthCoef;
mynear=1.0f;
myfar=5000.0f;
DepthCoef = ( mynear * myfar ) / ( myfar - mynear );
screenpos.x = newpos.x * dx / (newpos.y * DepthCoef*0.9f); // ugly coef
screenpos.y = newpos.z * dy / (newpos.y * DepthCoef*0.8f);
screenpos.x += SCREENX/2;
screenpos.y += SCREENY/2;
screenpos.y = SCREENY - screenpos.y;
return screenpos;
}

 

Les "zones 2D" sont définies par un centre 3D, une largeur et une hauteur. C'est un rectangle vertical qui est projeté sur l'écran. Le résultat donne :

Vu qu'il y a une trentaine de zones bien définies, les coordonnées sont directement tapées dans le programme. Ci dessous la zone ou chaque rocher peut être cliqué pour monter au sommet. On peut également cliquer sur un ronron pour le sélectionner.

Pour vérifier que la formule est assez précise, j'affiche un curseur 3D de test sous la souris. Je le dessine deux fois, en noir c'est le curseur affiché par le moteur Game Incubator (je lui donne les coordonnées 3D) et en blanc, c'est le curseur dont j'ai calculé les coordonnées écran avec la fonction ci dessus. C'est assez proche, cela me suffit.

Code : ACTIONS et Ordres (4 semaines)

Dans le code la créature est une machine à état. On a appelé les états des "actions". Les actions possibles sont : attendre, déplacer, manger, boire, jouer au toboggan, ...

La classe action possède les fonction usuelles : init, update, display, destroy. Chaque action a son propre bout de code, cela permet de pouvoir mettre en scène certaines actions (changer camera, forcer le déplacement de la créature, déclencher des sons à certains moments). Pour dispatcher suivant le type d'action, on a mis des gros switch. Le nombre d'actions étant connu et pas trop important (23 actions)  cela convient très  bien.

Dans l'image au dessous, on peut voir l'état des 5 créatures (la première attend, les trois suivantes font une vilaine grimace, ce qui arrive quand elle attendent et qu'elle sont pas encore éduquées, la dernière fait aussi une bêtise car elle se sauve). Dans cette première version, le corps des actions était vide et attendais simplement un certain nombre de secondes en affichant un texte. La mécanique globale est maintenant en place. La mise en scène s'est fait plus tard.

Voici un exemple d'action scénarisée :

Lorsque la créature sélection l'action "jouer_balancoire", la camera change (elle devient fixe) et le code de gestion de la balançoire est appelé à chaque tour de boucle. La balançoire est gérée est un petit code physique qui prend en compte la l'angle, la vitesse, la perte d'énergie et offre la possibilité au joueur de pousser sa créature pour qu'elle aille plus haut.

Pour gérer la créature nous avons aussi mis en place un système d'ordre. La créature peut empiler quelques ordres comme par exemple "va la" et ensuite "jouer avec ça". Quand une action est terminée, la créature regarde si elle a des ordres en attente et les exécute. Ca permet de gérer facilement des combinaisons d'actions "déplacement + action".

PNJ

Sur le plateau de jeu, il y a 5 créatures non jouables qui se baladent. On les appelle des "PNJ" (Personnages Non Jouables).

Les PNJ reçoivent des ordres, ce sont donc des créatures comme celle du joueur (donc c'est strictement la même classe). La seule différence c'est que c'est un script qui envoie les ordres. Les scripts ont été établis comme défini dans le game design. On a fait un petit langage composé d'actions simples. Chaque script est composé d'une succession d'ordre associée avec un temps d'attente et le tout est stoqué dans un fichier .txt. Voici par exemple un script.

30.0 wait
10.0 play_slide_big
15.0 wait
10.0 play_slide_big
05.0 wait
06.0 goto 51.4 36.1 (holes)
04.0 goto 49.7 40.0 (jump)
10.0 wait
12.0 goto 51.5 21.5 (slide)

La créature va attendre pendant 30 secondes, puis va recevoir l'ordre "play big slide" (on sait que la créature n'est pas loin du toboggan 2), ensuite elle attends, elle refait un tour de toboggan, elle attends, et elle se déplace aux coordonnées 51 36, etc, etc.

Les enfants aiment bien les choses récurrentes car ils s'habituent et ça devient familier. Ces créatures font toujours le même trajet et jouent toujours aux même activité. L'enfant peut dire "ah tiens voila la créature du toboggan".

Eric a mis en place un système de queue lorsque plusieurs créature veulent accéder à la même activité. Si tel est le cas, alors les créatures attendent que l'activité soit libre. Elle sont bien élevées.

Gfx : AnimationS (7 semaines)

Julien est très doué en animation, cette partie la c'est donc vraiment bien passé. Rares ont été les modifications. Il a su donner vie aux créatures et leur donner un coté attachant et drôle.

ICI vous pouvez voir une petite vidéo ou on voit les personnages animés.

Chaque créature a 37 animations.

Comme je m'y connais pas trop en animation, j'ai posé quelques questions à Benoît.

Comment l'animation du squelette est elle faite ?

L'animation du squelette passe par un système simple de cinématique inverse (IK) pour les pattes et par rotation (cinématique avant) pour les bras, la colonne vertébrale, la tête et le oreilles.

La cinématique inverse est un procédé qui permets de déplace une extrémité de squelette et le logiciel calcul lui même le déplacement des os intermédiaires.

La technique d'animation utilisée est un mixe de "pose to pose" et "straight ahead", qui consiste dans un premier temps à placer les clés principales pour définir les mouvement et ensuite déstructurer un peu le travail trop rigide du "pose to pose" en animant plus librement entre ces quelques clés principales.

Quels sont les outils et fonctions utilisés ?

Maya a été utilisé pour les animations.

La cinématique inverse est utilisée pour les jambes afin de mieux gérer le contact avec le sol. Techniquement les choses sont restés très simple pour se concentrer sur le travail artistique d'animation. Le niveau de complexité des créatures n'a pas demandé de développer un système de rigging complexe ou de faire appel à des plugins ou standalone comme motion builder ou final rig.

Le "rigging" est la fabrication d'un squelette détaillé et tous les contrôleurs qui vont permettre de l'animer. Dans cette étape sont crées tous tes manipulateurs, les contraintes pour savoir comment ils réagissent, et tous les trucs qui aident.

Les personnages ont ils des animations communes ou tout a été refait pour chaque perso ?

Dans le carde de ce genre de production ou l'équipe est restreinte il faut optimiser les temps de production et la réutilisation d'animation et de pause a permis de gagner du temps.

Cela à été facilité par le fait que 4 créature sur 5 sont des quadrupèdes; et malgré leur grande différences de démarche certaines animation ou pause ont pues être réutilisées et modifiées pour s'adapter à la créature en question. Les rigs des créatures ont été standardisés ( structure, nom des éléments etc ) ce qui a permis de facilité l'échange de données d'animation.

Y a t il des contraintes sur les os ? (qui empêche les positions improbables) et y a t il des contraintes physiques mise en place ? (qui font par exemple bouger les oreilles ou cheveux automatiquement)

A part l'IK il n'y a aucune contraintes sur les rigs. Les mouvements automatiques ne sont pas toujours aisés à mettre en place et leur principal problème réside dans leur avantage; ils sont automatiques donc produisent des résultats mécanique. L'animation "à la main" permet un meilleur contrôle, surtout dans le cas d'animations qui ont pour but d'amuser et d'avoir un petit coté cartoon.

Les personnage sont modélisé sur place (il n'avancent pas), est ce difficile pour faire une animation de course par exemple ?

Ca peut poser problème aux débutants, mais avec l'expérience ça devient naturel et on n'y fait plus attention. Une marche par exemple se décompose en quelque pauses clés; une fois ces pauses placées, on obtient déjà une quasi illusion de marche, même si le personnage ne se déplace pas dans l'espace.

Code : Affichage des persos (1 semaine)

Tout au début du projet, j'ai travaillé sur le convertisseur Collada -> Game Incubator. L'outil en ligne de commande sauvegarde les objets 3D ainsi que l'animation contenue dans le fichier collada. Ayant déjà bien souffert et testé sur des modèles complexes, j'ai eu rapidement des résultats sympathiques :

Mais bon il a fallu encore débugger un peu car le fichier collada exporté d'une vraie animation contenait bien plus d'information que mes fichiers de tests.

Au final, presque toutes les animations passaient très bien. Ici l'anim du toboggan (où tout le mouvement a été fait en animation).

La créature en train de nager. (pour déterminer que la créature doit nager, on combine deux informations : Elle se trouve sur une zone "eau" et la profondeur du sol est inférieur à un certain niveau. )

Cependant la vie n'étant pas toujours rose, j'avais toujours quelques problèmes. Le premier était sur les extrémités, surtout les bras de la créature bleue. Sur l'image en dessous, la créature est censé se gratter les fesses. On voit nettement que la main est loin de son derrière.

Il y avait aussi un second bug, le cochon avait quelques animation de travers, comme la marche qu'on voit ci dessous.

Bien plus tard dans le projet, j'ai corrigé ces deux bugs en m'y remettant profondément. Le premier était du à un problème de matrices. Dans le format collada, les matrices du squelette sont stockées deux fois, j'avais pris les mauvaises.

Le second bug venait des données sources. Dans le fichier maya, l'os au sommet de la hiérarchie avait un angle non nul (l'os "root", celui qui est en 0,0,0 qui sert de référence). Maya ne prends pas en compte l'orientation de cet os alors que dans mon convertisseur je le fais. Donc après modif et réexportation, le cochon était redevenu droit (6 animations étaient concernées).

Ouf.

Code : Animations faciales (1 semaine)

Dans la partie modélisation, nous avons vu que les persos avaient leur textures de bouches et d'yeux à part. J'ai modifié le GI pour pouvoir changer en temps réel des textures aux modèles 3D. Ici par exemple, le corps a une texture différente :

(le corps est en 2 parties pour respecter les contraintes sur le nombres d'os par matériau, approximativement 22).

Maintenant il faut séquencer ces changements de textures pour donner des expressions de visages sympa suivant les animations. Pour cela il faut coordonner ses changements par rapport aux anims. On pourrait le faire à la main, mais pour 180 animations, ça risque d'être long et fastidieux. Il a donc été prévu de faire un petit outil qui permette d'éditer facilement les animations faciales. L'outil est simple puisqu'il doit afficher le modèle 3D animé, et les informations sur les textures d'yeux et de la bouche. C'est Eric qui a crée l'outil (avec des spécifications définies à l'avance). L'outil a été fait avec le Game Incubator.

Le résultat c'est cela :

En haut on a le nom de l'animation, et le numéro de la créature. En bas on a trois timeline ("barre de temps") qui permettent de changer les textures. La timeline défile a raison de 10 clés par secondes, on a pas besoin de plus. Grâce aux touche de curseur on peut faire défiler la timeline (droite gauche), choisir le canal oeil droit, oeil gauche, bouche(haut bas) et avec les touches 1 à 9, on change la texture.

Avec des textures de tests, on voit bien comment cela fonctionne :

Ce mutant n'est pas disponible dans le jeu heureusement.

L'outil a été donné à l'artiste qui a fait toutes les textures ainsi que les animations faciales.

Voir l'éditeur en action : VIDEO (codec divx nécessaire)

Quand j'ai vu les personnages animés avec les expressions faciales définitives, ça m'a beaucoup amusé. C'est le genre de moment où on reprend bien confiance et on se dit "on tient un bon jeu la".

CODE : Textures

Au niveau des textures, j'utilise un gestionnaire bas niveau auquel toutes les couches demandent des textures. Lorsque celle ci est déjà chargée, on renvoi juste un pointeur dessus sinon on la charge. ça évite les textures en double. Toutes les textures sont effacées en sortant du programme.

Format :

La majorité des textures sont au format DDS. La compression DXT utilisée dans le format DDS est assez efficace sur de grandes textures. Le grand avantage, c'est que ce format est reconnu et utilisé dans la carte graphique directement sous sa forme compressée. Le DXT1 permets de réduire la taille par 6 (mais ne supporte pas de transparence) alors que le DXT5 divise par 3 la taille mais lui supporte l'alpha. La compression est simple et fonctionne par blocs de 16 pixels (4x4) : Pour ces pixels, l'algorithme de compression détermine les deux meilleurs couleurs, et les pixels sont ensuite codées sur 2 bits (ce qui fait 4 possibilités de couleurs, les deux autres couleurs sont les couleurs intermédiaires entre les 2 couleurs stockées).

Le DDS fait donc des petits "pâtés", il faut donc l'utiliser sur des textures larges ayant des grandes zones de couleurs unies.

Pour les textures de menus et d'interfaces, le DDS n'est pas possible car trop de perte. J'ai utilisé un format non compressé en 32bits. Pour stocker les textures, j'utilise le format PNG, c'est un excellent format de stockage sans perte allié a une bonne compression (le GameIncubator reconnaît le png, le tga, le bmp et le jpg).

Il existe un plugin DDS pour photoshop fourni par Nvidia. Il faut néanmoins faire attention car si votre taille de texture n'est pas un multiple de 2, vous ne pourrez pas sauvegarder en DDS, et le plugin ne vous donnera pas la cause (on croit alors que le plugin est buggé jusqu'a l'os).

Le mipmapping :

Les textures d'herbes ont posé un problèmes lorsqu'elle étaient vu de loin. En effet la texture étant alors petite à l'écran, cela crée un effet de scintillement désagréable des que la camera bouge. Pour cela il a fallu mettre en marche le mipmapping dans le Game Incubator. Le mipmapping permets de choisir en temps réel la meilleur texture à afficher suivant sa taille à l'écran. Dans le DDS, on peut stocker plusieurs versions de différentes taille de la même texture (en général, chaque texture est deux fois plus petite que la précédente).

Si une herbe est loin, la carte choisie la texture la plus petite pour afficher l'objet, ainsi on a plus l'effet de scintillement.

Filtre :

Par défaut le Game Incubator n'avait pas le filtre "bilinéaire" activé sur les textures. Ce filtre sert a calculer des couleurs intermédiaires entre les pixels quand une textures est zoomées dans un sens ou dans l'autre.

Sans filtre, voici ce que donne une texture :

On voit les pixels, c'est pas très beau.

La même texture, zoomée avec le filtre :

Les pixels sont interpolés, on ne les voit plus.

Code : Animations decor (1 semaine)

Animation de textures eau :

Pour créer un effet d'eau, il faut faire une grande couche d'eau transparente. En dessous, on voit des motifs (fond du lac), ce qui donne un petit effet sympa.

Pour animer l'eau, on va déplacer les coordonnées de textures (donc les points 3D ne bougent pas). Pour faire cela, j'ai ajouté deux paramètre "offset u" et "offset v" dans le vertex shader qui affiche les objets statiques (Le Game Incubator gère facilement les vertex shaders, suffit de modifier les petits fichiers contenant le programme appliqué aux vertices et hop). Ainsi le lac, les marres, la cascade donnent l'impression de bouger. Ces objets 3D sont bien identifiés dans le code (par leur nom) donc un mouvement particulier peut être assigné à chacun d'eux (plus rapide pour la cascade, lent pour les petites marres).

Papillons et poissons :

Les papillons et les poissons suivent une trajectoire définie. La trajectoire est définie par un ensemble de point et de vitesses à chacun de ses points. Si on affiche le point principal de cette trajectoire on le verrait décrire une série de lignes brisées en changeant de vitesse à chaque début de segment. J'ai fait un manager de trajectoire pour cela. On lui donne un temps et il renvoi une position. Il peut dire aussi si la fin de la trajectoire est atteinte.

Si les poissons et les papillons suivaient cette trajectoire de manière stricte, ça serait pas beau car trop "mécanique". Donc pour rendre le truc pour naturel, on va rendre autonome ces charmantes bestioles. Les poissons ont reçu une vitesse maximum pour tourner, il font ainsi de grand virages. Ils ont aussi une vitesse et une accélération. Quand ils sont trop près du point de référence de la trajectoire, ils ralentissent et quand ils sont trop loin, ils accélèrent. Les papillons quand à eux sont plus vifs, donc ils tournent instantanément. Ils ont le même système d'accélération et de ralentissement que les poissons, en un peu plus nerveux. Comme les papillons volent en groupe et qu'ils suivent tous le même point guide, chaque papillon reçoit une valeur aléatoire de décalage par rapport au point guide. Ce décalage est retiré au sort toutes les 3 secondes. Ainsi les papillons donnent l'impression de voler dans tous les sens de manière pas très organisée, ce qui fait naturel.

Ce système de trajectoires précalculées est aussi utilisé pour forcer quelques mouvements des ronrons. On le retrouve pour forcer le ronron à aller sous la douche ou dans les toilettes, et pour le faire dévaler la cascade. Dans ces cas, le ronrons suit parfaitement le point guide, ce qui ne se remarque pas trop (ces mouvements sont très rectilignes).

Particules, brume eau / balançoire / Bulles :

J'ai mis en place un petit système de particules avec des sprites 3D (images 2D placées dans le monde 3D, donc la taille dépends de la distance avec la camera). On a un émetteur de particule qui émet des particules qui auront une vitesse, une variation de taille, une variation de transparence et une durée de vie déterminée (et tirée au hasard entre des bornes).

Un premier essaie donne des résultats sympas :

On voit bien ici l'image 2D utilisée par chaque particule. En en mettant un certain nombre on obtient une sorte de nuage de vapeur.

J'ai mis ça en place pour la cascade et la douche :

Ensuite je l'ai aussi fait pour les spaghettis à bulles et les lumières de la balançoire (des petites étoiles lumineuses sont émises quand on s'en sert) :

Dans le décor, il y a aussi quelques autres objets animés. La balançoire est animé avec une simple rotation autours de l'axe x. Les toilettes et la douches eux, possèdent un squelette et l'animation a été faite par l'artiste.

GFX : Interface et menus (2 semaines)

La dernière tache artistique a été la création des éléments de menus et d'interfaces. Eric et moi avions déjà défini des éléments, il fallait maintenant les remplacer par les éléments définitifs.

Benoît s'est occupé de cette tache et il a opté pour un style arrondi et enfantin. Les couleurs bleue et rose des éléments se sont parfaitement intégrés.

Voici quelques pages :

La page d'aide interactive. Deux petits cadres dont l'un contient une image et l'autre l'explication. L'aide interactive apparaît si l'enfants clique sur le bouton "Aide" lorsque celui ci clignote.

Voici les menus (en espagnol, c'est fun). La fonte définitive est bien sympa aussi.

Page de résultat des mini jeux. La créature a gagné le premier prix ici. Belle coupe et étoiles animées dans le fond.

La page des statistiques de la créature. On a refait plusieurs fois ces éléments pour trouver quelque chose de simples et compréhensible. Au départ j'avais demandé que les coupe et médailles de chaque niveau de difficulté soient diffèrents (une coupe en bois, une en herbe, une en sable). Benoît a interprété ça en or/argent/bronze et au final c'était plus trop compréhensible. On a donc tout simplifié ce qui rend les choses plus lisibles.

On voit les 5 jauges qui sont le coeur du jeu. Les icônes à coté sont clairs et lorsqu'un enfant se balade dans le jeu, il comprends assez rapidement à quoi elle font référence. Ici notre créature a faim et est assez sale. C'est bientôt l'heure de la douche ou de prendre un bain.

Sur la droite, les étoiles représentent les aptitudes de la créature. Ici elle est très sage et assez bonne en course. Elle est pas bonne en saut et natation. Benoît a choisi d'utiliser des icônes représentant des formes humaines. Au début j'avais un doute mais au final ça passe bien.

L'interface "in game" complète.

L'ensemble des icônes réunis sur une petite page d'explication.

LOGO

Pour le logo, Benoît m'avais préparé deux ou trois ébauches de logos assez fouillés et travaillés. Il a aussi intégré un logo qu'avait fait sa compagne Sophie (image ci dessus). Au final ce dernier logo s'est révélé être plus efficace et on l'a gardé tel quel.

Localisation (1 semaine)

Le jeu est prévu pour fonctionner en 5 langues différentes : Français, Anglais, Allemand, Italien, Espagnol. En gros ça correspond aux gros marché du jeu vidéo. Il y a un marché supplémentaire qui est le japon, mais bon, je m'en occuperai plus tard.

Donc à l'intérieur du jeu, chaque phrase est numéroté et pour obtenir une chaîne de caractère, on la demande au "localisation manager" en lui passant le numéro de la chaîne.

Pour des raisons de simplicité, toutes les langues sont stockées dans le même fichiers. Le fichier langage est un fichier texte, qui pour chaque ligne contient les 5 traductions, séparées par des point virgules. C'est un caractère qu'on utilise pas souvent donc c'est parfait.

Voici le début du fichier :

English;Français;Español;Italiano;Deutsch;Commentaires
Menu;Menu;Inicio;Menu;Menü;en tête menu principal
New game;Nouvelle partie;Nueva partida;Nuova partita;Neues Spiel;menu bouton nouvelle partie
Load game;Charger une partie;Cargar una partida;Carica la partita;Spiel laden;menu bouton charger partie
Options;Options;Opciones;Opzioni;Optionen;menu bouton options
Back;Retour;Volver;Indietro;Zurück;menu bouton retour
...

Le localisation manager charge tout le fichier langage et ensuite on lui dit dans quel langue il doit fonctionner. Si on défini par exemple l'Italien et qu'on lui demande la chaîne 3 :

cLocalisationManager::getInstance()->GetText(3);

Il renverra un pointeur sur la chaîne "Carica la partita"

L'avantage du système avec les points virgules, c'est que c'est un format reconnu par excel (format .csv) et donc pour éditer les textes et les faire traduire par des gens extérieurs, c'est plus sympa de leur envoyer un fichier lisible par un tableur.

Sons et musiques (2 semaines)

Sons

Avant de passer commande des sons, nous avions défini une liste de 25 sons. Ca représentait les sons indispensables et ça faisait une quantité de sons raisonnable (comprendre "raisonnablement coûteux").

Sylvain nous a donc fait ces sons. Ils étaient vraiment bons et donnaient beaucoup de vie au jeu. Au final, Sylvain en a fait un peu plus et je lui en ai commandé une dizaine supplémentaire. Le nombre de sons dans le jeu est de 58 maintenant.

Le son est un élément très important d'un jeu, c'est ce qui donne une bonne moitié de la vie à mon avis. Le jeu a vraiment pris toute sa dimension le jour où on a commencé à le sonoriser.

Pour les "voix" des ronrons Sylvain a enregistré sa propre voix et a ajouté un "pitch shift". Voici ce que ça donne : (cliquer sur le nom pour écouter)

Ronron fait du toboggan

Ronron danse

 

Musique

Pour la musique, je voulais absolument quelque chose de doux et d'orchestral. J'ai pensé à Olivier car j'avais beaucoup aimé son travail sur Obscure et sur Rally Championsheep (les musiques peuvent être écoutée sur son site : http://www.olivierderiviere.com/ ).

Le projet lui a plu et il a donc accepté de bosser sur le projet. En 5 jours il a composé plus de 20 min de musiques sur 10 morceaux dans un style qui colle parfaitement au jeu. Les divers musiques sont douce et surprenantes. En fait dans le monde des ronrons, chaque personne à mis sa propre touche, c'est comme ça que j'aime bien travailler. On final cette somme de talent donne quelque chose de vraiment sympa. Une fois de plus le résultat a été au dessus de mes espérances.

Voici deux morceaux du monde des ronrons :

Le monde des ronrons - Musique 1

Le monde des ronrons - Musique 2

Devant la multitudes des morceaux, on a mis en place une ambiance dynamique. Il y a un thème simple qui revient régulièrement et entre ces passages, des musiques plus marquées sont jouées. Ainsi le jeu n'est pas saturé par la musique, mais en plus l'ambiance souligne ce qu'il se passe. Ainsi les musiques ne seront pas les même si le joueur a des créature plutôt jeunes ou alors adultes. De même l'ambiance ne sera pas la même si certaines créatures sont en mauvaise santé ou malades.

Olivier a utilisé la banque de son "Vienna Symphony Library" qui permet d'atteindre un résultat aussi réaliste.

Au final je suis très satisfait des musiques et Olivier est satisfait du jeu. Ca lui a permis de faire un petit break car d'habitude il compose plutôt pour des jeux d'un style très différent (Alone in the dark 5, Obscure).

FINI

A ce stade, le jeu était donc quasi terminé. Quand on approche de la fin ça devient agréable. Le jeu prends toute sa grandeur quand on commence à faire les finitions. C'est ce que vous verrez dans le chapitre suivant.

Page suivante : Debug et Tests

Retour Sommaire