samedi 20 juillet 2013

Flop­Flop Jump : le making-­of

L'article qui suit a pour but de vous permettre d'appréhender et de suivre (à postériori) le développement du "petit" projet de jeu mobile (Android et bientôt iOS) "Flop­Flop Jump" réalisé en solo de A à Z.

Pour rappel, le jeu est téléchargeable GRATUITEMENT ici : https://play.google.com/store/apps/details?id=air.OpiumBleu.FlopFlopJump

Ce "post­­mortem" respecte l'ordre chronologique du projet et aborde l'ensemble des étapes de développement (création, conception, programmation, vente, …).


Etant en plein développement d'un jeu "conséquent" (sortie prévue pour octobre 2013) qui fera ici l'objet d'une série d'articles, j'ai souhaité faire une pause en développant rapidement un projet nettement plus modeste/simple. Mon choix s'est porté sur un "doodle jump like"… Si vous ne connaissez pas le jeu d'origine, je vous conseille vivement de le charger (gratuitement) sur votre téléphone pour comprendre la suite de cet article :


Ce jeu ­ mainte fois copié ­ répond parfaitement à ce que je recherche :
- graphismes et animations peu nombreux
- programmation "simple"
- pas de niveaux à créer (le décor se crée automatiquement !)
- concept de jeu apprécié sur Google Play

Un tel jeu, peu consommateur de ressources, se prête aussi très bien à un développement en Flash/Air (qui est la technologie que j'utilise majoritairement pour mes applications mobiles et qui n'est pas réputée pour sa vitesse…). A priori le candidat idéal pour un petit projet de quelques jours… Je m'y met courant mai (2013).

Sans vouloir brûler les étapes, le développement fut en fait bien plus complexe et plus long que prévu… comme toujours serai­-je tenté de dire…

Contrairement à mes précédents projets solo, j'ai décidé de commencer par la programmation puis seulement ensuite penser au design, aux graphismes, etc… J'avais alors dans l'idée que la programmation ne me prendrait qu'une semaine…

Fort d'une certaine expérience dans le domaine, j'ai décidé d'utiliser les mêmes technologies et bibliothèques que mes projets précédents :
- Adobe Flash CS6, comme IDE (environnement de développement)
- Action Script 3 (AS3) comme langage de programmation
- Adobe AIR 3.x comme "technologie" d'exécution sur mobiles
- ND2D comme bibliothèque graphique (je ne suis pas fan de Starling)
- Photoshop (+Flash) comme logiciel de dessin

Evidemment un tel projet peut être réalisé avec des équivalent gratuits (voir open source) : FlashDevelop, Gimp, …

Développement

Il est préférable d'avoir de bonnes notions de Flash, d'ActionScript 3 (sans être un expert) et de la bibliothèque ND2D pour y comprendre quelque chose… Si vous n'avez jamais utilisé cette dernière bibliothèque graphique, je vous conseille la lecture de ce lien : nd2d endless runner.

La première étape fut de créer l'arborescence du projet, en restant fidèle au concept de POO (programmation orientée objet) et à MA vision des choses. Le projet contient donc une classe Application (ou main si vous préférez) qui étend la classe Sprite qui contient (graphiquement parlant) le jeu en lui-même, les menus, … bref TOUT. La classe Jeu étend la classe Scene2D de ND2D (une occurrence de World2D est créée dans la classe Application). Puis dans Jeu doivent venir se greffer les différents éléments du jeu (personnage, plateformes, fond, ennemis, …) sous forme d'occurrence de classes. Mon autre jeu en cours utilise aussi ND2D mais est organisé légèrement différemment; j'ai cherché ici à simplifier…

Par défaut j'ai travaillé sur un projet en 320 pixels (de large) sur 480 pixels (de haut) à 30 images par seconde. Le jeu sera redimensionné dynamiquement au moment de l'exécution. C'est un "problème" récurrent sur mobile où chaque téléphone/tablette peut avoir une résolution différente. Heureusement j'ai déjà pas mal creusé la question et le vectoriel "natif" de Flash est ici le bienvenue. Le rythme de 30 img/s (et non 60 habituellement) me paraît plus "prudent" vu la lenteur de la technologie utilisée sur de nombreux supports encore en circulation.

