Le comptoir du code

Les pérégrinations d'un développeur pragmatique

Angular Bomber

By Mik | 16 octobre 2015 | 3 Comment

Le jeu

Comment jouer?

Cliquer pour commencer, plus cliquer pour lancer une bombe.

Le repo sous github

Le contexte

En ce moment j’ai eu un peu de temps et je me suis remémoré un jeu auquel j’avais joué dans mon enfance, avec des graphismes HD de l’époque (je ne suis même pas sûr qu’il y avait plus de 2 couleurs).

Il s’agissait d’un avion passant en dessus d’une ville, qui passait de gauche à droite en larguant une bombe à chaque passage, ce qui détruisait entièrement un building.

Le problème c’est qu’il perdait de l’altitude à chaque passage, ce qui fait qu’au bout d’un moment, il risquait d’entrer en collision avec un building. C’est la dure vie d’un monde en 2D : on ne peut pas passer entre les immeubles.

origine

Julius Corentin Acquefacques aussi a ce genre de problème

Bref, ça m’a rappelé des souvenirs, et je me suis demandé comment le refaire dans la techno du moment, j’ai nommé Angular (pousse-toi React, c’est pas encore ton tour).

Premier jet des tâches prévues :

  • initialisation et link du repo dans github
  • faire des graphismes en html/CSS : le jeu n’utilise aucune librairie graphique, que du CSS. Parce que c’est marrant et que les jeux rétro sont à la mode.
    • avion
    • immeubles avec des couleurs
    • bombe
  • Passer l’application sous angular
  • Première animations simples
    • avion
    • bombe
  • Création d’un event sur le clic souris (cliquer largue une bombe, c’est la principale interaction avec le jeu)
  • Lier l’animation de la bombe avec le clic
  • Lier les immeubles au modèle mémoire
  • Lier les bombes aux immeubles
  • Génération automatique du niveau

Puis dans la V2 :

  • Système de niveaux
  • Vérifier que les niveaux sont possibles à finir et que les immeubles ne sont pas trop haut!
  • Meilleur rendu graphique
  • Et tout ce qu’on ne fera jamais car pas le temps

On est parti!
Commençons par l’initialisation du repo git dans un coin du disque dur.
On passe par l’interface github et on fait notre tout nouveau repo.

angular-bomber-github

Création du repo sous github

Puis on récupère le repo vide, lié au repo distant github automatiquement.

git clone git@github.com:grafmik/angular-bomber.git

Et voilà, il n’y aura plus qu’à faire des pushs en temps voulu.

Faisons un premier commit avec un README, ce sera fait.

echo "# building-destroyer-angular" >> README.md
git add .
git commit -m "Initial commit"
git push origin master

Graphismes

Les graphismes vont être simplistes, faisons-les rapidement avec un fichier html5 et un fichier css rattaché.
Je conçois les graphismes en premier car cela montrera le design du jeu. Il est toujours sympa de voir à quoi ressemblera le projet le plus tôt possible, plutôt que de travailler sur la plomberie invisible. Ca permet de mieux comprendre le projet. Pour moi c’est quelque chose qu’il vaut mieux faire pour tous les projets, surtout pour les POC (proof of concept), les maquettes et les MVP (minimum viable products).

Je vais travailler « à l’ancienne », avec des cases : l’avion tient sur une case, un étage d’un immeuble est une case, une bombe est une case. Ca donnera l’effet (très!) rétro que je souhaite, et simplifiera également la programmation.

angular-bomber-premiere-version

oh mon dieu c’est magnifique

Voilà! La version 0.1 alpha du jeu sera le sublime « dessin » sur la gauche. Le carré blanc est l’avion qui passe de gauche à droite, le carré noir est la bombe, de la même taille que l’avion 😉 et les immeubles en bas, avec des couleurs choisies avec goût. Et derrière, le ciel, cyan bien évidemment.

On pourra reprendre les graphismes plus tard, mais je ne vois pas vraiment trop comment améliorer cette perfection 😉
Blague à part, je laisse tout dans un style de carré brut. Il serait facile de rajouter des images ou bien de détailler les graphismes en ajoutant des règles css.

Ajouter Angular et remplacer les données d’example par un modèle

Le html va être le premier à bénéficier de ce changement en perdant pas mal de lignes et en devenant dynamique :

