Dans ce chapitre nous allons voir le menu de notre jeu et mettre en place la gestion des collisions.
Les références
On va avoir les nouveaux fichiers menu.js et collisions.js, on va donc les charger dans index.html :
<!-- Load Crazy Bird --> <script src="js/game.js"></script> <script src="js/boot.js"></script> <script src="js/particles.js"></script> <script src="js/load.js"></script> <script src="js/settings.js"></script> <script src="js/utils.js"></script> <script src="js/menu.js"></script> <script src="js/collisions.js"></script>
D’autre part dans le fichier load.js on avait commenté les événements pour éviter de générer des erreurs, on va avoir besoin maintenant d’en dé-commenter quelques uns :
... C.sprites.help.mousedown = C.menu.onHelp; C.sprites.help.touchstart = C.menu.onHelp; ... C.helpPannel.mousedown = C.menu.onHideHelp; C.helpPannel.touchstart = C.menu.onHideHelp; ... C.sprites.play.mousedown = C.menu.onPlay; C.sprites.play.touchstart = C.menu.onPlay; ...
Enfin dans le fichier game.js on va ajouter les propriétés nécessaires pour le jeu, on en est donc avec toutes ces propriétés :
// Properties state: undefined, stage: undefined, renderer: undefined, pannelHeight: 40, sounds : { balloon: undefined, crash: undefined, crashPlane: undefined, life: undefined }, sprites: { loading : undefined, sky: undefined, land: undefined, title: undefined, play: undefined, help: undefined, bird: undefined, pannel: undefined, planes: [], balloons: [], gameOver: undefined, playAgain: undefined }, helpPannel: undefined, helpMessage: undefined, highScoreText: undefined, messageText: undefined, nbrPlanes: 3, nbrBalloons: 2, elapsed: Date.now(), level: 1, balloonsDone: 0, maxBalloons: 8, lifes: 0, score: 0, speed: 5,
Le fichier menu.js
C’est ici qu’on a le code pour gérer le menu auquel on a abouti dans le précédent chapitre :
/* global PIXI, C */ C.menu = { // Properties scaleStep: 0.01, show: function () { C.sprites.title.scale.x += this.menu.scaleStep; C.sprites.title.scale.y += this.menu.scaleStep; if (C.sprites.title.scale.x > 1.1) { this.menu.scaleStep = -.01; } else if (C.sprites.title.scale.x < .9) { this.menu.scaleStep = .01; } }, // Help event onHelp: function () { C.helpPannel.visible = true; C.helpMessage.visible = true; }, // Hide help event onHideHelp: function () { C.helpPannel.visible = false; C.helpMessage.visible = false; }, // Play event onPlay: function () { C.sprites.title.visible = false; C.sprites.play.visible = false; C.sprites.help.visible = false; C.highScoreText.visible = false; C.sprites.bird.visible = true; C.messageText.visible = true; C.sprites.pannel.visible = true; C.state = C.play.on; } };
La fonction show
On a vu que l’état dans lequel le jeu se trouve appelle en permanence cette fonction. En effet dans setting.js on a prévu à la fin :
C.state = C.menu.show;
On fait un effet de changement de dimension du titre (il grossit et se réduit de façon cyclique). A cet effet on prévoit une propriété :
scaleStep: 0.01,
Et ensuite on gère la dimension dans la fonction :
show: function () { C.sprites.title.scale.x += this.menu.scaleStep; C.sprites.title.scale.y += this.menu.scaleStep; if (C.sprites.title.scale.x > 1.1) { this.menu.scaleStep = -.01; } else if (C.sprites.title.scale.x < .9) { this.menu.scaleStep = .01; } },
Ça crée un peu d’animation sur l’écran et c’est facile à faire ! on en est ici :
Help !
Voyons maintenant la partie aide. Pour faire apparaître la fenêtre d’aide il faut cliquer (ou toucher) sur « HELP ! ». Ce qui appelle la fonction onHelp
:
// Help event onHelp: function () { C.helpPannel.visible = true; C.helpMessage.visible = true; },
On se contente de rendre visible le panneau d’aide :
Si on clique (ou touche) maintenant le panneau d’aide on appelle la fonction onHideHelp
:
// Hide help event onHideHelp: function () { C.helpPannel.visible = false; C.helpMessage.visible = false; },
Et là on rend à nouveau le panneau non visible.
Play
Si on clique (ou touche) « PLAY » on appelle la fonction onPlay
:
// Play event onPlay: function () { C.sprites.title.visible = false; C.sprites.play.visible = false; C.sprites.help.visible = false; C.highScoreText.visible = false; C.sprites.bird.visible = true; C.messageText.visible = true; C.sprites.pannel.visible = true; C.state = C.play.on; }
On rend visibles tous les sprites pour le jeu et on change l’état avec une fonction qu’on verra dans le prochain chapitre. On obtient maintenant cette apparence :
Le jeu est en place et il ne restera plus qu’à l’animer !
Les collisions
On va avoir besoin de gérer les collisions :
-
entre l’oiseau et les avions,
-
entre l’oiseau et les ballons,
-
entre les avions entre eux pour éviter qu’ils soient empilés.
On a vu dans la première partie la librairie sat.js qu’on utilise pour cette gestion.
Voici le code complet du fichier collision.js :
/* global C, SAT */ // Aliases var V = SAT.Vector; C.collisions = { //Properties response: undefined, planePolygon: [ new V(4, 128), new V(192, 8), new V(332, 68), new V(264, 201), new V(99, 212) ], balloonPolygon: [ new V(10, 0), new V(20, 0), new V(20, 75), new V(30, 75) ], // Get plane box getPlaneBox: function (plane) { return new SAT.Box(new SAT.Vector(plane.x, plane.y), 356, 222).toPolygon(); }, // Get plane polygon getPlanePolygon: function (plane) { return new SAT.Polygon(new V(plane.x, plane.y), this.planePolygon); }, // Get balloonn polygon getBalloonPolygon: function (balloon) { return new SAT.Polygon(new V(balloon.x, balloon.y), this.balloonPolygon); }, // Get balloon circle getBalloonCircle: function (balloon) { return new SAT.Circle(new V(balloon.x, balloon.y - 35), 40); }, // Get bird circle getBirdCircle: function () { return new SAT.Circle(new V(C.sprites.bird.x + 40, C.sprites.bird.y + 60), 38); }, // Detect bird/plane collision birdPlane: function (plane) { return SAT.testPolygonCircle(this.getPlanePolygon(plane), this.getBirdCircle(), this.response); }, // Detect bird/balloon circle collision birdBalloonCircle: function (balloon) { return SAT.pointInCircle(new V(C.sprites.bird.x + 133, C.sprites.bird.y + 83), this.getBalloonCircle(balloon), this.response); }, // Detect bird/balloon polygon collision birdBalloonPolygon: function (balloon) { return SAT.pointInPolygon(new V(C.sprites.bird.x + 133, C.sprites.bird.y + 83), this.getBalloonPolygon(balloon), this.response); }, // Check for free place for plane freeOfPlane: function (plane) { for (var i = 0; i < C.nbrPlanes; ++i) { if ((C.sprites.planes[i].state && SAT.testPolygonPolygon(this.getPlaneBox(C.sprites.planes[i]), this.getPlaneBox(plane), this.response))) { return false; } } return true; } };
J’utilise un alias pour simplifier la syntaxe des vecteurs :
var V = SAT.Vector;
Les avions
Pour les avions j’ai prévu un polygone tout simple pour les collisions avec l’oiseau :
Ce qui donne cette définition :
planePolygon: [ new V(4, 128), new V(192, 8), new V(332, 68), new V(264, 201), new V(99, 212) ],
Par contre pour le positionnement initial de l’avion avant qu’il entre en scène, pour éviter que les avions soient trop proches j’utilise un rectangle :
L’oiseau
Comme l’oiseau est presque circulaire j’ai défini un cercle pour lui :
Ce repère est pour les collisions avec les avions, pour ce qui est des ballons on prend uniquement le bout du bec.
Les ballons
Pour les ballons j’ai distingué deux parties :
-
le ballon lui-même avec un crevaison à la clé,
-
le manche sans crevaison mais juste une inclinaison.
Les fonctions de création des zones
On a des fonctions pour générer la définition des zones de collision :
// Get plane box getPlaneBox: function (plane) { return new SAT.Box(new SAT.Vector(plane.x, plane.y), 356, 222).toPolygon(); }, // Get plane polygon getPlanePolygon: function (plane) { return new SAT.Polygon(new V(plane.x, plane.y), this.planePolygon); }, // Get balloonn polygon getBalloonPolygon: function (balloon) { return new SAT.Polygon(new V(balloon.x, balloon.y), this.balloonPolygon); }, // Get balloon circle getBalloonCircle: function (balloon) { return new SAT.Circle(new V(balloon.x, balloon.y - 35), 40); }, // Get bird circle getBirdCircle: function () { return new SAT.Circle(new V(C.sprites.bird.x + 40, C.sprites.bird.y + 60), 38); },
Les fonction de test de collision
On a ensuite des fonction de test de collision :
// Detect bird/plane collision birdPlane: function (plane) { return SAT.testPolygonCircle(this.getPlanePolygon(plane), this.getBirdCircle(), this.response); }, // Detect bird/balloon circle collision birdBalloonCircle: function (balloon) { return SAT.pointInCircle(new V(C.sprites.bird.x + 133, C.sprites.bird.y + 83), this.getBalloonCircle(balloon), this.response); }, // Detect bird/balloon polygon collision birdBalloonPolygon: function (balloon) { return SAT.pointInPolygon(new V(C.sprites.bird.x + 133, C.sprites.bird.y + 83), this.getBalloonPolygon(balloon), this.response); },
Espace libre d’avion
Pour terminer on a une fonction pour déterminer si un espace est libre d’avion pour positionner un avion prêt à se lancer :
// Check for free place for plane freeOfPlane: function (plane) { for (var i = 0; i < C.nbrPlanes; ++i) { if ((C.sprites.planes[i].state && SAT.testPolygonPolygon(this.getPlaneBox(C.sprites.planes[i]), this.getPlaneBox(plane), this.response))) { return false; } } return true; }
Si on fait le point on commence à avoir pas mal de fichiers pour notre jeu :
En résumé
Dans ce chapitre on a :
-
mis en place la gestion du menu avec l’aide et le lancement du jeu
-
mis en place la gestion des collisions