J'ai donc commencé par chercher à faire défiler un fond (arrière plan). Celui­-ci ne contient aucun objet avec lequel on peut interagir et n'est là qu'à titre purement "graphique". Sa vitesse de défilement est proportionnelle à la vitesse de déplacement du personnage, mais amoindri (effet de parallaxe). Mon idée était d'utiliser une image assez grande pour être utilisée en boucle (pas de construction via un système de map/tile). Plutôt que de dessiner quelque chose de temporaire, j'ai utilisé un bruit de Perlin (facile à réaliser en AS3) pour remplir ce fond. Quand je ferai les graphismes je remplacerai par une véritable image.
Ce fond est donc une classe, nommée Fond_manager qui étend la classe Node2D (une classe de ND2D) et contient elle­-même un Sprite2D (autre classe de ND2D)

Le résultat :


Pour le défilement (vertical), j'ai joué sur la propriété material.uvOffsetY du Sprite2D plutôt que sur sa coordonnée y, réglant ainsi automatiquement le problème du défilement continu. J'ai aussi remarqué qu'utiliser cette propriété semble rendre le scrolling moins sujet aux saccades ou "freeze" intempestif. Le scrolling est un des problèmes les plus épineux en Flash (surtout sur mobile), même en utilisant Stage3D, et il est très difficile d'avoir un résultat vraiment parfait. Je ferai prochainement un article sur ce sujet.

Le projet a alors l'arborescence suivante :
Application (=Sprite) ­> Jeu (=Scene2D) ­> Fond_manager (=Node2D) ­> background (=Sprite2D)

Tous les autres éléments du jeu (sauf les menus, …) reprendront le même principe : extension de la classe ND2D et création d'éléments de type Sprite2D.
Pour la vitesse de défilement, j'utilise une notion de vitesse verticale (modifiée à chaque rebond) et de gravité, commun à tous les jeux de plateformes.

Arriver à cette étape m'a déjà pris plusieurs jours, malgré mon expérience de ce type de développement. Ma volonté de simplifier le code, d'adopter une nouvelle norme de nommage et des plantages inexplicables de mon Flash m'ont vite fait déchanter quant au temps global de développement de ce projet. Puis les choses ont repris une vitesse de croisière plus habituelle…

Je gère donc ensuite le personnage (d'abord dessiné sous la forme d'un simple carré noir) via une classe Player_manager.
Contrairement au Doodle Jump d'origine, je souhaite :
- faire rebondir sur les cotés plutôt que de pouvoir passer d'un coté à l'autre automatiquement. Un détail.
- faire monter ou descendre uniquement le décor, pas le personnage. Ce point simplifie la programmation et ne me paraît pas dommageable au plaisir du jeu.

Le contrôle du personnage doit être réalisé via l'inclinaison du téléphone et donc utiliser l'accéléromètre de la machine. En soit, lire les données renvoyées par l'accéléromètre ne pose pas de difficulté avec AIR, mais leur utilisation est autrement plus problématique !
En effet sur quel axe d'inclinaison (x, y, z) se baser ? le déplacement doit-­il être proportionnel à l'angle d'inclinaison ? le personnage doit-­il avoir une inertie ? …
Il n'y a pas de réponse idéale (et peu de documentation sur le sujet), il faut donc expérimenter les différentes pistes, faire des réglages, encore et encore… ce qui devait prendre une heure m'a finalement pris une demi­-journée (!) pour arriver à un résultat "correct" mais que je sais devoir revoir pour la version définitive. Disons que je clos temporairement ce problème pour pouvoir passer à autre chose…

A cette étape le projet a donc l'arborescence suivante : Application ­> Jeu ­> Fond_manager > Player_manager

Reste maintenant à s'occuper des plateformes…

C'est évidemment la partie du développement la plus complexe et la plus intéressante. Ici pas de niveaux créés par l'homme, mais un algorithme créant les plateformes selon une certaine logique (en tenant compte des plateformes déjà placées, de la difficulté, …), potentiellement à l'infini…
J'ai commencé par faire 2 types de plateformes (pour le moment représentées par de simples carrés roses/mauves) avec deux intensités de rebond différentes. Au départ une rangée entière de plateformes est créée (pour ne pas tomber dès le début du jeu) puis je crée une (ou deux) plateforme à chaque fois que je monte. Les plateformes qui disparaissent par le bas de l'écran ne sont pas réellement supprimées (en temps qu'objet) mais stockées pour être réutiliser (concept d'Object Pooling).
Pour l'instant le positionnement des nouvelles plateformes est simpliste et purement aléatoire.