<div class="game" ng-app="angularbomber" ng-controller="BomberController" ng-click="mainClic()">
  <div ng-repeat="buildingFloor in buildingsToDisplay" class="sprite building-floor" ng-style="buildingFloor.style"></div>
  <div ng-if="plane.active" class="sprite plane" ng-class="{crashed: plane.crashed}" ng-style="plane.style"></div>
  <div ng-if="bomb.active" class="sprite bomb" ng-style="bomb.style"></div>
  <div ng-if="isMessageDisplayed()" ng-bind="getMessageDisplayed()" class="mainmessage"></div>
</div>

On voit déjà assez simplement qu’il va y avoir des immeubles, un avion, une bombe, et également un message global pour le game over ou la fin du niveau. Oui il n’y a qu’un seul niveau pour l’instant, et je pense qu’il faudra attendre la version 2 pour des niveaux supplémentaires. Je prévois la livraison de cette version en 2040 s’il n’y a pas de retard 😉

Pour ce qui est des css, on utilise du relative-absolute pour placer les sprites comme il faut.
Une des difficultés est de transformer le modèle des immeubles en modèle Angular.

En gros, transformer un objet building avec un attribut hauteur en une série de blocs (étages de l’immeubles) qu’on affichera avec la directive ng-repeat.

Moteur de jeu

Une itération de jeu se fait à intervalle de temps donné.

setInterval(function() { $scope.gameengine(); }, 150);

La fonction contient toute la logique du jeu : elle fait avancer l’avion, le fait se crasher, fait tomber la bombe, rase les immeubles, etc.

Problèmes rencontrés

Quelques problèmes rencontrés, dont certains non résolus, notamment des problèmes de rafraichissement de $scope, il faudra que je m’y penche.
J’étais parti sur une syntaxe « controller as » mais je me suis ravisé car il me semblait que les problèmes de $scope venaient de là, en fait j’ai tout remplacé par $scope et ça n’a rien changé.
J’avais également utilisé des $watch, qui malgré le 3e paramètre à true pour le deep watch, ne se déclenchaient pas lors d’un changement de l’objet. Du coup j’ai fait plus simple en rafraichissant directement les données quand j’en avais vraiment besoin.
Je ne vais pas regarder en détail tout cela par manque de temps, bien que les problématiques sont intéressantes.

Conclusion

Voici pour le premier article de ce blog.
J’avais très envie de réaliser ce petit jeu ces derniers jours, donc voilà, c’est fait!
Je me suis bien amusé 😉
Le jeu marche pas trop mal, c’est ce que je voulais.
Bien sûr il pourrait être tellement amélioré. Cependant, le voir tourner si rapidement (une soirée de code) est vraiment gratifiant 🙂
Si j’ai du temps un jour, je repasserai peut-être dessus. D’ici là, pas mal de boulot m’attend ailleurs, on ne peut pas faire que jouer…

Le repo sous github

A la prochaine!

TAGS

3 Comments

19 octobre, 2015 Répondre

Salut,

Sympathique expérience et jeu plus difficile qu'il n'y paraît. Voire impossible si tu te loupes une fois, non ?
Je ne pense pas que cela change grand chose, mais j'avais lu qu'il fallait mieux utiliser une boucle avec setTimeout plutôt qu'un setInterval. Je crois que c'était dans le livre de Rob Hawkes 'Foundation HTML5 Canvas', mais la raison était celle expliquée dans cet article. http://javascript.info/tutorial/settimeout-setinterval

Bon courage pour les graphismes. :)

    Mik

    19 octobre, 2015 Répondre

    Hello!

    Oui, le niveau est généré aléatoirement de manière très naïve, ce qui fait que si l'on a pas de chance lors du chargement du jeu, le niveau est impossible à terminer :) il faudra attendre la V2 pour avoir un meilleur algorithme qui résoudra ce problème ;) C'est de l'open source, les pull request sont bienvenus!

    Effectivement dans certains cas je pense qu'un setTimeout est plus approprié qu'un setInterval.
    Cependant dans le cas de ce jeu, si le navigateur est lent et manque une frame d'animation, je pense qu'il est préférable qu'il n'y ait pas de rattrapage des événements perdus car dans ce cas, l'avion avancera d'un coup de plusieurs cases, potentiellement pour aller se loger dans un immeuble.
    Avec setInterval, le jeu ralentira juste. Le jeu sera d'ailleurs plus facile sur un navigateur lent.

    Merci et bon jeu! ;)

14 mai, 2016 Répondre

The stealth bomber's peculiar shape deflects radio beams in both ways. The large flat areas on the top and bottom of the plane are just like tilted mirrors. These flat areas will deflect most radio beams away from the station, presuming the station isn't directly beneath the plane.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *