tag:linuxfr.org,2005:/tags/crafty/publicLinuxFr.org : les contenus étiquetés avec « crafty »2014-04-23T08:54:56+02:00/favicon.pngtag:linuxfr.org,2005:News/352342014-04-22T11:56:12+02:002014-04-22T11:56:11+02:00Petit jeu en HTML5 et découverte de CraftyLicence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<div><p>Rien de tel que de créer son propre jeu… à jouer dans le navigateur. Petite introduction au développement de jeux sur web avec le moteur <a href="http://craftyjs.com/">Crafty</a>.</p>
<p>C'est un moteur de jeu pour HTML5 écrit en javascript. Il fonctionne par entités et propose un rendu par DOM ou Canvas. Dans ce tutoriel, on va utiliser un rendu par DOM, qui est apparemment plus rapide que Canvas (c'est ce que dit la doc !). Nous allons donc nous servir de Crafty pour créer un petit tableau de jeu généré aléatoirement, et y déplacer un personnage, tout en gérant les collisions et animations du personnage et son environnement.</p>
<p><em>NdM : merci à etenil pour son journal.</em></p></div><ul><li>lien nᵒ 1 : <a title="http://linuxfr.org/users/etenil--2/journaux/petit-jeu-en-html5-et-decouverte-de-crafty" hreflang="fr" href="https://linuxfr.org/redirect/89943">Journal à l'origine de la dépêche</a></li><li>lien nᵒ 2 : <a title="http://craftyjs.com/" hreflang="en" href="https://linuxfr.org/redirect/89944">Le site de Crafty</a></li><li>lien nᵒ 3 : <a title="http://blog.etenil.net/static/crafty.zip" hreflang="fr" href="https://linuxfr.org/redirect/89945">Code du jeu</a></li><li>lien nᵒ 4 : <a title="http://blog.etenil.net/static/crafty/index.html" hreflang="xx" href="https://linuxfr.org/redirect/89946">Démo du jeu</a></li><li>lien nᵒ 5 : <a title="http://blog.etenil.net/static/crafty/index.html" hreflang="fr" href="https://linuxfr.org/redirect/89952">Jouer à Crafty</a></li></ul><div><h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li>
<a href="#programmer-des-jeux-vid%C3%A9o-avec-crafty">Programmer des jeux vidéo avec Crafty</a><ul>
<li><a href="#l%C3%A9cran-de-chargement">L'écran de chargement</a></li>
<li><a href="#planter-le-d%C3%A9cor">Planter le décor</a></li>
<li><a href="#premiers-pas">Premiers pas</a></li>
<li><a href="#collisions">Collisions</a></li>
<li><a href="#aller-plus-loin">Aller plus loin</a></li>
</ul>
</li>
</ul><h2 id="programmer-des-jeux-vidéo-avec-crafty">Programmer des jeux vidéo avec Crafty</h2>
<p>J'ai commencé à apprendre la programmation pour développer mes propres jeux vidéos. Beaucoup d'eau a coulé sous les ponts depuis et je me retrouve à développer surtout du web et des systèmes de base de données. Mon but initial de faire des jeux vidéos sombrant dans l'oubli…</p>
<p>J'ai donc choisi de renouveler mon intérêt pour le développement de jeux et de regarder du côté des technologies web. Leur promesse d'être utilisable sur tout support est séduisante et c'est aussi la seule manière de faire des jeux pour Firefox OS (mon téléphone).</p>
<p>Tout d'abord, trouver quelques sprites; c'est quand même plus intéressant à voir que des blocs colorés ! Une bonne ressource est <a href="http://opengameart.org/content/oga-16x16-jrpg-sprites-tiles">OpenGameArt.org</a>. J'en ai fait une petite sélection et y ai ajouté une fleur animée.</p>
<p><img src="//img.linuxfr.org/img/687474703a2f2f626c6f672e6574656e696c2e6e65742f7374617469632f696d616765732f776f726c642e706e67/world.png" alt="Sprites du monde" title="Source : http://blog.etenil.net/static/images/world.png"></p>
<p><img src="//img.linuxfr.org/img/687474703a2f2f626c6f672e6574656e696c2e6e65742f7374617469632f696d616765732f6368617261637465722e706e67/character.png" alt="Sprites du perso" title="Source : http://blog.etenil.net/static/images/character.png"></p>
<p>Vous pouvez récupérer <a href="http://blog.etenil.net/static/crafty.zip">le code du petit jeu</a>, ça vous évitera d'être perdu.</p>
<h3 id="lécran-de-chargement">L'écran de chargement</h3>
<p>Le fichier HTML qui va nous servir de base est pratiquement nu.</p>
<pre><code class="html"> <span class="cp"><!DOCTYPE html></span>
<span class="nt"><html></span>
<span class="nt"><head></span>
<span class="nt"><meta</span> <span class="na">charset=</span><span class="s">"utf-8"</span> <span class="nt">/></span>
<span class="nt"><script </span><span class="na">type=</span><span class="s">"text/javascript"</span> <span class="na">src=</span><span class="s">"https://raw.githubusercontent.com/craftyjs/Crafty/release/dist/crafty.js"</span><span class="nt">></script></span>
<span class="nt"><script </span><span class="na">type=</span><span class="s">"text/javascript"</span> <span class="na">src=</span><span class="s">"game.js"</span><span class="nt">></script></span>
<span class="nt"><style></span>
<span class="nt">body</span><span class="o">,</span> <span class="nt">html</span> <span class="p">{</span>
<span class="k">margin</span><span class="o">:</span> <span class="m">0</span><span class="p">;</span>
<span class="k">padding</span><span class="o">:</span> <span class="m">0</span><span class="p">;</span>
<span class="k">overflow</span><span class="o">:</span> <span class="k">hidden</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">#game</span> <span class="p">{</span>
<span class="k">margin</span><span class="o">:</span> <span class="m">100px</span> <span class="k">auto</span> <span class="m">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt"></style></span>
<span class="nt"><title></span>Crafty game test<span class="nt"></title></span>
<span class="nt"></head></span>
<span class="nt"><body></span>
<span class="nt"><div</span> <span class="na">id=</span><span class="s">"game"</span><span class="nt">></div></span>
<span class="nt"></body></span>
<span class="nt"></html></span></code></pre>
<p>Et voici la toute base de notre jeu, à mettre dans le fichier <em>game.js</em>.</p>
<pre><code class="javascript"> <span class="nb">window</span><span class="p">.</span><span class="nx">onload</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">game</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">'game'</span><span class="p">);</span>
<span class="nx">randRange</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">min</span><span class="p">,</span> <span class="nx">max</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">random</span><span class="p">()</span> <span class="o">*</span> <span class="p">(</span><span class="nx">max</span> <span class="o">-</span> <span class="nx">min</span> <span class="o">+</span> <span class="mi">1</span><span class="p">))</span> <span class="o">+</span> <span class="nx">min</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">init</span><span class="p">(</span><span class="mi">320</span><span class="p">,</span> <span class="mi">240</span><span class="p">,</span> <span class="nx">game</span><span class="p">);</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">sprite</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="s2">"world.png"</span><span class="p">,</span> <span class="p">{</span>
<span class="nx">grass1</span><span class="o">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">],</span>
<span class="nx">grass2</span><span class="o">:</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">],</span>
<span class="nx">grass3</span><span class="o">:</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span><span class="mi">0</span><span class="p">],</span>
<span class="nx">grass4</span><span class="o">:</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span><span class="mi">0</span><span class="p">],</span>
<span class="nx">flower</span><span class="o">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">],</span>
<span class="nx">bush1</span><span class="o">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">2</span><span class="p">],</span>
<span class="nx">bush2</span><span class="o">:</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">]</span>
<span class="p">});</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">sprite</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="mi">18</span><span class="p">,</span> <span class="s2">"character.png"</span><span class="p">,</span> <span class="p">{</span>
<span class="nx">player</span><span class="o">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">]</span>
<span class="p">});</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">scene</span><span class="p">(</span><span class="s2">"loading"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">load</span><span class="p">([</span><span class="s2">"world.png"</span><span class="p">,</span> <span class="s2">"character.png"</span><span class="p">],</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">scene</span><span class="p">(</span><span class="s1">'main'</span><span class="p">);</span>
<span class="p">});</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">background</span><span class="p">(</span><span class="s1">'#000'</span><span class="p">);</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, Text"</span><span class="p">)</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="mi">140</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="mi">120</span><span class="p">})</span>
<span class="p">.</span><span class="nx">text</span><span class="p">(</span><span class="s1">'Loading...'</span><span class="p">)</span>
<span class="p">.</span><span class="nx">css</span><span class="p">({</span><span class="s1">'text-align'</span><span class="o">:</span> <span class="s1">'center'</span><span class="p">,</span> <span class="s1">'color'</span><span class="o">:</span> <span class="s1">'#FFF'</span><span class="p">});</span>
<span class="p">});</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">scene</span><span class="p">(</span><span class="s1">'loading'</span><span class="p">);</span>
<span class="p">}</span></code></pre>
<p>La première chose qu'on fait ici, c'est initialiser le moteur Crafty. Pour cela, on lance <code>Crafty.init()</code> en définissant la taille de la zone de jeu (320x240), ainsi que la zone de jeu elle-même (le div <code>#game</code>).</p>
<p>On définit ensuite les sprites. Les sprites se gèrent très facilement dans Crafty; il suffit d'indiquer le fichier de sprites, puis l'index de chaque sprite dans l'objet de mapping. ici <code>grass2</code> est situé à x=1 et y=0, c'est-à-dire 16px vers la droite, et collé au haut de l'image.</p>
<p>Les sprites de personnages sont un peu différents car ceux-ci sont plus hauts que larges (16x18). Une fois définis, on pourra invoquer les sprites par leur petit nom directement, simplifiant ainsi les opérations. Notez que les sprites d'animation ne sont définis que par une seule image pour le moment, leur état neutre (voir <code>player</code>).</p>
<p>Crafty utilise le concept de scène. Ici on a défini la scène de chargement, qui s'affiche jusqu'à ce que les objets nécessaires à la scène suivante soient chargés. Vous ne le verrez peut-être pas car c'est très court, mais le texte <em>loading…</em> devrait apparaitre brièvement sur un écran noir. La scène suivante <code>main</code> n'a pour l'instant pas été déclarée, conduisant à un écran noir.</p>
<p>Il est temps de passer à la scène principale.</p>
<h3 id="planter-le-décor">Planter le décor</h3>
<p>La zone de jeu va être générée en grande partie aléatoirement. Le sol sera tapissé de carrés d'herbe aléatoires, quelques buissons et fleurs animées. Les bords de l'écran seront quant à eux délimités par des buissons. Enfin notre personnage sera au milieu la zone de jeu.</p>
<p>On va définir empiriquement qu'il y a 1 chance sur 50 d'avoir une fleur sur un carré de sol, et 1 chance sur 25 de trouver un buisson aléatoire. Il sera aisé plus tard d'ajuster ces valeurs si besoin.</p>
<p>Je vous livre la fonction de génération de monde :</p>
<pre><code class="javascript"> <span class="c1">// Method to randomy generate the map</span>
<span class="kd">function</span> <span class="nx">generateWorld</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// Generate the grass along the x-axis</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o"><</span> <span class="mi">20</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Generate the grass along the y-axis</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">j</span> <span class="o"><</span> <span class="mi">15</span><span class="p">;</span> <span class="nx">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">grassType</span> <span class="o">=</span> <span class="nx">randRange</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, grass"</span> <span class="o">+</span> <span class="nx">grassType</span><span class="p">)</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="nx">i</span> <span class="o">*</span> <span class="mi">16</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="nx">j</span> <span class="o">*</span> <span class="mi">16</span><span class="p">});</span>
<span class="c1">// 1/50 chance of drawing a flower.</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">i</span> <span class="o">></span> <span class="mi">0</span> <span class="o">&&</span> <span class="nx">i</span> <span class="o"><</span> <span class="mi">19</span> <span class="o">&&</span> <span class="nx">j</span> <span class="o">></span> <span class="mi">0</span> <span class="o">&&</span> <span class="nx">j</span> <span class="o"><</span> <span class="mi">14</span> <span class="o">&&</span> <span class="nx">randRange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">50</span><span class="p">)</span> <span class="o">></span> <span class="mi">49</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">flower</span> <span class="o">=</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, SpriteAnimation, flower"</span><span class="p">)</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="nx">i</span> <span class="o">*</span> <span class="mi">16</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="nx">j</span> <span class="o">*</span> <span class="mi">16</span><span class="p">})</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"wind"</span><span class="p">,</span> <span class="mi">1000</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="p">.</span><span class="nx">animate</span><span class="p">(</span><span class="s2">"wind"</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span>
<span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="s2">"enterframe"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">isPlaying</span><span class="p">())</span>
<span class="k">this</span><span class="p">.</span><span class="nx">animate</span><span class="p">(</span><span class="s2">"wind"</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="c1">// 1/25 chance of drawing a bush.</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">i</span> <span class="o">></span> <span class="mi">0</span> <span class="o">&&</span> <span class="nx">i</span> <span class="o"><</span> <span class="mi">19</span> <span class="o">&&</span> <span class="nx">j</span> <span class="o">></span> <span class="mi">0</span> <span class="o">&&</span> <span class="nx">j</span> <span class="o"><</span> <span class="mi">14</span> <span class="o">&&</span> <span class="nx">randRange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">25</span><span class="p">)</span> <span class="o">></span> <span class="mi">24</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">bush</span> <span class="o">=</span> <span class="nx">Crafty</span>
<span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, randbushes, bush"</span><span class="o">+</span><span class="nx">randRange</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">))</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="nx">i</span> <span class="o">*</span> <span class="mi">16</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="nx">j</span> <span class="o">*</span> <span class="mi">16</span><span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">// Create the bushes along the x-axis which will form the boundaries</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o"><</span> <span class="mi">20</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, wall_top, bush"</span><span class="o">+</span><span class="nx">randRange</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">))</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="nx">i</span> <span class="o">*</span> <span class="mi">16</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">z</span><span class="o">:</span> <span class="mi">2</span><span class="p">});</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, wall_bottom, bush"</span><span class="o">+</span><span class="nx">randRange</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">))</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="nx">i</span> <span class="o">*</span> <span class="mi">16</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="mi">224</span><span class="p">,</span> <span class="nx">z</span><span class="o">:</span> <span class="mi">2</span><span class="p">});</span>
<span class="p">}</span>
<span class="c1">// Create the bushes along the y-axis</span>
<span class="c1">// We need to start one more and one less to not overlap the previous bushes</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">i</span> <span class="o"><</span> <span class="mi">15</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, wall_left, bush"</span> <span class="o">+</span> <span class="nx">randRange</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">))</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="nx">i</span> <span class="o">*</span> <span class="mi">16</span><span class="p">,</span> <span class="nx">z</span><span class="o">:</span> <span class="mi">2</span><span class="p">});</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, wall_right, bush"</span> <span class="o">+</span> <span class="nx">randRange</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">))</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="mi">304</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="nx">i</span> <span class="o">*</span> <span class="mi">16</span><span class="p">,</span> <span class="nx">z</span><span class="o">:</span> <span class="mi">2</span><span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span></code></pre>
<p>Passons à la déclaration de la scène principale.</p>
<pre><code class="javascript"> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">scene</span><span class="p">(</span><span class="s2">"main"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">generateWorld</span><span class="p">();</span>
<span class="c1">// Create our player entity with some premade components</span>
<span class="kd">var</span> <span class="nx">player</span> <span class="o">=</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, player, controls"</span><span class="p">)</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="mi">152</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="mi">111</span><span class="p">,</span> <span class="nx">z</span><span class="o">:</span> <span class="mi">1</span><span class="p">})</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_left"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_right"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_up"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_down"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
<span class="p">});</span></code></pre>
<p>Ici, on génère le monde aléatoirement, puis on place notre personnage principal en plein milieu de la zone de jeu. Les appels <code>.reel()</code> définissent les animations du personnage par rapport à l'arrangement des sprites. Les paramètres de <code>.reel()</code> sont le nom de l'animation, sa durée en ms, la position <em>x</em> du sprite de départ, la position <em>y</em> du sprite de départ, puis la longueur de l'animation en nombre de sprites (vers la droite).</p>
<p>Pour l'instant le personnage est immobile, et les animations n'ont aucun effet. Nous allons remédier à cela.</p>
<h3 id="premiers-pas">Premiers pas</h3>
<p>Crafty fournit deux contrôles de base. L'un permet d'aller à droite ou gauche et sauter, l'autre de se déplacer dans les quatre directions. Ce n'est pas très satisfaisant, nous allons définir nos propres contrôles qui permettront aussi des diagonales.</p>
<p>Juste après la ligne <code>generateWorld();</code>, mettez le code suivant:</p>
<pre><code class="javascript"> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">c</span><span class="p">(</span><span class="s1">'CustomControls'</span><span class="p">,</span> <span class="p">{</span>
<span class="nx">__move</span><span class="o">:</span> <span class="p">{</span><span class="nx">left</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span> <span class="nx">right</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span> <span class="nx">up</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span> <span class="nx">down</span><span class="o">:</span> <span class="kc">false</span><span class="p">},</span>
<span class="nx">_speed</span><span class="o">:</span> <span class="mi">3</span><span class="p">,</span>
<span class="nx">CustomControls</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">speed</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">speed</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span> <span class="o">=</span> <span class="nx">speed</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">move</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="s1">'EnterFrame'</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// Move the player in a direction depending on the booleans</span>
<span class="c1">// Only move the player in one direction at a time (up/down/left/right)</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">move</span><span class="p">.</span><span class="nx">right</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">x</span> <span class="o">+=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">move</span><span class="p">.</span><span class="nx">left</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">x</span> <span class="o">-=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">move</span><span class="p">.</span><span class="nx">up</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">y</span> <span class="o">-=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">move</span><span class="p">.</span><span class="nx">down</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">y</span> <span class="o">+=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="p">});</span>
<span class="k">this</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="s1">'KeyDown'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Default movement booleans to false</span>
<span class="nx">move</span><span class="p">.</span><span class="nx">right</span> <span class="o">=</span> <span class="nx">move</span><span class="p">.</span><span class="nx">left</span> <span class="o">=</span> <span class="nx">move</span><span class="p">.</span><span class="nx">down</span> <span class="o">=</span> <span class="nx">move</span><span class="p">.</span><span class="nx">up</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="c1">// If keys are down, set the direction</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">===</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">keys</span><span class="p">.</span><span class="nx">RIGHT_ARROW</span><span class="p">)</span> <span class="nx">move</span><span class="p">.</span><span class="nx">right</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">===</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">keys</span><span class="p">.</span><span class="nx">LEFT_ARROW</span><span class="p">)</span> <span class="nx">move</span><span class="p">.</span><span class="nx">left</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">===</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">keys</span><span class="p">.</span><span class="nx">UP_ARROW</span><span class="p">)</span> <span class="nx">move</span><span class="p">.</span><span class="nx">up</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">===</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">keys</span><span class="p">.</span><span class="nx">DOWN_ARROW</span><span class="p">)</span> <span class="nx">move</span><span class="p">.</span><span class="nx">down</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">});</span>
<span class="k">this</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="s1">'KeyUp'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// If key is released, stop moving</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">===</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">keys</span><span class="p">.</span><span class="nx">RIGHT_ARROW</span><span class="p">)</span> <span class="nx">move</span><span class="p">.</span><span class="nx">right</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">===</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">keys</span><span class="p">.</span><span class="nx">LEFT_ARROW</span><span class="p">)</span> <span class="nx">move</span><span class="p">.</span><span class="nx">left</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">===</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">keys</span><span class="p">.</span><span class="nx">UP_ARROW</span><span class="p">)</span> <span class="nx">move</span><span class="p">.</span><span class="nx">up</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">===</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">keys</span><span class="p">.</span><span class="nx">DOWN_ARROW</span><span class="p">)</span> <span class="nx">move</span><span class="p">.</span><span class="nx">down</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="p">});</span>
<span class="k">return</span> <span class="k">this</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">});</span></code></pre>
<p>Voici notre code de contrôle. La logique est assez simple, à chaque appui sur un bouton, on regarde l'état des touches fléchées pour déterminer les directions du mouvement en une combinaison de gauche, droite, bas et haut. Une fois le mouvement défini dans <code>__move</code>, crafty déplacera l'entité de <code>_speed</code> pixels dans les directions données lors du rafraîchissement d'écran.</p>
<p>On va maintenant modifier la déclaration du personnage pour le faire se déplacer, et animer son mouvement.</p>
<pre><code class="javascript"> <span class="kd">var</span> <span class="nx">player</span> <span class="o">=</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, player, controls, CustomControls, SpriteAnimation"</span><span class="p">)</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="mi">160</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="mi">144</span><span class="p">,</span> <span class="nx">z</span><span class="o">:</span> <span class="mi">1</span><span class="p">})</span>
<span class="p">.</span><span class="nx">CustomControls</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_left"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_right"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_up"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_down"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="s2">"EnterFrame"</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">left</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">isPlaying</span><span class="p">(</span><span class="s2">"walk_left"</span><span class="p">))</span>
<span class="k">this</span><span class="p">.</span><span class="nx">animate</span><span class="p">(</span><span class="s2">"walk_left"</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">right</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">isPlaying</span><span class="p">(</span><span class="s2">"walk_right"</span><span class="p">))</span>
<span class="k">this</span><span class="p">.</span><span class="nx">animate</span><span class="p">(</span><span class="s2">"walk_right"</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">up</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">isPlaying</span><span class="p">(</span><span class="s2">"walk_up"</span><span class="p">))</span>
<span class="k">this</span><span class="p">.</span><span class="nx">animate</span><span class="p">(</span><span class="s2">"walk_up"</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">down</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">isPlaying</span><span class="p">(</span><span class="s2">"walk_down"</span><span class="p">))</span>
<span class="k">this</span><span class="p">.</span><span class="nx">animate</span><span class="p">(</span><span class="s2">"walk_down"</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">})</span>
<span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="s2">"KeyUp"</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">pauseAnimation</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">resetAnimation</span><span class="p">();</span>
<span class="p">});</span></code></pre>
<p>Notez la déclaration de <em>CustomControls</em> comme méthode controle, et la vitesse d'1px/image. Pour gérer les animations, on se greffe sur l'évènement <em>EnterFrame</em>, et on détermine l'animation à jouer par rapport à la direction de mouvement du personnage. Quand une touche est relachée, on arrête et rembobine l'animation pour revenir en position neutre (évènement <em>KeyUp</em>).</p>
<p>À présent, le personnage devrait évoluer gaillardement sur votre écran, et passer allègrement à travers les buissons et hors de la zone de jeu…</p>
<h3 id="collisions">Collisions</h3>
<p>Il est temps de passer à la gestion des collisions. On va faire très simple et ne pas définir de hitbox. Crafty utilisera alors les sprites eux-mêmes comme hitbox. Pas terrible, mais simple.</p>
<p>On va aussi ne s'occuper que des collisions entre le joueur et les buissons (quels qu'ils soient). Ça évitera au perso de sortir de la zone de jeu et le forcera à éviter les buissons dans l'herbe.</p>
<p>Modifiez la déclaration du joueur comme suit :</p>
<pre><code class="javascript"> <span class="kd">var</span> <span class="nx">player</span> <span class="o">=</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, player, controls, CustomControls, SpriteAnimation, Collision"</span><span class="p">)</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="mi">160</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="mi">144</span><span class="p">,</span> <span class="nx">z</span><span class="o">:</span> <span class="mi">1</span><span class="p">})</span>
<span class="p">.</span><span class="nx">CustomControls</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_left"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_right"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_up"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_down"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="s2">"EnterFrame"</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">left</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">isPlaying</span><span class="p">(</span><span class="s2">"walk_left"</span><span class="p">))</span>
<span class="k">this</span><span class="p">.</span><span class="nx">animate</span><span class="p">(</span><span class="s2">"walk_left"</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">right</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">isPlaying</span><span class="p">(</span><span class="s2">"walk_right"</span><span class="p">))</span>
<span class="k">this</span><span class="p">.</span><span class="nx">animate</span><span class="p">(</span><span class="s2">"walk_right"</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">up</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">isPlaying</span><span class="p">(</span><span class="s2">"walk_up"</span><span class="p">))</span>
<span class="k">this</span><span class="p">.</span><span class="nx">animate</span><span class="p">(</span><span class="s2">"walk_up"</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">down</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">isPlaying</span><span class="p">(</span><span class="s2">"walk_down"</span><span class="p">))</span>
<span class="k">this</span><span class="p">.</span><span class="nx">animate</span><span class="p">(</span><span class="s2">"walk_down"</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">})</span>
<span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="s2">"KeyUp"</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">pauseAnimation</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">resetAnimation</span><span class="p">();</span>
<span class="p">})</span>
<span class="p">.</span><span class="nx">collision</span><span class="p">()</span>
<span class="p">.</span><span class="nx">onHit</span><span class="p">(</span><span class="s2">"wall_left"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">x</span> <span class="o">+=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">pauseAnimation</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">resetAnimation</span><span class="p">();</span>
<span class="p">})</span>
<span class="p">.</span><span class="nx">onHit</span><span class="p">(</span><span class="s2">"wall_right"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">x</span> <span class="o">-=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">pauseAnimation</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">resetAnimation</span><span class="p">();</span>
<span class="p">})</span>
<span class="p">.</span><span class="nx">onHit</span><span class="p">(</span><span class="s2">"wall_bottom"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">y</span> <span class="o">-=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">pauseAnimation</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">resetAnimation</span><span class="p">();</span>
<span class="p">})</span>
<span class="p">.</span><span class="nx">onHit</span><span class="p">(</span><span class="s2">"wall_top"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">y</span> <span class="o">+=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">pauseAnimation</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">resetAnimation</span><span class="p">();</span>
<span class="p">})</span>
<span class="p">.</span><span class="nx">onHit</span><span class="p">(</span><span class="s2">"randbushes"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">left</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">x</span> <span class="o">+=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">right</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">x</span> <span class="o">-=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">up</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">y</span> <span class="o">+=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">down</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">y</span> <span class="o">-=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">pauseAnimation</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">resetAnimation</span><span class="p">();</span>
<span class="p">});</span></code></pre>
<p>Après avoir déclaré l'utilisation du module <em>Collision</em>, on l'initialise avec <code>collision()</code>. Ensuite il suffit de gérer l'évènement <code>onHit</code> sur les objets intéressants.</p>
<p>Les évènements de collisions sont résolus après le mouvement, mais avant le rendu. C'est pour cela qu'on fait reculer le personnage d'un pas (enfin, de <code>_speed</code>) lors de la détection d'une collision. Du point de vue du joueur, le personnage restera parfaitement immobile.</p>
<p>On pourrait bien entendu faire autre chose lors de la collision, comme lancer un combat, ou envoyer un bonus tout en laissant le personnage passer dans le buisson. Les possibilités sont infinies !</p>
<h3 id="aller-plus-loin">Aller plus loin</h3>
<p>C'est donc une toute base de jeu, mais sans logique. On peut déjà améliorer le code sur beaucoup de points. Vous pourrez vous plonger dans la <a href="http://craftyjs.com/api/events.html">documentation de Crafty</a> pour vous y atteler.</p>
<p>On peut s'assurer que les buissons n'apparaissent pas sur des fleurs, et que le joueur n'apparaît pas sur des buissons.</p>
<p>L'algorithme de génération du monde peut être largement amélioré pour grouper les types d'herbe et faire des zones herbues et d'autres moins. On pourra introduire d'autres types de sprites pour avoir un terrain un peu plus intéressant. Avec de gros sprites, on peut aussi introduire des éléments de décor comme des maisons, ou même des PNJ.</p>
<p>Les hitbox des entités sont très maladroites. Il serait bien plus élégant de définir des hitbox sur les pieds du personnage et la base des buissons, afin de pouvoir passer derrière les éléments (il faudra aussi gérer l'axe <em>Z</em> des sprites pour le rendu !).</p>
<p>En faisant des zones de sortie dans les buissons sur les rebords, on pourra lier d'autres tableaux, générés de façon procédurale eux aussi. Voire même générer plusieurs zones contigües à la fois et maintenir une structure de données pour que le jeu reste homogène.</p>
<p>Et bien plus encore, autant que votre créativité permet !</p></div><div><a href="https://linuxfr.org/news/petit-jeu-en-html5-et-decouverte-de-crafty.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/101743/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/news/petit-jeu-en-html5-et-decouverte-de-crafty#comments">ouvrir dans le navigateur</a>
</p>
etenilBAudBenoît SibaudNÿcopalm123ZeroHeureNeoXhttps://linuxfr.org/nodes/101743/comments.atomtag:linuxfr.org,2005:Diary/348462014-04-01T00:20:44+02:002014-04-01T00:20:44+02:00Petit jeu en HTML5 et découverte de CraftyLicence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li>
<a href="#programmer-des-jeux-vid%C3%A9o-avec-crafty">Programmer des jeux vidéo avec Crafty</a><ul>
<li><a href="#l%C3%A9cran-de-chargement">L'écran de chargement</a></li>
<li><a href="#planter-le-d%C3%A9cor">Planter le décor</a></li>
<li><a href="#premiers-pas">Premiers pas</a></li>
<li><a href="#collisions">Collisions</a></li>
<li><a href="#aller-plus-loin">Aller plus loin</a></li>
</ul>
</li>
</ul><h2 id="programmer-des-jeux-vidéo-avec-crafty">Programmer des jeux vidéo avec Crafty</h2>
<p>J'ai commencé à apprendre la programmation pour développer mes propres jeux vidéos. Beaucoup d'eau a coulé sous les ponts depuis et je me retrouve à développer surtout du web et des systèmes de base de données. Mon but initial de faire des jeux vidéos sombrant dans l'oubli…</p>
<p>J'ai donc choisi de renouveler mon intérêt pour le développement de jeux et de regarder du côté des technologies web. Leur promesse d'être utilisable sur tous support est séduisante et c'est aussi la seule manière de faire des jeux pour Firefox OS (mon téléphone).</p>
<p><a href="http://craftyjs.com/">Crafty</a> est un moteur de jeu pour HTML5 écrit en javascript. Il fonctionne par entités et propose un rendu par DOM ou Canvas. Dans ce tuto, on va utiliser un rendu par DOM, qui est apparemment plus rapide que canvas (c'est ce que dit la doc!). Nous allons donc nous servir de Crafty pour créer un petit tableau de jeu généré aléatoirement, et y déplacer un personnage, tout en gérant les collisions et animations du personnage et son environnement.</p>
<p>Tout d'abord, trouver quelques sprites; c'est quand même plus intéressant à voir que des blocs colorés! Une bonne ressource est <a href="http://opengameart.org/content/oga-16x16-jrpg-sprites-tiles">OpenGameArt.org</a>. J'en ai fait une petite sélection et y ai ajouté une fleur animée.</p>
<p><img src="//img.linuxfr.org/img/687474703a2f2f626c6f672e6574656e696c2e6e65742f7374617469632f696d616765732f776f726c642e706e67/world.png" alt="Sprites du monde" title="Source : http://blog.etenil.net/static/images/world.png"></p>
<p><img src="//img.linuxfr.org/img/687474703a2f2f626c6f672e6574656e696c2e6e65742f7374617469632f696d616765732f6368617261637465722e706e67/character.png" alt="Sprites du perso" title="Source : http://blog.etenil.net/static/images/character.png"></p>
<p>Vous pouvez récupérer <a href="http://blog.etenil.net/static/crafty.zip">le code du petit jeu</a>, ça vous évitera d'être perdu.</p>
<h3 id="lécran-de-chargement">L'écran de chargement</h3>
<p>Le fichier HTML qui va nous servir de base est pratiquement nu.</p>
<pre><code class="html"> <span class="cp"><!DOCTYPE html></span>
<span class="nt"><html></span>
<span class="nt"><head></span>
<span class="nt"><meta</span> <span class="na">charset=</span><span class="s">"utf-8"</span> <span class="nt">/></span>
<span class="nt"><script </span><span class="na">type=</span><span class="s">"text/javascript"</span> <span class="na">src=</span><span class="s">"https://raw.githubusercontent.com/craftyjs/Crafty/release/dist/crafty.js"</span><span class="nt">></script></span>
<span class="nt"><script </span><span class="na">type=</span><span class="s">"text/javascript"</span> <span class="na">src=</span><span class="s">"game.js"</span><span class="nt">></script></span>
<span class="nt"><style></span>
<span class="nt">body</span><span class="o">,</span> <span class="nt">html</span> <span class="p">{</span>
<span class="k">margin</span><span class="o">:</span> <span class="m">0</span><span class="p">;</span>
<span class="k">padding</span><span class="o">:</span> <span class="m">0</span><span class="p">;</span>
<span class="k">overflow</span><span class="o">:</span> <span class="k">hidden</span><span class="p">;</span>
<span class="p">}</span>
<span class="nf">#game</span> <span class="p">{</span>
<span class="k">margin</span><span class="o">:</span> <span class="m">100px</span> <span class="k">auto</span> <span class="m">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="nt"></style></span>
<span class="nt"><title></span>Crafty game test<span class="nt"></title></span>
<span class="nt"></head></span>
<span class="nt"><body></span>
<span class="nt"><div</span> <span class="na">id=</span><span class="s">"game"</span><span class="nt">></div></span>
<span class="nt"></body></span>
<span class="nt"></html></span></code></pre>
<p>Et voici la toute base de notre jeu, à mettre dans le fichier <em>game.js</em>.</p>
<pre><code class="javascript"> <span class="nb">window</span><span class="p">.</span><span class="nx">onload</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">game</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s1">'game'</span><span class="p">);</span>
<span class="nx">randRange</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">min</span><span class="p">,</span> <span class="nx">max</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">random</span><span class="p">()</span> <span class="o">*</span> <span class="p">(</span><span class="nx">max</span> <span class="o">-</span> <span class="nx">min</span> <span class="o">+</span> <span class="mi">1</span><span class="p">))</span> <span class="o">+</span> <span class="nx">min</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">init</span><span class="p">(</span><span class="mi">320</span><span class="p">,</span> <span class="mi">240</span><span class="p">,</span> <span class="nx">game</span><span class="p">);</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">sprite</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="s2">"world.png"</span><span class="p">,</span> <span class="p">{</span>
<span class="nx">grass1</span><span class="o">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">],</span>
<span class="nx">grass2</span><span class="o">:</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">],</span>
<span class="nx">grass3</span><span class="o">:</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span><span class="mi">0</span><span class="p">],</span>
<span class="nx">grass4</span><span class="o">:</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span><span class="mi">0</span><span class="p">],</span>
<span class="nx">flower</span><span class="o">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">],</span>
<span class="nx">bush1</span><span class="o">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">2</span><span class="p">],</span>
<span class="nx">bush2</span><span class="o">:</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">]</span>
<span class="p">});</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">sprite</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span> <span class="mi">18</span><span class="p">,</span> <span class="s2">"character.png"</span><span class="p">,</span> <span class="p">{</span>
<span class="nx">player</span><span class="o">:</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">]</span>
<span class="p">});</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">scene</span><span class="p">(</span><span class="s2">"loading"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">load</span><span class="p">([</span><span class="s2">"world.png"</span><span class="p">,</span> <span class="s2">"character.png"</span><span class="p">],</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">scene</span><span class="p">(</span><span class="s1">'main'</span><span class="p">);</span>
<span class="p">});</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">background</span><span class="p">(</span><span class="s1">'#000'</span><span class="p">);</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, Text"</span><span class="p">)</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="mi">140</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="mi">120</span><span class="p">})</span>
<span class="p">.</span><span class="nx">text</span><span class="p">(</span><span class="s1">'Loading...'</span><span class="p">)</span>
<span class="p">.</span><span class="nx">css</span><span class="p">({</span><span class="s1">'text-align'</span><span class="o">:</span> <span class="s1">'center'</span><span class="p">,</span> <span class="s1">'color'</span><span class="o">:</span> <span class="s1">'#FFF'</span><span class="p">});</span>
<span class="p">});</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">scene</span><span class="p">(</span><span class="s1">'loading'</span><span class="p">);</span>
<span class="p">}</span></code></pre>
<p>La première chose qu'on fait ici, c'est initialiser le moteur Crafty. Pour cela, on lance <code>Crafty.init()</code> en définissant la taille de la zone de jeu (320x240), ainsi que la zone de jeu elle-même (le div <code>#game</code>).</p>
<p>On définit ensuite les sprites. Les sprites se gèrent très facilement dans Crafty; il suffit d'indiquer le fichier de sprites, puis l'index de chaque sprite dans l'objet de mapping. ici <code>grass2</code> est situé à x=1 et y=0, c'est à dire 16px vers la droite, et collé au haut de l'image.</p>
<p>Les sprites de personnages sont un peu différents car ceux-ci sont plus hauts que larges (16x18). Une fois définis, on pourra invoquer les sprites par leur petit nom directement, simplifiant ainsi les opérations. Notez que les sprites d'animation ne sont définis que par une seule image pour le moment, leur état neutre (voir <code>player</code>).</p>
<p>Crafty utilise le concept de scène. Ici on a définit la scène de chargement, qui s'affiche jusqu'à ce que les objets nécessaires à la scène suivante soient chargés. Vous ne le verrez peut être pas car c'est très court, mais le texte <em>loading…</em> devrait apparaitre brièvement sur un écran noir. La scène suivante <code>main</code> n'a pour l'instant pas été déclarée, conduisant à un écran noir.</p>
<p>Il est temps de passer à la scène principale.</p>
<h3 id="planter-le-décor">Planter le décor</h3>
<p>La zone de jeu va être en générée aléatoirement en grande partie. Le sol sera tapissé de carrés d'herbe aléatoires, quelques buissons et fleurs animées. Les bords de l'écran seront quant à eux délimités par des buissons. Enfin notre personnage sera au milieu la zone de jeu.</p>
<p>On va définir empiriquement qu'il y a 1/50 d'avoir une fleur sur un carré de sol, et 1/25 chance de trouver un buisson aléatoire. Il sera aisé plus tard d'ajuster ces valeurs si besoin.</p>
<p>Je vous livre la fonction de génération de monde:</p>
<pre><code class="javascript"> <span class="c1">// Method to randomy generate the map</span>
<span class="kd">function</span> <span class="nx">generateWorld</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// Generate the grass along the x-axis</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o"><</span> <span class="mi">20</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Generate the grass along the y-axis</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">j</span> <span class="o"><</span> <span class="mi">15</span><span class="p">;</span> <span class="nx">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">grassType</span> <span class="o">=</span> <span class="nx">randRange</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, grass"</span> <span class="o">+</span> <span class="nx">grassType</span><span class="p">)</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="nx">i</span> <span class="o">*</span> <span class="mi">16</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="nx">j</span> <span class="o">*</span> <span class="mi">16</span><span class="p">});</span>
<span class="c1">// 1/50 chance of drawing a flower.</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">i</span> <span class="o">></span> <span class="mi">0</span> <span class="o">&&</span> <span class="nx">i</span> <span class="o"><</span> <span class="mi">19</span> <span class="o">&&</span> <span class="nx">j</span> <span class="o">></span> <span class="mi">0</span> <span class="o">&&</span> <span class="nx">j</span> <span class="o"><</span> <span class="mi">14</span> <span class="o">&&</span> <span class="nx">randRange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">50</span><span class="p">)</span> <span class="o">></span> <span class="mi">49</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">flower</span> <span class="o">=</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, SpriteAnimation, flower"</span><span class="p">)</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="nx">i</span> <span class="o">*</span> <span class="mi">16</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="nx">j</span> <span class="o">*</span> <span class="mi">16</span><span class="p">})</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"wind"</span><span class="p">,</span> <span class="mi">1000</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="p">.</span><span class="nx">animate</span><span class="p">(</span><span class="s2">"wind"</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span>
<span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="s2">"enterframe"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">isPlaying</span><span class="p">())</span>
<span class="k">this</span><span class="p">.</span><span class="nx">animate</span><span class="p">(</span><span class="s2">"wind"</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="c1">// 1/25 chance of drawing a bush.</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">i</span> <span class="o">></span> <span class="mi">0</span> <span class="o">&&</span> <span class="nx">i</span> <span class="o"><</span> <span class="mi">19</span> <span class="o">&&</span> <span class="nx">j</span> <span class="o">></span> <span class="mi">0</span> <span class="o">&&</span> <span class="nx">j</span> <span class="o"><</span> <span class="mi">14</span> <span class="o">&&</span> <span class="nx">randRange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">25</span><span class="p">)</span> <span class="o">></span> <span class="mi">24</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">bush</span> <span class="o">=</span> <span class="nx">Crafty</span>
<span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, randbushes, bush"</span><span class="o">+</span><span class="nx">randRange</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">))</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="nx">i</span> <span class="o">*</span> <span class="mi">16</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="nx">j</span> <span class="o">*</span> <span class="mi">16</span><span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">// Create the bushes along the x-axis which will form the boundaries</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o"><</span> <span class="mi">20</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, wall_top, bush"</span><span class="o">+</span><span class="nx">randRange</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">))</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="nx">i</span> <span class="o">*</span> <span class="mi">16</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">z</span><span class="o">:</span> <span class="mi">2</span><span class="p">});</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, wall_bottom, bush"</span><span class="o">+</span><span class="nx">randRange</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">))</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="nx">i</span> <span class="o">*</span> <span class="mi">16</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="mi">224</span><span class="p">,</span> <span class="nx">z</span><span class="o">:</span> <span class="mi">2</span><span class="p">});</span>
<span class="p">}</span>
<span class="c1">// Create the bushes along the y-axis</span>
<span class="c1">// We need to start one more and one less to not overlap the previous bushes</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">i</span> <span class="o"><</span> <span class="mi">15</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, wall_left, bush"</span> <span class="o">+</span> <span class="nx">randRange</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">))</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="nx">i</span> <span class="o">*</span> <span class="mi">16</span><span class="p">,</span> <span class="nx">z</span><span class="o">:</span> <span class="mi">2</span><span class="p">});</span>
<span class="nx">Crafty</span><span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, wall_right, bush"</span> <span class="o">+</span> <span class="nx">randRange</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">))</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="mi">304</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="nx">i</span> <span class="o">*</span> <span class="mi">16</span><span class="p">,</span> <span class="nx">z</span><span class="o">:</span> <span class="mi">2</span><span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span></code></pre>
<p>Passons à la déclaration de la scène principale.</p>
<pre><code class="javascript"> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">scene</span><span class="p">(</span><span class="s2">"main"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">generateWorld</span><span class="p">();</span>
<span class="c1">// Create our player entity with some premade components</span>
<span class="kd">var</span> <span class="nx">player</span> <span class="o">=</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, player, controls"</span><span class="p">)</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="mi">152</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="mi">111</span><span class="p">,</span> <span class="nx">z</span><span class="o">:</span> <span class="mi">1</span><span class="p">})</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_left"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_right"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_up"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_down"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
<span class="p">});</span></code></pre>
<p>Ici, on génère le monde aléatoirement, puis on place notre personnage principal en plein milieu de la zone de jeu. Les appels <code>.reel()</code> définissent les animations du personnage par rapport à l'arrangement des sprites. Les paramètres de <code>.reel()</code> sont le nom de l'animation, sa durée en ms, la position x du sprite de départ, la position y du sprite de départ, puis la longueur de l'animation en nombre de sprites (vers la droite).</p>
<p>Pour l'instant le personnage est immobile, et les animations n'ont aucun effet. Nous allons remédier ça.</p>
<h3 id="premiers-pas">Premiers pas</h3>
<p>Crafty fournit deux contrôles de base. L'un permet d'aller à droite ou gauche et sauter, l'autre de se déplacer dans les quatre directions. Ce n'est pas très satisfaisant, nous allons définir nos propres contrôles qui permettront aussi des diagonales.</p>
<p>Juste après la ligne <code>generateWorld();</code>, mettez le code suivant:</p>
<pre><code class="javascript"> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">c</span><span class="p">(</span><span class="s1">'CustomControls'</span><span class="p">,</span> <span class="p">{</span>
<span class="nx">__move</span><span class="o">:</span> <span class="p">{</span><span class="nx">left</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span> <span class="nx">right</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span> <span class="nx">up</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span> <span class="nx">down</span><span class="o">:</span> <span class="kc">false</span><span class="p">},</span>
<span class="nx">_speed</span><span class="o">:</span> <span class="mi">3</span><span class="p">,</span>
<span class="nx">CustomControls</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">speed</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">speed</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span> <span class="o">=</span> <span class="nx">speed</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">move</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="s1">'EnterFrame'</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// Move the player in a direction depending on the booleans</span>
<span class="c1">// Only move the player in one direction at a time (up/down/left/right)</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">move</span><span class="p">.</span><span class="nx">right</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">x</span> <span class="o">+=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">move</span><span class="p">.</span><span class="nx">left</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">x</span> <span class="o">-=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">move</span><span class="p">.</span><span class="nx">up</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">y</span> <span class="o">-=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">move</span><span class="p">.</span><span class="nx">down</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">y</span> <span class="o">+=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="p">});</span>
<span class="k">this</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="s1">'KeyDown'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Default movement booleans to false</span>
<span class="nx">move</span><span class="p">.</span><span class="nx">right</span> <span class="o">=</span> <span class="nx">move</span><span class="p">.</span><span class="nx">left</span> <span class="o">=</span> <span class="nx">move</span><span class="p">.</span><span class="nx">down</span> <span class="o">=</span> <span class="nx">move</span><span class="p">.</span><span class="nx">up</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="c1">// If keys are down, set the direction</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">===</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">keys</span><span class="p">.</span><span class="nx">RIGHT_ARROW</span><span class="p">)</span> <span class="nx">move</span><span class="p">.</span><span class="nx">right</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">===</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">keys</span><span class="p">.</span><span class="nx">LEFT_ARROW</span><span class="p">)</span> <span class="nx">move</span><span class="p">.</span><span class="nx">left</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">===</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">keys</span><span class="p">.</span><span class="nx">UP_ARROW</span><span class="p">)</span> <span class="nx">move</span><span class="p">.</span><span class="nx">up</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">===</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">keys</span><span class="p">.</span><span class="nx">DOWN_ARROW</span><span class="p">)</span> <span class="nx">move</span><span class="p">.</span><span class="nx">down</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">});</span>
<span class="k">this</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="s1">'KeyUp'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// If key is released, stop moving</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">===</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">keys</span><span class="p">.</span><span class="nx">RIGHT_ARROW</span><span class="p">)</span> <span class="nx">move</span><span class="p">.</span><span class="nx">right</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">===</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">keys</span><span class="p">.</span><span class="nx">LEFT_ARROW</span><span class="p">)</span> <span class="nx">move</span><span class="p">.</span><span class="nx">left</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">===</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">keys</span><span class="p">.</span><span class="nx">UP_ARROW</span><span class="p">)</span> <span class="nx">move</span><span class="p">.</span><span class="nx">up</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">keyCode</span> <span class="o">===</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">keys</span><span class="p">.</span><span class="nx">DOWN_ARROW</span><span class="p">)</span> <span class="nx">move</span><span class="p">.</span><span class="nx">down</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="p">});</span>
<span class="k">return</span> <span class="k">this</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">});</span></code></pre>
<p>Voici notre code de contrôle. La logique est assez simple, à chaque appui sur un bouton, on regarde l'état des touches fléchées pour déterminer les directions du mouvement en une combinaison de gauche, droite, bas et haut. Une fois le mouvement défini dans <code>__move</code>, crafty déplacera l'entité de <code>_speed</code> pixels dans les directions données lors du rafraîchissement d'écran.</p>
<p>On va maintenant modifier la déclaration du personnage pour le faire se déplacer, et animer son mouvement.</p>
<pre><code class="javascript"> <span class="kd">var</span> <span class="nx">player</span> <span class="o">=</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, player, controls, CustomControls, SpriteAnimation"</span><span class="p">)</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="mi">160</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="mi">144</span><span class="p">,</span> <span class="nx">z</span><span class="o">:</span> <span class="mi">1</span><span class="p">})</span>
<span class="p">.</span><span class="nx">CustomControls</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_left"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_right"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_up"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_down"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="s2">"EnterFrame"</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">left</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">isPlaying</span><span class="p">(</span><span class="s2">"walk_left"</span><span class="p">))</span>
<span class="k">this</span><span class="p">.</span><span class="nx">animate</span><span class="p">(</span><span class="s2">"walk_left"</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">right</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">isPlaying</span><span class="p">(</span><span class="s2">"walk_right"</span><span class="p">))</span>
<span class="k">this</span><span class="p">.</span><span class="nx">animate</span><span class="p">(</span><span class="s2">"walk_right"</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">up</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">isPlaying</span><span class="p">(</span><span class="s2">"walk_up"</span><span class="p">))</span>
<span class="k">this</span><span class="p">.</span><span class="nx">animate</span><span class="p">(</span><span class="s2">"walk_up"</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">down</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">isPlaying</span><span class="p">(</span><span class="s2">"walk_down"</span><span class="p">))</span>
<span class="k">this</span><span class="p">.</span><span class="nx">animate</span><span class="p">(</span><span class="s2">"walk_down"</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">})</span>
<span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="s2">"KeyUp"</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">pauseAnimation</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">resetAnimation</span><span class="p">();</span>
<span class="p">});</span></code></pre>
<p>Notez la déclaration de <em>CustomControls</em> comme méthode controle, et la vitesse d'1px/image. Pour gérer les animations, on se greffe sur l'évènement <em>EnterFrame</em>, et on détermine l'animation à jouer par rapport à la direction de mouvement du personnage. Quand une touche est relachée, on arrête et rembobine l'animation pour revenir en position neutre (évènement <em>KeyUp</em>).</p>
<p>À présent, le personnage devrait évoluer gaillardement sur votre écran, et passer allègrement à travers les buissons et hors de la zone de jeu…</p>
<h3 id="collisions">Collisions</h3>
<p>Il est temps de passer à la gestion des collisions. On va faire très simple et ne pas définir de hitbox. Crafty utilisera alors les sprites eux-mêmes comme hitbox. Pas terrible, mais simple.</p>
<p>On va aussi ne s'occuper que des collisions entre le joueur et les buissons (quels qu'ils soient). Ça évitera au perso de sortir de la zone de jeu et le forcera à éviter les buissons dans l'herbe.</p>
<p>Modifiez la déclaration du joueur comme suit:</p>
<pre><code class="javascript"> <span class="kd">var</span> <span class="nx">player</span> <span class="o">=</span> <span class="nx">Crafty</span><span class="p">.</span><span class="nx">e</span><span class="p">(</span><span class="s2">"2D, DOM, player, controls, CustomControls, SpriteAnimation, Collision"</span><span class="p">)</span>
<span class="p">.</span><span class="nx">attr</span><span class="p">({</span><span class="nx">x</span><span class="o">:</span> <span class="mi">160</span><span class="p">,</span> <span class="nx">y</span><span class="o">:</span> <span class="mi">144</span><span class="p">,</span> <span class="nx">z</span><span class="o">:</span> <span class="mi">1</span><span class="p">})</span>
<span class="p">.</span><span class="nx">CustomControls</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_left"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_right"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_up"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">reel</span><span class="p">(</span><span class="s2">"walk_down"</span><span class="p">,</span> <span class="mi">200</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="s2">"EnterFrame"</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">left</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">isPlaying</span><span class="p">(</span><span class="s2">"walk_left"</span><span class="p">))</span>
<span class="k">this</span><span class="p">.</span><span class="nx">animate</span><span class="p">(</span><span class="s2">"walk_left"</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">right</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">isPlaying</span><span class="p">(</span><span class="s2">"walk_right"</span><span class="p">))</span>
<span class="k">this</span><span class="p">.</span><span class="nx">animate</span><span class="p">(</span><span class="s2">"walk_right"</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">up</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">isPlaying</span><span class="p">(</span><span class="s2">"walk_up"</span><span class="p">))</span>
<span class="k">this</span><span class="p">.</span><span class="nx">animate</span><span class="p">(</span><span class="s2">"walk_up"</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">down</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="k">this</span><span class="p">.</span><span class="nx">isPlaying</span><span class="p">(</span><span class="s2">"walk_down"</span><span class="p">))</span>
<span class="k">this</span><span class="p">.</span><span class="nx">animate</span><span class="p">(</span><span class="s2">"walk_down"</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">})</span>
<span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="s2">"KeyUp"</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">pauseAnimation</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">resetAnimation</span><span class="p">();</span>
<span class="p">})</span>
<span class="p">.</span><span class="nx">collision</span><span class="p">()</span>
<span class="p">.</span><span class="nx">onHit</span><span class="p">(</span><span class="s2">"wall_left"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">x</span> <span class="o">+=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">pauseAnimation</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">resetAnimation</span><span class="p">();</span>
<span class="p">})</span>
<span class="p">.</span><span class="nx">onHit</span><span class="p">(</span><span class="s2">"wall_right"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">x</span> <span class="o">-=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">pauseAnimation</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">resetAnimation</span><span class="p">();</span>
<span class="p">})</span>
<span class="p">.</span><span class="nx">onHit</span><span class="p">(</span><span class="s2">"wall_bottom"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">y</span> <span class="o">-=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">pauseAnimation</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">resetAnimation</span><span class="p">();</span>
<span class="p">})</span>
<span class="p">.</span><span class="nx">onHit</span><span class="p">(</span><span class="s2">"wall_top"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">y</span> <span class="o">+=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">pauseAnimation</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">resetAnimation</span><span class="p">();</span>
<span class="p">})</span>
<span class="p">.</span><span class="nx">onHit</span><span class="p">(</span><span class="s2">"randbushes"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">left</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">x</span> <span class="o">+=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">right</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">x</span> <span class="o">-=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">up</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">y</span> <span class="o">+=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">if</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">__move</span><span class="p">.</span><span class="nx">down</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">y</span> <span class="o">-=</span> <span class="k">this</span><span class="p">.</span><span class="nx">_speed</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">pauseAnimation</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nx">resetAnimation</span><span class="p">();</span>
<span class="p">});</span></code></pre>
<p>Après avoir déclaré l'utilisation du module <em>Collision</em>, on l'initialise avec <code>collision()</code>. Ensuite il suffit de gérer l'évènement <code>onHit</code> sur les objets intéressants.</p>
<p>Les évènements de collisions sont résolus après le mouvement, mais avant le rendu. C'est pour cela qu'on fait reculer le personnage d'un pas (enfin, de <code>_speed</code>) lors de la détection d'une collision. Du point de vue du joueur, le personnage restera parfaitement immobile.</p>
<p>On pourrait bien entendu faire autre chose lors de la collision, comme lancer un combat, ou dropper un bonus tout en laissant le personnage passer dans le buisson. Les possibilités sont infinies!</p>
<h3 id="aller-plus-loin">Aller plus loin</h3>
<p>C'est donc une toute base de jeu, mais sans logique. On peut déjà améliorer le code sur beaucoup de points. Vous pourrez vous plonger dans la <a href="http://craftyjs.com/api/events.html">documentation de Crafty</a> pour vous y atteler.</p>
<p>On peut s'assurer que les buissons ne spawnent pas sur des fleurs, et que le joueur ne spawne pas sur des buissons.</p>
<p>L'algorithme de génération du monde peut être largement amélioré pour grouper les types d'herbe et faire des zone hebues et d'autres moins. On pourra introduire d'autres types de sprites pour avoir un terrain un peu plus intéressant. Avec de gros sprites, on peut aussi introduire des éléments de décor comme des maisons, ou même des PNJ.</p>
<p>Les hitbox des entités sont très maladroites. Il serait bien plus élégant de définir des hitbox sur les pieds du personnage et la base des buissons, afin de pouvoir passer derrière les éléments (il faudra aussi gérer l'axe <em>Z</em> des sprites pour le rendu!).</p>
<p>En faisant des zones de sortie dans les buissons sur les rebords, on pourra lier d'autres tableaux, générés de façon procédurale eux-aussi. Voire même générer plusieurs zones contigües à la fois et maintenir un structure de données pour que le jeu reste homogène.</p>
<p>Et bien plus encore, autant que votre créativité permet!</p><div><a href="https://linuxfr.org/users/etenil--2/journaux/petit-jeu-en-html5-et-decouverte-de-crafty.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/101742/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/etenil--2/journaux/petit-jeu-en-html5-et-decouverte-de-crafty#comments">ouvrir dans le navigateur</a>
</p>
etenilhttps://linuxfr.org/nodes/101742/comments.atomtag:linuxfr.org,2005:Diary/345472013-12-02T23:00:24+01:002013-12-02T23:00:24+01:00projet : commentaires didactiques d'une partie d'échecsLicence CC By‑SA http://creativecommons.org/licenses/by-sa/3.0/deed.fr<p>Bonsoir,<br>
la lecture du code de Pychess (je pense en particulier à <a href="http://code.google.com/p/pychess/source/browse/utilities/blunders.py">ce fichier</a>) et mes déboires de mauvais joueur d'échecs m'ont donné une idée.</p>
<p>Pourquoi ne pas essayer d'"enrober" l'information donnée par les moteurs d'analyse (Crafty, Gnuchess), information que Pychess sait lire, pour donner des commentaires didactiques au joueur ? Pour le moment, <a href="http://code.google.com/p/pychess/source/browse/utilities/blunders.py">blunders.py</a> dit juste quelque chose comme "oups, mauvais coup, il aurait fallu jouer ceci" et ce, quand la différence entre la position réellement jouée et le meilleur coup qu'il était possible de jouer devient très grande. </p>
<p>Je pense par exemple à des commentaires comme : (1) nommer les ouvertures (2) conseiller de garder le centre, la structure des pions (3) annoncer à l'avance des pièges possibles (ex : fourchette) (4) parler des coups qui paraissent évidents mais qui sont mauvais. La liste n'est pas exhaustive !</p>
<p>Tout cela n'est pas clair et j'aurais aimé savoir si certains ont eu la même idée que moi; concrètement, un simple patch à Pychess, voire un clone de ce projet pourrait suffire. J'imagine que l'idée générale serait de voir comment faire correspondre les commentaires "humains" à l'analyse des moteurs de jeu, le défi étant de coder cette correspondance.</p>
<p>Si vous êtes partants, si vous avez des idées… je suis intéressé.</p><div><a href="https://linuxfr.org/users/suizokukan/journaux/projet-commentaires-didactiques-d-une-partie-d-echecs.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/100555/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/suizokukan/journaux/projet-commentaires-didactiques-d-une-partie-d-echecs#comments">ouvrir dans le navigateur</a>
</p>
Xavier Faurehttps://linuxfr.org/nodes/100555/comments.atom