A cette étape le projet a donc l'arborescence suivante :
Application ­> Jeu ­> Fond_manager
­> Plateformes_manager
­> Player_manager

Cela me permet d'avoir, après plusieurs jours pénibles, ENFIN une version "fonctionnelle".

Le principal du code étant là (OUF !), il me reste à :
1/ définir les différents types de plateformes
2/ améliorer la génération des plateformes
3/ faire les différents menus
4/ gérer le "game­-over"
5/ faire les graphismes
6/ faire les sons et musiques
7/ penser monétisation
8/ préparer la mise en place sur le Store Android (Google Play)
9/ régler divers détails
10/ conclusion

A ce stade du développement j'atteins sans problème les 30 img/s, aussi bien sur mon PC (pourtant ancien) que sur ma tablette (Mototola Xoom). Je sais donc que j'atteindrai ce rythme sur le jeu final. C'est toujours rassurant…

1/ Types de plateformes
Au-delà de la simple plateforme, je crée (chaque type de plateforme est une classe en soit, qui étend Sprite2D) de nombreux autres types (plateforme qui bouge, plateforme qui se détruit après un rebond dessus, plateforme "trampoline", …) et j'en rajouterai sans doute dans les prochaines mises à jour du jeu.

Pour cette première version j'ai donc défini les types suivant :
(une unité de large = 1 cinquième de la largeur de l'écran)
- type 0 : plateforme "simple" de 2 unités (tile) de large
- type 1 : plateforme "trampoline"
- type 2 : plateforme se déplaçant horizontalement
- ­ type 3 : plateforme se déplaçant verticalement
- type 4 : plateforme "simple" de 1 unité (tile) de large
- type 5 : plateforme se détruisant après un rebond
- type 6 : plateforme non traversable de 1 unité (tile) de large

L'ordre n'a pas été choisi au hasard, mais reflète ­ selon moi ­ une certaine difficulté : des plateformes de type 0 facilitent plus la progression que des plateformes de type 6, …

Au passage, là encore le temps de développement fut plus long que prévu… je pensais y passer une heure mais suite à un bug tordu (une plateforme sur sept, d'un certain type, étant invisible… bien tordu celui-là…) j'y ai passé une demi­-journée…

2/ Améliorer la génération des plateformes
Certaines plateformes facilitent la progression; je dois donc en tenir compte lors de la génération des "niveaux" pour régler la difficulté. Pas mal de réflexion à la clef et d'essais… Je reste au final sur le schéma suivant :
- chaque niveau contient forcément une plateforme de type 4
- le niveau a une chance sur deux de contenir une deuxième plateforme choisie au hasard parmi tous les types disponibles
- le niveau a une autre possibilité (en fonction de la difficulté) de contenir une troisième plateforme, d'un type choisi en fonction de la difficulté
- si une seule plateforme a été créée pour ce niveau, on en crée quand même une deuxième (de type 4). Cette ultime plateforme a été rajoutée pour empêcher les cas impossibles à franchir (rencontrés aux cours des essais).

A priori un micmac tiré par les cheveux, mais en fait le résultat d'une certaine logique et de pas mal d'essais…

Les "ennemis" respectent une logique semblable.

3/ Création des menus
Rien de particulier à dire sur ce point, si ce n'est que leur rendu est ici réalisé avec le moteur par défaut de Flash (donc en vectoriel). Comme ils n'apparaissent que pendant que le jeu est arrêté (ou en pause) cela n'a aucune conséquence sur les performances (et simplifie leur réalisation).
A noter aussi que pour l'instant je ne gère pas un enregistrement "mondialisé" des scores (pour une prochaine mise à jour je pense). De même je ne souhaite pas proposer x options de réglages (calibration de l'accéléromètre, volume, niveau de détails, …). Je changerai les choses au cas par cas en fonction des retours des joueurs.

J'ai donc 3 écrans de menu
- un écran "général" qui propose de jouer, couper le son, voir une page d'infos et d'aller sur mon Store.
- un écran d'infos qui affiche les divers copyright et autres infos techniques sur le jeu.
- un écran de "game-­over" qui propose soit de rejouer, soit de revenir au menu général.

Bref, le minimum syndical… Mais cela devrait suffire pour une version 1.0…

4/ gérer le "game­-over"
Il suffit de tester à chaque déplacement le nombre de plateformes "actives". S'il n'en reste plus, c'est qu'elles sont toutes sorties de l'écran (par le haut) et donc qu'on est déjà en train de tomber depuis un certain temps. Il suffit alors d'afficher le menu de "game­-over". Tout simplement. Au passage on met le moteur d'affichage ND2D en pause (world2d.pause()). De même la moindre collision avec un ennemi "tue" Flop-Flop...

5/ faire les graphismes
Là encore, les choses ne se passent pas comme d'habitude (décidément ce "petit" projet se révèle plein de surprises!)… En effet imaginer et créer est souvent une formalité pour moi… Les idées ne me manquent jamais. Je pensai donc que trouver un "univers" graphique pour ce jeu serait simple, car les possibilités ne manquent pas… Malheureusement ce type de jeu étant très répandu, de nombreuses pistes ont déjà été exploitées… un "sauteur" extra-terrestre ? Déjà fait !... de la gelée ? Déjà fait !... du caca (?!) ? Déjà fait !... et plus je creusais, plus je trouvais de bonnes idées… déjà exploitées… Robot, crème glacée, pingouin, bonhomme en pain d'épice, père noël, ninja, chevalier, super héros, singe, insecte, âne, … :­(


Après une intense réflexion (joke), je décide d'inventer le personnage de Flop­-Flop, le déchet nucléaire. Il aurait pris vie un soir d'orage, quelque part dans une usine de retraitement des déchets nucléaires, blablabla… Bref il est flasque, il est vert fluo, il a de gros pustules, il est pas très fufute mais il est sympa et… il veut vivre !!! Son but : s'échapper de l'usine avant d'être réduit en cendre…

Bon, on peut pas avoir de super idées à chaque fois…

Voici quelques recherches graphiques autour de cette idée :



Remarquez au passage que les dessins ont aussi été réalisés dans Flash. J'ai finalement décidé de travailler directement en vectoriel dans le logiciel…

Finalement après x retouches et essais, il ressemble définitivement à ça :


Je passe ensuite aux plateformes, ce qui est finalement réglé en quelques après­-midi (ici capturé dans mon environnement de travail avec certaines ébauches non utilisées):


Les menus sont inspirés directement et simplement de l'esprit des plateformes :


Reste à créer quelques animations du personnage lorsqu'il atterrit, s'écrase, etc… Curieusement j'ai eu un peu de mal… ne sachant encore si le personnage devait être ridicule, cartoon, touchant, kawai, … (animations ici au ralenti) :


Un "méchant" (j'en créerai d'autres types) régulièrement :


6/ Sons
J'avais prévu une semaine pour faire les sons et des musiques... mais pour x raisons personnelles, cette semaine s'est envolée avant que je puisse toucher un clavier... Donc c'est le dernier jour avant la sortie (un dimanche en plus...) que je me suis décidé à m'y mettre... N'ayant pas touché un vrai instrument de musique depuis des années, je me suis rabattu sur mon ami Kaossilator. Si vous ne connaissez pas ce génial petit appareil Korg, je vous conseille quelques recherches sur youtube. Pour résumé celui-ci permet de faire des boucles rythmiques ou des morceaux très chiptune sans réelles connaissances musicales. Notez que l'appareil génère les sons, ce n'est pas un clavier midi; aucun son ne vient de mon ordinateur ou d'un autre appareil. Bref, avec un kaossilator on a besoin de rien d'autre...

L'appareil ne comportant aucun moyen d'enregistrement (on éteint et on perd tout...) il est conseillé ne noter ce que l'on fait au fur et à mesure si on veut être capable de refaire un morceau deux fois de suite... Voilà ce qu'à donné dans mon cas cette "notation" musicale peu académique :


Dans quelques siècles les archéologues s'arracheront les cheveux à déchiffrer ce bout de papier... :-)

Je me suis filmé en train de faire la boucle actuelle du jeu... La boucle fait environ 1 minute et en gros j'ai mis 3 minutes à la faire... Comme quoi les "vrais" compositeurs n'ont vraiment aucun mérite ;-) :



J'ai raccordé le kaossilator à mon pc via un simple cable double-jack et enregistré en live via Adobe SoundBooth (un freeware fait aussi l'affaire). Juste une retouche pour améliorer le bouclage du son et hop !... bon, je me console en me disant qu'on peut couper le son... La preuve est faite que je ne suis pas musicien en tous cas...

