enchant.js - 7e partie
Rédigé par Fred - - Aucun commentaire
Il existe plusieurs plugins pour enchantjs dont certains ont été
intégrés directement dans enchant.js
. Par exemple avatar
, ui
,
box2d
, gl
, timeline
…
On va commencer par s’intéresser à timeline
, plugin qui n’en est
plus un maintenant.
timeline
Supposons que l’on veuille déplacer un sprite d’un point A à un point
B sur une certaine période de temps. Il va falloir : prendre en compte
la distance entre les deux points, le taux de frame par seconde, et
calculer de combien le sprite doit se déplacer. Le « plugin »
timeline
permet de faire ça plus simplement : il permet de contrôler
les entités suivant le temps (et aussi suivant les frames). En faisant
un_sprite.tl.setTimeBased()
, on indiquera un temps dans les méthodes du
plugin, alors que par défaut (ou avec un_sprite.tl.setFrameBased()
)
on indiquera un nombre de frames.
Par exemple, bear.tl.moveTo(250, 250, 2000);
fera bouger bear
vers
le point (250, 250)
en 2 secondes ou en 2000 frames (de la même
manière, il existe moveBy
qui permet de se déplacer d’un certain
nombre de pixels). On peut également faire tourner (rotateTo
et
rotateBy
), mettre à l’échelle (scaleTo
et scaleBy
) ou alors
régler l’opacité du sprite (fadeIn
, fadeOut
et fadeTo
) de la
même façon.
Ce qui est pratique, c’est qu’on peut enchaîner les instructions :
bear.tl.moveTo(250, 250, 2000).scaleTo(-1, 1, 250) .moveTo(10, 10, 2000).scaleTo(1, 1, 250);
On se déplace, se tourne, puis on retourne au point de départ, et on se remet dans le bon sens. Cela n’empêche en rien l’ajout d’écouteur comme on peut le voir dans l’exemple 2.
Dans l’exemple suivant, on voit que les méthodes loop
, delay
et
then
font ce que leur nom indique : loop
permet de répéter à
l’infini une séquence, delay
permet de temporiser et then
permet
l’appel à une fonction. (Pour arrêter la boucle, on peut utiliser
unloop
.)
Si on veut enchaîner les appels à delay/then
:
bear.tl.delay(30).then(une_fonction). delay(15).then(function{}( dosomething(foo));). delay(10).then(function{}( this.anotherthing(););
on peut utiliser cue
à la place :
bear.tl.cue({ 30: une_noction, 45: function{}(do_something(foo)), 55: function{}(this.anotherthing()) });
Dans l’exemple 4, on a deux sprites qui se comportent de façon
identique, l’un avec delay/then
, l’autre avec cue
.
On a vu précédemment, que bear.tl.moveTo(250, 250, 2000).scaleTo(-1,
1, 250)
permettait au sprite de se déplacer, puis de se retourner.
Si on veut faire les deux actions en même temps, on peut soit utiliser
la méthode tween
:
bear1.tl.tween({ x: 250, y: 250, scaleX: 2, rotation: 45, opacity: 0.5, time: 2000});
qui permet de faire toutes ces opérations en même temps, soit utiliser
la méthode and
:
bear2.tl.delay(2000).moveTo(250, 10, 3000).and(). scaleTo(3, 1, 4000).and(). fadeTo(0.5, 100);
qui permet de chaîner les instructions (et également de mettre des durées d’action différentes) comme le montre l’exemple 5.
La ligne de temps est en fait gérée sous forme de queue
. Et quand on
fait bear.tl.moveBy(10,10,10);
la timeline
est retournée. On peut
donc soit enchaîner les actions sur une même ligne, soit les mettre
sur plusieurs :
bear.tl.moveBy(10,10,10).rotateTo(90,100); //est équivalent à bear.tl.moveBy(10,10,10); bear.tl.rotateTo(90,100);
On peut aussi arrêter/redémarrer la ligne de temps :
bear1.on('touchstart', function(){ if (flag){ bear1.tl.pause(); }else{ bear1.tl.resume(); } flag = !flag; });
Et attendre un événement avec la méthode waitUntil
qui prend en
argument une fonction qui va retourner vrai au bout d’un moment ce qui
permet de passer à l’action d’après :
bear3.tl.waitUntil(function(){ bear3.moveBy(1,1); return bear3.x>200; }).moveTo(150, 150, 1000).waitUntil(function(){ return flag;}).moveTo(200, 200, 1000);
Ici, bear3
va se déplacer d’un pixel par un pixel, et lorsque qu’il
aura dépassé la borne, il ira en (150, 150)
, puis attendra que
flag
soit à true
et se déplacera à nouveau.
Il existe encore d’autres méthodes, mais on ne va pas les voir (je vous
invite à regarder le code source), à part la méthode action
qui
prend comme paramètre la durée d’exécution de l’action (avec time
),
une fonction d’initialisation, une fonction de fin, et une fonction à
exécuter durant l’exécution de l’action :
bear2.tl.delay(1000).action({ time: 2000, onactionstart: function(){ lbl.text = "ça commence"; bear2.tl.show(); }, onactionend: function(){ lbl.text = "c’est fini"; bear2.tl.removeFromScene(); }, onactiontick: function(){ lbl.text = "c’est en cours"; bear2.x++; bear2.opacity -= 1 / 60; } });
Ces trois derniers points sont regroupés dans l’exemple 6.
Pour terminer, on va s’intéresser à un argument que prennent la plupart de ces méthodes. On peut en effet contrôler la vitesse d’exécution des animations (easings.net). Pour cela on ajoute la fonction en dernier paramètre :
sprite.tl.moveBy(100, 100, enchant.Easing.QUAD_EASEOUT). fadeTo(0.5, enchant.Easing.SWING)
Les différentes fonctions possibles sont montrées dans l’exemple suivant.
ui
Le plugin ui
définit un certain nombre de classes comme une croix
directionnel, un pad analogique, la création de bouton, et moultes
autres choses bien sympathiques. On va voir la plupart.
Croix directionnelle, pad analogique
On a fait un jeu qui utilise les flèches du clavier, mais on veut que
notre jeu soit jouable sur tablette. Comment faire ? On utilise la
classe Pad
ou APad
du plugin :
var pad = new Pad(); pad.x = 0; pad.y = 220; game.rootScene.addChild(pad); var apad = new APad(); apad.x = 0; apad.y = 220; game.rootScene.addChild(apad);
Dans le cas de la croix directionnelle, on peut utiliser
game.input.left
, comme pour le clavier. On a donc seulement le code
du dessus à ajouter pour avoir un pad qui fonctionne : la différence
entre l’exemple 8 et l’exemple 8b, c’est uniquement le code ci-dessus.
On peut faire en sorte que l’utilisateur ait un retour sur le fait qu’il clique bien sur la croix :
pad.frame = 0; if (game.input.left) { this.vx = -4; pad.frame = 1; pad.rotation = 270; }
Le frame 1 de la croix a le bouton du haut de grisé. En jouant sur la rotation, on obtient l’effet souhaité.
Pour le pad analogique, c’est tout aussi simple. Il suffit d’ajouter
this.moveBy(apad.vx*5, apad.vy*5);
comme le montre l’exemple 8c. Si on veut ne gérer que le pad, il
suffit de supprimer les contrôles sur game.input
. À l’inverse, on
peut aussi ne pas vouloir se déplacer à la fois avec le pad et les
flèches. Il suffit de contrôler si le pad est touché avec
apad.touched
:
if (apad.isTouched){ this.vx = apad.vx*5; this.vy = apad.vy*5; }
C’est ce qui est fait dans l’exemple 8d.
Les boutons
Le plugin permet aussi de créer de jolis boutons facilement. Le code
btn_un = new Button("Un premier bouton", "blue", 50, 150);
crée un bouton de 50×150 avec le texte Un premier bouton
en
appliquant le thème bleu. On peut bien sûr ajouter des thèmes pour
choisir ses propres couleurs. Quand on appuie sur le bouton,
btn.pressed
passe à true
, btn.y
est incrémenté, et le thème
active
est appliqué. Quand on relâche, btn.pressed
passe à
false
, btn.y
est décrémenté, et le thème repasse à normal
. Pour
voir ça en action, c’est dans l’exemple 9.
Affichage de texte
Les labels
utilisent les polices de l’ordinateur. Si vous avez un
peu regardé les images fournies par enchant.js, vous avez certainement
remarqué que dans font0.png
, il y a des icônes pour chaque lettre
(ascii). Pour les utiliser facilement, on peut se servir de la classe
MutableText
. On donne en paramètre les coordonnées, ainsi que la
largeur de la zone :
var mt = new MutableText(100,0,120); mt.text = 'Are you ready?';
Le texte sera alors affiché avec les lettres du fichier font0.png
ce
qui fait un peu plus jeu vidéo.
Une sous-classe de MutableText
est ScoreLabel
. Elle permet
d’afficher… un score. Ce score est en fait composé d’une variable
label
— par défaut, "Score:"
— et d’un nombre, qui défile pour
atteindre la variable score
. Si on ne veut pas faire défiler le
score, il suffit de mettre la variable easing
à 0. Sinon, plus ce
nombre est grand, plus il défile doucement.
var sl = new ScoreLabel(20, 70); sl.label = 'Points: '; sl.easing = 5; game.rootScene.onenterframe = function(){ if (this.age % 50 ===0){ sl.score += 1000; }};
Dans le même genre, il y a la classe TimeLabel
qui affiche un
chronomètre, ou un compte à rebours :
var tl1 = new TimeLabel(0, 100); game.rootScene.addChild(tl1); var tl2 = new TimeLabel(0, 120, 'countdown'); tl2.label = 'Reste: '; tl2.time = 20; game.rootScene.addChild(tl2);
Là aussi le texte — par défaut à "Time:"
— peut être modifié.
La classe LifeLabel
permet d’afficher le nombre de cœurs. On précise
le nombre de cœur maximum au début, et quand on incrémente le
compteur, celui-ci ne dépassera pas ce maximum.
var ll = new LifeLabel(0, 150, 5); ll.label.text = 'Vie : '; ll.life = 3; game.rootScene.onenterframe = function(){ if (this.age % 50 ===0){ ll.life++; } }
Pas vraiment du texte pour cette dernière classe, mais elle est liée à
la LifeLabel
puisqu’elle permet d’afficher une barre de vie (ou
de points de magie, de l’expérience…) :
var bar = new Bar(10, 220); game.rootScene.addChild(bar); bar.maxvalue = 300; bar.value = bar.maxvalue; bar.ontouchstart = function(){ bar.value -= 50; }
On peut utiliser bar.image
pour changer l’image de la barre, la
direction de la barre avec bar.direction = 'left';
pour la faire
diminuer dans l’autre sens, et utiliser bar.easing
pour changer la
vitesse d’animation.
Toutes ces classes sont regroupés dans ce dernier exemple.
Autres plugins
Dans le dossier examples/plugins
d’enchant.js, il y a des exemples
pour ces deux plugins, ainsi que pour avatar
(animation d’avatar),
box2d
(pour la physique 2D), gl
(pour utiliser webgl, ce qui
permet entre autre de faire de la 3D), widget
(pour avoir des
boutons, menu de navigation, etc.) ou encore wiiu
(pour jouer sur
la Wii U). Mais ça, je vous laisse regarder par vous-même.