Mise à jour de la version 1.0.2 (juillet 2013) : J'ai finalement acheté une petite musique libre de droit... il faut savoir laisser s'exprimer le talent des autres...

Mise à jour de la version 1.0.4 (juillet 2013) : J'ai rajouté des bruitages. ça devient un peu plus "vivant"...

7/ Monétiser
Le but n'était pas de faire une application payante. Non seulement les équivalents sont gratuits mais de toutes façons la vente sur Android est hasardeuse et nécessite marketing, pub, ... Pour moi plutôt l'occasion de tester la publicité dans l'application. Techniquement j'utilise admob (de google) et l'ANE (extension pour adobe air) de Milkman Games. Aucune difficulté en passant par cet ANE; des heures d'essais plus ou moins heureux avec d'autres ANE gratuits...

8/ Mise en place sur l'Android Market
L'ayant déjà fait (pour MultiChrono), j'ai prévu une journée pour faire les icones, la fiche, etc... et une autre journée pour soumettre l'application. Au final aucun problème. La soumission étant très rapide dans mon cas. Soumis le dimanche soir, tout était en place lundi matin... Un conseil : Si vous soumettez pour la première fois, ne négligez pas le temps de création des images, descriptions, traductions, ... demandés.

9/ Divers
Je complèterai ultérieurement... mais forcément toujours plein de petits bugs et améliorations à régler tout au long de l'aventure...

Mise à jour de la version 1.0.2 (juillet 2013) : J'ai rajouté un mini "enregistreur d'actions" dans le jeu, qui stocke dans une base sql distante (sur mon serveur) le nombre de démarrage de l'application, le nombre de parties lancées, etc... un bon moyen de traquer les bugs et un premier pas vers l'enregistrement des scores...

Mise à jour de la version 1.0.3 (juillet 2013) : J'ai empêché la mise en veille de l'écran. Sur ma tablette de test, aucun problème (surtout que je teste sans jouer longtemps), mais on m'a signalé que la mise en veille rapide de certains téléphones gâchait était vraiment problématique. J'ai donc corrigé (surtout que techniquement c'est très simple...).

10/ Conclusion
J'avais prévu de sortir le jeu le 1ier juillet et j'ai tenu les délais... j'avais prévu de ne travailler dessus que l'après midi (pas que ça à faire) et je m'y suis tenu... mais à part ça les choses ont été plus complexes que prévu (comme d'habitude finalement...).

Si vous envisagez de créer seul un jeu, voici mes conseils :
- il n'y a pas de "petit" projet... tout projet demande du temps, de la réflexion et un certain investissement personnel. Bien y penser avant de se lancer.
- On met TOUJOURS plus de temps que prévu... c'est LA règle absolue. Ne pas l'oublier dans son planning.
- Flash/air est tout à fait adapté à ce genre de jeux. L'utilisation d'une bibliothèque stage 3D est quand même indispensable... Starling, nd2D, genome2D, ... peu importe laquelle.
- De nombreux projets en équipe n'arrivent pas jusqu'au bout, car il est difficile de partager la même motivation lorsqu'il s'agit d'un projet non "professionnel"; alors plutôt que de démarrer un projet qui n'aboutira pas, lancez vous seul ! Oui, on peut faire un jeu seul de A à Z ! la preuve...
- Misez sur vos qualités et connaissez vos faiblesses (et défauts)
- Ne visez pas la lune... en tous cas pour vos premières réalisations.
- Préparez la sortie du jeu pendant le développement... par exemple en écrivant un making-of (n'espérez pas l'écrire après, vous aurez oublié la moitié de ce qui s'est passé)... repérez les sites pouvant vous consacrer un article, ... tout cela peut/doit être fait pendant le développement. Un bon moyen de se changer les idées face à un bug récalcitrant...
- Fixez vous des délais, un planning, ... Même large cela aide à maintenir la pression et à aller jusqu'au bout...

11/ Et maintenant...
Le jeu est sorti un peu à l'arrache le 1ier juillet (2013)... Le jour précédent je n'avais encore pas de musique, pas mal de bugs, ... Bref je sais que je vais faire des mises à jour... rajouter des ennemis, une vraie musique, peut être une animation d'intro... Je pense faire une version iOS (iphone, ipad, ...) en septembre. je prévois aussi de faire régulièrement le point sur ce blog quant aux téléchargements et à la pub embarquée... A SUIVRE...

Pour rappel, le jeu est téléchargeable GRATUITEMENT ici : https://play.google.com/store/apps/details?id=air.OpiumBleu.FlopFlopJump