<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>GameDev - Dreamnoid</title>
	<atom:link href="http://gamedev.dreamnoid.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://gamedev.dreamnoid.com</link>
	<description></description>
	<lastBuildDate>Thu, 12 Jan 2012 12:00:14 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Exporter des données depuis Excel</title>
		<link>http://gamedev.dreamnoid.com/2011/08/31/exporter-des-donnees-depuis-excel/</link>
		<comments>http://gamedev.dreamnoid.com/2011/08/31/exporter-des-donnees-depuis-excel/#comments</comments>
		<pubDate>Wed, 31 Aug 2011 21:21:52 +0000</pubDate>
		<dc:creator>Dri</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Data]]></category>
		<category><![CDATA[Excel]]></category>
		<category><![CDATA[GCN]]></category>
		<category><![CDATA[Office]]></category>
		<category><![CDATA[Pipeline]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[Utilitaire]]></category>

		<guid isPermaLink="false">http://gamedev.dreamnoid.com/?p=448</guid>
		<description><![CDATA[Si vous utilisez Excel pour créer les données de votre jeu, voici une solution pour exporter automatiquement vos fichiers XLSX vers un format texte ou binaire.]]></description>
			<content:encoded><![CDATA[<p>En ce moment je travaille sur un RPG qui bien que modeste demande de manipuler et équilibrer pas mal de nombres.</p>
<p>Pour <a href="http://www.d2p-games.com/reckless_squad/">Reckless Squad</a> nous utilisions simplement des fichiers Lua contenant toutes nos données, un peu à la manière du <a href="http://en.wikipedia.org/wiki/JSON#Data_types.2C_syntax_and_example">JSON</a>. Pour moi c&#8217;était suffisant, mais c&#8217;est parce que je ne m&#8217;occupais pas franchement de l&#8217;équilibrage. Ce n&#8217;est que vers la fin du développement qu&#8217;on a ressentis le besoin de mettre les données en relation les unes avec les autres et d&#8217;avoir une vue d&#8217;ensemble. <a href="http://www.mom-to-be.fr/?page_id=9">Franck</a> a donc rassemblé toutes nos données dans un joli tableau Excel, mais on devait toujours reporter les changements aux fichiers Lua. Non seulement il y a un risque d&#8217;erreur assez fort (du genre se tromper de ligne) mais en plus il n&#8217;a pas fallut longtemps avant que les deux sources cessent d&#8217;être synchros.</p>
<p>On a fait avec, mais pour ce projet là je voulais faire les choses différemment. Au tout début j&#8217;utilisais Excel pour traiter des fichiers <a href="http://en.wikipedia.org/wiki/Comma-separated_values">CSV</a>, mais cela posait deux problèmes :</p>
<ol>
<li>Un fichier CSV ne permet pas d&#8217;utiliser tout le potentiel d&#8217;Excel.</li>
<li>A chaque enregistrement du fichier il fallait répondre &#8216;oui&#8217; a une série de messagebox. C&#8217;est devenu pénible assez vite.</li>
</ol>
<p>La solution était de copier/coller le tableau Excel dans un fichier texte. Cela donne quelque chose de similaire au CSV, juste avec des tabulations plutôt que des point-virgules.</p>
<p>Mais ça reste une opération manuelle, rapidement agaçante, et il est facile d&#8217;oublier une colonne ou une ligne lors de la sélection.</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-449" style="border: 1px solid black;" title="Un apercu des stats des monstres" src="http://gamedev.dreamnoid.com/files/2011/08/excel01.png" alt="" width="400" height="241" /></p>
<p style="text-align: left;">J&#8217;ai donc décidé de retrousser mes manches et de m&#8217;attaquer à une vraie solution : écrire un utilitaire pour exporter les données d&#8217;un fichier Excel au bon format.</p>
<p style="text-align: left;">C# est tout naturellement la solution. J&#8217;ai créé un projet console et ai ajouté la référence &#8220;<em>WindowsBase.dll</em>&#8221; qui permet d&#8217;utiliser le namespace <em>System.IO.Packaging</em>. Comme le nom l&#8217;indique, on va manipuler des archives ZIP. Ou pour être plus précis, des archives XLSX.</p>
<p style="text-align: left;">Depuis Office 2007, Word et Excel utilisent le format <a href="http://en.wikipedia.org/wiki/Office_Open_XML">Office Open XML</a> qui est relativement similaire au Open Document. L&#8217;idée c&#8217;est que le document est constitué de plusieurs fichiers XML contenus dans une archive ZIP. <em>System.IO.Packaging</em> va donc nous permettre d’accéder à ces fichiers XML à l&#8217;intérieur de notre XLSX. Les specs du format font plus de 6000 pages, mais la partie qui nous intéresse est simplissime, un rapide coup d’œil aux fichiers XML (après les avoir réindentés) permet de comprendre comment ça marche.</p>
<p style="text-align: left;">La première chose qui peut surprendre, c&#8217;est que les cellules contenant du texte ne stockent pas le texte en question mais un nombre. Il s&#8217;agit de l&#8217;index vers une table contenant toutes les chaines de caractère du document. Probablement pour des raisons d&#8217;optimisation, comme on le fait souvent dans les jeux vidéo d&#8217;ailleurs. La première étape est donc de récupérer ces chaines qui sont dans le fichier <em>/xl/sharedStrings.xml</em> :</p>
<p style="text-align: left;"><img class="aligncenter size-full wp-image-450" title="Listing 01" src="http://gamedev.dreamnoid.com/files/2011/08/excel_listing01.png" alt="" width="531" height="264" /></p>
<p style="text-align: left;">Le <a href="http://en.wikipedia.org/wiki/XPath">XPath</a> &#8220;<em>*/*/*</em>&#8221; devrait être &#8220;<em>sst/si/t</em>&#8221; mais pour une raison que je ne m&#8217;explique pas, ce dernier ne fonctionne pas. En utilisant les jokers à la place ça fonctionne avec tous les fichiers Excel que j&#8217;ai pu tester, donc je vais pas chercher plus loin.</p>
<p style="text-align: left;">Maintenant que nous avons notre table de chaînes, on va pouvoir s&#8217;attaquer à la feuille de calcul en elle même. Un même document Excel peut avoir plusieurs feuilles, et elles sont stockées dans le dossier <em>/xl/worksheets/</em>. Même procédure que plus haut pour charger le fichier XML en mémoire. Le noeud qui nous intéresse est <em>sheetData</em> qui contient une liste de noeuds <em>row</em>, eux même contenant des noeuds <em>c</em> (pour <em>cell</em>).</p>
<p style="text-align: left;">Simple, pas vrai ?</p>
<p style="text-align: left;">Bon il y a deux trois trucs auxquels il faut faire attention. Dans mon cas je veux charger ma feuille de style dans un tableau à deux dimensions, il faut donc garder ça en tête :</p>
<ul>
<li>Excel saute les lignes vides. Le numéro réel de la ligne est fournit par l&#8217;attribut <em>r</em>.</li>
<li>De même, les colonnes de droite vides ne faisant pas parties d&#8217;un tableau ne sont pas présentes.</li>
</ul>
<p>C&#8217;est facile à contourner, je me contente de repérer de tels cas et d&#8217;ajouter des cellules vides jusqu&#8217;à ce que j&#8217;ai un beau tableau 2D.</p>
<p>Excel stocke deux informations par cellule : la valeur (&lt;v&gt;) et la formule (&lt;f&gt;). Dans mon cas la formule ne m&#8217;intéresse pas, je veux juste le résultat final, je ne récupère donc que la valeur. L&#8217;attribut <em>t</em> (type) d&#8217;une cellule indique s&#8217;il s&#8217;agit d&#8217;une chaine de caractère ou d&#8217;un nombre. De ce que j&#8217;ai pu voir, il n&#8217;est présent que pour les chaines de caractère (<em>t=&#8221;s&#8221;</em>). S&#8217;il n&#8217;y est pas c&#8217;est que c&#8217;est un nombre.</p>
<p>Comme j&#8217;ai besoin de faire la distinction entre int et float pour exporter en binaire, je regarde s&#8217;il y a un point dans la chaine de caractère. Si c&#8217;est le cas, toute la colonne contient des floats (même si les autres nombres sont entiers).</p>
<p>Dans le cas d&#8217;une chaine de caractère, c&#8217;est aussi un nombre que vous trouverez. C&#8217;est l&#8217;index de la chaine dans la table que l&#8217;on a créé plus haut.</p>
<p>A ce moment là nous avons déjà un tableau contenant l&#8217;intégralité de notre feuille de calcul. J&#8217;ai rajouté une fonction pour séparer la première ligne du reste du tableau et la considérer comme un en-tête :</p>
<p><img class="aligncenter size-full wp-image-452" title="Listing 02" src="http://gamedev.dreamnoid.com/files/2011/08/excel_listing02.png" alt="" width="313" height="163" />Cependant, mes fichiers Excel contiennent dans une même feuille plusieurs tableaux, par exemple je me sert des stats du joueur pour déterminer celles des monstres. J&#8217;ai donc un tableau contenant les dites stats, et je ne souhaite pas l&#8217;exporter. J&#8217;ai aussi d&#8217;autres colonnes dans mon tableau de monstres qui ne sont pas pertinentes et qui servent uniquement pour les formules. Ce que je veux, c&#8217;est n&#8217;exporter qu&#8217;un sous-ensemble de ma feuille de calcul.</p>
<p>Comme nous avons fait en sorte de stocker nos cellules dans un tableau à deux dimensions, extraire un sous-ensemble est trivial :</p>
<p><img class="aligncenter size-full wp-image-453" title="Listing 03" src="http://gamedev.dreamnoid.com/files/2011/08/excel_listing03.png" alt="" width="585" height="250" />Le tableau s&#8217;indexe comme n&#8217;importe quel tableau 2D (<em>y*width+x</em>), et avec ça je peux donc extraire juste la partie qui m&#8217;intéresse.</p>
<p>Enfin, l&#8217;export. Mon utilitaire exporte au même format que le copier/coller, l&#8217;avantage c&#8217;est qu&#8217;il le fait tout seul comme un grand quand je lance mes scripts de compilation. Je peux donc utiliser cette ligne de commande pour exporter un sous ensemble du tableau :</p>
<blockquote><p>XLS2BIN.exe txt &#8220;Data.xlsx&#8221; &#8220;Monsters.txt&#8221; sheet1 true 0 20 18 22</p></blockquote>
<p>Cool.</p>
<p><img class="aligncenter size-full wp-image-454" title="Les données dans Notepad++" src="http://gamedev.dreamnoid.com/files/2011/08/excel02.png" alt="" width="400" height="249" /></p>
<p>J&#8217;ai aussi codé une fonction permettant d&#8217;exporter directement en binaire, ce qui peut être intéressant pour les petites tables triviales. Mais il est plus probable que vous ayez besoin de traiter ces données, par exemple dans mon cas le tableau des monstres contient une colonne &#8220;animation d&#8217;attaque&#8221;. L&#8217;animation est spécifiée avec une chaine de caractères (ex: &#8220;sword&#8221;) mais j&#8217;utilise un autre script pour remplacer cette chaîne par l&#8217;ID de l&#8217;animation. Cela a plusieurs avantages :</p>
<ul>
<li>Données plus compactes et temps de chargement plus court, ce qui est important sur un smartphone.</li>
<li>Possibilité de vérifier les données et de tout arrêter si l&#8217;animation &#8220;swrod&#8221; (au lieu de &#8220;sword&#8221;) n&#8217;a pas été trouvée.</li>
</ul>
<p>Cet autre script recrache toutes les données du jeu dans un unique fichier binaire, et c&#8217;est la seule chose que le jeu en lui même connaisse. Pas besoin de parser des chaines de caractère, toutes les données sont déjà dans le bon format. Je développe pour Windows Phone 7 et utilise donc C#, ce qui m&#8217;oblige à récupérer les données avec un <em>BinaryReader</em>, mais si vous utilisez du bon vieux C ou C++, un simple <em>fread</em> peut suffire pour charger l&#8217;<em>ensemble</em> des données dans une structure. Faites juste attention à ne pas avoir des champs de taille variable.</p>
<p><img class="aligncenter size-full wp-image-455" title="Et les données, en binaire" src="http://gamedev.dreamnoid.com/files/2011/08/excel03.png" alt="" width="400" height="253" /></p>
<p>Bon arrivé là je vais quand même vous passer ce petit utilitaire, avec ses sources. Je l&#8217;ai fait à l&#8217;arrache, c&#8217;est assez peu documenté et il est possible que ça ne fonctionne pas avec tous les fichiers Excel. D&#8217;ailleurs, j&#8217;ai utilisé Excel 2007, je n&#8217;ai aucune idée si ça fonctionne avec 2010. Lancez-le sans argument pour voir la liste des paramètres attendus.</p>
<p style="text-align: center;"><a href="http://dreamnoid.com/download/XLS2BIN.zip">Télécharger</a></p>
<p>Enfin, comme jamais rien n&#8217;est parfait en ce bas monde, il reste un problème avec cette méthode. A vrai dire il reste un problème avec toute méthode impliquant Excel : <em>il locke les fichiers tant qu&#8221;ils sont ouverts</em>. La fonction <em>File.Open</em> (même en read only) va donc échouer si le fichier est déjà ouvert par Excel. Devoir quitter et relancer Excel à chaque fois qu&#8217;on veut tester les nouvelles valeurs est, disons-le franchement, super chiant. Si quelqu&#8217;un connait un moyen pour éviter ça, je rêve de l&#8217;entendre.</p>
]]></content:encoded>
			<wfw:commentRss>http://gamedev.dreamnoid.com/2011/08/31/exporter-des-donnees-depuis-excel/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Générer des maps de façon procédurale</title>
		<link>http://gamedev.dreamnoid.com/2011/07/29/generer-des-maps-de-facon-procedurale/</link>
		<comments>http://gamedev.dreamnoid.com/2011/07/29/generer-des-maps-de-facon-procedurale/#comments</comments>
		<pubDate>Fri, 29 Jul 2011 15:09:46 +0000</pubDate>
		<dc:creator>Dri</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[2D]]></category>
		<category><![CDATA[Algorithme]]></category>
		<category><![CDATA[D2P Games]]></category>
		<category><![CDATA[GCN]]></category>
		<category><![CDATA[Génération procédurale]]></category>
		<category><![CDATA[Making of]]></category>
		<category><![CDATA[Reckless Squad]]></category>
		<category><![CDATA[RTS]]></category>

		<guid isPermaLink="false">http://gamedev.dreamnoid.com/?p=429</guid>
		<description><![CDATA[Découvrez l'algorithme utilisé dans Reckless Squad pour générer des niveaux aléatoirement.]]></description>
			<content:encoded><![CDATA[<p>&#8230; à la manière de Reckless Squad.</p>
<p>Cet article est une traduction en français légèrement revue d&#8217;<a href="http://www.d2p-games.com/2010/08/generating-maps-procedurally/">un article technique</a> que j&#8217;ai écrit l&#8217;an dernier pour le site de <a href="http://www.d2p-games.com">D2P Games</a>.</p>
<p>Pour Reckless Squad nous voulions un jeu qui soit hautement rejouable. Pour cela nous devions générer aléatoirement beaucoup de choses, de cette façon, le jeu continue de se réinventer lui même.</p>
<p>C&#8217;est aussi un gros avantage pour nous, développeurs, parce qu&#8217;on ne peut pas vraiment se permettre de réaliser toutes les maps du jeu à la main (même si on en a déjà fait pas mal pour <a href="http://www.d2p-games.com/2010/08/weekly-news-18/">les missions</a>).</p>
<p>Alors comment marche notre algorithme ?</p>
<p>&nbsp;</p>
<p>Dans <a href="http://www.d2p-games.com/reckless_squad/">Reckless Squad</a>, chaque map est un &#8220;chemin&#8221; allant d&#8217;un point de départ à un point d&#8217;arrivée. Mais nous voulions ajouter quelques cavités pour le rendre plus naturel.</p>
<p>La première étape a été de choisir où commencera le chemin. Nous avons choisis le côté gauche de l&#8217;écran, parce que c&#8217;est ce à quoi nous sommes habitués dans les cultures occidentales : nous lisons de gauche à droite. Ce point de départ sera alors situé sur l&#8217;un des bords de l&#8217;écran. Nous déterminons la position exacte aléatoirement.</p>
<p>Une fois que nous avons ce point de départ, nous avons besoin d&#8217;un point d&#8217;arrivée. Même technique, sauf que le point se situe maintenant sur le côté droit de l&#8217;écran.</p>
<p>Nous avons également décidés que le chemin passerait toujours pas le centre de la map, donc j&#8217;ajoute ce point entre les deux autres. A ce moment là, j&#8217;ai déjà trois points qui forment mon chemin :</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-430" style="border: 1px solid black;" title="Les trois points forment un chemin" src="http://gamedev.dreamnoid.com/files/2011/07/mapgen_01.png" alt="" width="400" height="241" /></p>
<p style="text-align: left;">La map est une <a href="http://wiki.gamedev.net/index.php/RPG_Map">grille 2D</a>, comme vous pouvez le voir les points sont &#8220;dessinés&#8221; dessus avec des croix.</p>
<p style="text-align: left;">J&#8217;itère ensuite sur les points, deux par deux, et trouve un nouveau point entre chacun d&#8217;eux. Ensuite je le déplace légèrement et aléatoirement tout en faisant attention à ce qu&#8217;il reste bien à l&#8217;intérieur de la map :</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-431" style="border: 1px solid black;" title="Je rajoute des points positionnés aléatoirements" src="http://gamedev.dreamnoid.com/files/2011/07/mapgen_02.png" alt="" width="400" height="241" /></p>
<p>En gris vous pouvez voir l&#8217;ancien chemin, le nouveau est en blanc. Je répète l&#8217;opération :</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-432" style="border: 1px solid black;" title="Seconde passe" src="http://gamedev.dreamnoid.com/files/2011/07/mapgen_02b.png" alt="" width="400" height="241" /></p>
<p>Encore et encore :</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-433" style="border: 1px solid black;" title="D'autres itérations" src="http://gamedev.dreamnoid.com/files/2011/07/mapgen_03.png" alt="" width="400" height="241" /></p>
<p>Et après <em>beaucoup</em> d&#8217;autres itérations, j&#8217;ai le contour de ma map :</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-435" style="border: 1px solid black;" title="Après de nombreuses itérations, la map prend forme" src="http://gamedev.dreamnoid.com/files/2011/07/mapgen_041.png" alt="" width="400" height="241" /></p>
<p style="text-align: left;">En noir, la &#8220;zone bloquante&#8221; et en blanc le chemin.</p>
<p style="text-align: left;">Il est possible de contrôler les différents paramètres de l’algorithme, comme le nombres d&#8217;itérations, la distance autorisée entre chaque points et la taille de la map pour obtenir des résultats très différents. Par exemple, voici un niveau que se devait d&#8217;être long :</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-441" style="border: 1px solid black;" title="Un chemin plus long" src="http://gamedev.dreamnoid.com/files/2011/07/mapgen_11.png" alt="" width="400" height="300" /></p>
<p>Maintenant je veux &#8220;habiller&#8221; la map de façon à ce qu&#8217;elle soit jolie : ma première étape consiste à séparer les &#8220;éléments isolés&#8221; du reste de la &#8220;zone bloquante&#8221;. Les éléments isolés seront représentés par des arbres, des rochers, etc. Ils sont en vert sur cette image :</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-436" style="border: 1px solid black;" title="Les éléments isolés sont identifiés" src="http://gamedev.dreamnoid.com/files/2011/07/mapgen_05.png" alt="" width="400" height="240" /></p>
<p>Arrivé là, je vais ajouter du &#8220;volume&#8221; aux maps car Reckless Squad utilise une perspective vue de dessus de 4/3 comme les vieux RPG 2D.</p>
<p>J&#8217;ai décidé que les deux tiles les plus basses seront vues de face, et le reste du dessus. Souvenez-vous des maps de la bonne vieille ère SNES :</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-437" style="border: 1px solid black;" title="Une partie du tileset" src="http://gamedev.dreamnoid.com/files/2011/07/mapgen_07.png" alt="" width="64" height="128" /></p>
<p>La partie en rouge constituera la &#8220;zone bloquante&#8221;, vue de dessus. La partie verte est la bordure qui fait la transition entre cette zone et ce que j&#8217;appelle &#8220;la falaise&#8221;, à savoir la partie bleue. Il s&#8217;agit du mur vu de face.</p>
<p>J&#8217;applique le même principe aux maps de Reckless squad :</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-438" style="border: 1px solid black;" title="En rose la bordure" src="http://gamedev.dreamnoid.com/files/2011/07/mapgen_06.png" alt="" width="400" height="240" /></p>
<p>La bordure est ici dessinée avec cette atroce couleur rose, les deux tiles en dessous représentent la falaise.</p>
<p>Une fois que toutes mes tiles sont marquées &#8220;herbe&#8221;, &#8220;zone bloquante&#8221;, &#8220;bordure&#8221;, &#8220;falaise&#8221; ou &#8220;élément isolé&#8221;, je peux leur ajouter des images. Cette partie est plutôt simple : je colle des sprites par dessus. Les sprites sont triés par calques pour conserver l&#8217;effet de perspective : les unités sont dessinés par dessus l&#8217;herbe et la falaise, mais sous la zone bloquante et la bordure.</p>
<p>Et voilà le résultat final !</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-439" style="border: 1px solid black;" title="La map finale, dans le jeu" src="http://gamedev.dreamnoid.com/files/2011/07/mapgen_09.png" alt="" width="400" height="241" /></p>
<p style="text-align: left;">Bien que générée aléatoirement, cette map peut être retrouvée et recrée à loisir grâce au numéro que vous voyez en haut à gauche sur les captures d&#8217;écran précédentes. Il s&#8217;agit de la &#8220;seed&#8221;, le nombre qui détermine le tirage des nombres aléatoires.</p>
<p style="text-align: left;">En effet, ce n&#8217;est un secret pour personne mais les ordinateurs n&#8217;ont absolument aucune imagination et les nombres aléatoires sont en réalité des listes prédéfinies. La <em>seed</em> (graine) détermine quelle liste de nombres utiliser. En spécifiant la même seed à notre algorithme, il produira exactement le même résultat.</p>
<p style="text-align: left;">Et petit bonus qui n&#8217;était pas dans l&#8217;article originel, une fois que la map est générée, j&#8217;applique le <a href="http://en.wikipedia.org/wiki/A*_search_algorithm">pathfinding</a> entre le point de départ et le point d&#8217;arrivée pour déterminer le chemin qu&#8217;empruntera le convoi. Cela me permet de dessiner la route que vous voyez sur la capture d&#8217;écran précédente, elle permet au joueur d&#8217;anticiper les mouvements du convoi qu&#8217;il doit protéger.</p>
<p style="text-align: left;">Mais ce n&#8217;est pas tout, a partir de là, je peux appliquer un coefficient à chaque tile pour savoir sa distance par rapport à ce chemin idéal. Cette distance me permet de positionner les coffres légèrement en retrait du chemin, forçant le joueur à abandonner temporairement son convoi et le mettre en danger pour aller les chercher.</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-442" style="border: 1px solid black;" title="Les endroits isolés sont idéaux pour placer des coffres" src="http://gamedev.dreamnoid.com/files/2011/07/mapgen_10.png" alt="" width="400" height="265" /></p>
<p style="text-align: center;">
<p style="text-align: left;">Voilà ! Je pense traduire d&#8217;autres articles que j&#8217;avais écris à l&#8217;époque, donc <em>stay tuned</em> !</p>
]]></content:encoded>
			<wfw:commentRss>http://gamedev.dreamnoid.com/2011/07/29/generer-des-maps-de-facon-procedurale/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Comment ça marche : un jeu de combat</title>
		<link>http://gamedev.dreamnoid.com/2011/02/20/comment-ca-marche-un-jeu-de-combat/</link>
		<comments>http://gamedev.dreamnoid.com/2011/02/20/comment-ca-marche-un-jeu-de-combat/#comments</comments>
		<pubDate>Sun, 20 Feb 2011 15:04:12 +0000</pubDate>
		<dc:creator>Dri</dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[Français]]></category>
		<category><![CDATA[Jeux vidéo]]></category>
		<category><![CDATA[2D]]></category>
		<category><![CDATA[Animation]]></category>
		<category><![CDATA[GCN]]></category>
		<category><![CDATA[Jeux de Combat]]></category>
		<category><![CDATA[Making of]]></category>
		<category><![CDATA[XNA]]></category>

		<guid isPermaLink="false">http://gamedev.dreamnoid.com/?p=356</guid>
		<description><![CDATA[Tour d'horizon du fonctionnement d'un jeu de combat 2D, de l'animation à l'IA en passant par la physique et les collisions.]]></description>
			<content:encoded><![CDATA[<p>J&#8217;entretiens une relation étrange avec les jeux de combat : d&#8217;un côté ils me fascinent, et de l&#8217;autre je suis incapable d&#8217;y jouer correctement.</p>
<p>Même si je me débrouille bien dans Smash Bros et Soul Calibur, je suis quand même incapable de battre Bison dans Street Fighter II et les raccourcis vers les combos sur le stick droit de la manette est la seule raison pour laquelle j&#8217;arrive à avancer dans BlazBlue. Et si je joue contre quelqu&#8217;un qui s&#8217;investit vraiment dans le jeu, je me fais systématiquement massacrer <img src='http://gamedev.dreamnoid.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Mais cela ne m&#8217;empêche pas d&#8217;être émerveillé par de tels jeux. Je pense que ça vient en partie du fait que l&#8217;on dispose d&#8217;une large gamme de personnages, tous uniques. Aussi bien sur leur backstory, que leur design ou leurs coups. Et si un type de jeu me fascine, vous pouvez être sûr que je vais essayer d&#8217;en faire un, ou au moins de comprendre comment ça marche.</p>
<p>J&#8217;ai donc réalisé une petite démo de jeu de combat, une sorte de prototype avec peu de fonctionnalités, pour voir un peu les dessous de la chose. Et voici mon parcours.</p>
<h3>Contrôles et physique</h3>
<p>J&#8217;ai décidé pour ce prototype d&#8217;inclure les actions suivantes :</p>
<ul>
<li>Se déplacer (courir)</li>
<li>Sauter</li>
<li>Se baisser</li>
<li>Attaque horizontale</li>
<li>Garde</li>
</ul>
<p>J&#8217;ai changé le repère en mettant le zéro sur Y au niveau du sol et en inversant l&#8217;axe, ainsi sauter augmente la composante Y, et il n&#8217;est pas possible de descendre sous 0 (le sol).</p>
<p>J&#8217;ai ensuite une fonction qui transforme une telle coordonnée monde en coordonnée écran, pour afficher les sprites au bon endroit.</p>
<p>La physique est gérée avec deux vecteurs 2D : la position et la vélocité du combattant.</p>
<p>Pour déplacer le personnage, j&#8217;ai juste à modifier sa vélocité. Courir reviens à changer la vélocité sur X (300 et -300 actuellement) et pour s&#8217;arrêter il suffit de la remettre à zéro. De même, sauter revient à définir la vélocité sur Y (800, il faut que ce soit assez &#8220;fort&#8221; pour dépasser la gravité).</p>
<div id="attachment_363" class="wp-caption aligncenter" style="width: 432px"><a href="http://gamedev.dreamnoid.com/files/2011/01/fg_crouch_guard.png"><img class="size-full wp-image-363" title="fg_crouch_guard" src="http://gamedev.dreamnoid.com/files/2011/01/fg_crouch_guard.png" alt="" width="422" height="305" /></a><p class="wp-caption-text">Link s&#39;accroupit et Marth se protège</p></div>
<p>A chaque mise à jour de la simulation physique, j&#8217;ajoute à la  position le produit entre la vélocité et le temps écoulé depuis la  dernière frame (le delta time, en secondes) et réduit légèrement la  vélocité avec la &#8220;décélération&#8221; qui augmente au fur et à mesure que le  temps passe. Cela permet d&#8217;annuler la vélocité de façon fluide, ça  fonctionne un peu comme la friction de l&#8217;air.</p>
<p>De même j&#8217;applique la gravité qui se fait de plus en plus forte,  comme à la décélération. Lorsque le personnage touche le sol, je cesse  d&#8217;appliquer la gravité et je remet les forces de décélération et de  gravité à leur valeur d&#8217;origine.</p>
<p>Il est important de préciser que je traite les deux axes séparément, c&#8217;est bien plus simple comme ça.</p>
<h3>Animations #1</h3>
<p>Ma première implémentation du système d&#8217;animation est simple et se base sur des sprite sheets. Elle est en réalité tellement simple que je n&#8217;avais qu&#8217;une seule frame par animation.</p>
<p>(Les sprites viennent de <a href="http://www.spriters-resource.com/custom_edited/supersmashbros/index.html">The Spriters Resource</a> et le fond de BlazBlue)</p>
<p>Une animation est composée d&#8217;une ou plusieurs frames, et le personnage ne peut avoir qu&#8217;une seule animation courante. Par défaut c&#8217;est &#8220;Idle&#8221; : le personnage se tient debout, sans bouger. Puis chaque action a sa propre animation, qu&#8217;elle soit déclenchée par l&#8217;appuie d&#8217;une touche (le saut, courir, etc), par la physique (retomber) ou par un évènement (se faire blesser).</p>
<p>En fonction de l&#8217;animation courante, les actions possibles changent. Par exemple il n&#8217;est pas possible de s&#8217;accroupir en même temps que l&#8217;on saute, et quand on est touché, on ne peut rien faire.</p>
<div id="attachment_362" class="wp-caption aligncenter" style="width: 338px"><a href="http://gamedev.dreamnoid.com/files/2011/01/fg_jumping.png"><img class="size-full wp-image-362" title="fg_jumping" src="http://gamedev.dreamnoid.com/files/2011/01/fg_jumping.png" alt="" width="328" height="384" /></a><p class="wp-caption-text">Marth en plein saut</p></div>
<h3>Hitboxes</h3>
<p>Chaque frame d&#8217;une animation a une liste de hitboxes, qui ne sont en réalité que des rectangles. Ces hitboxes sont divisées en 3 catégories :</p>
<ul>
<li>Les bleus sont capables de prendre des dégâts</li>
<li>Les rouges infligent des dégâts si elles touchent une bleu</li>
<li>Les vertes bloquent les attaques</li>
</ul>
<p>Si une frame n&#8217;a pas de hitbox, elle ne peut rien faire. C&#8217;est le cas par exemple des frames lorsqu&#8217;un ennemi est touché, il est invulnérable pendant un certain temps.</p>
<div id="attachment_360" class="wp-caption aligncenter" style="width: 384px"><a href="http://gamedev.dreamnoid.com/files/2011/01/fg_attack.png"><img class="size-full wp-image-360" title="fg_attack" src="http://gamedev.dreamnoid.com/files/2011/01/fg_attack.png" alt="" width="374" height="242" /></a><p class="wp-caption-text">Après avoir pris une attaque, Marth est invulnérable pendant un court instant</p></div>
<p>Les collisions sont testées entre les différentes hitboxes et soustraire la position du joueur à celle de l&#8217;ennemi permet d&#8217;obtenir le vecteur direction de l&#8217;attaque afin de propulser la cible dans la bonne direction. J&#8217;imagine que spécifier ce vecteur à la main pour chaque attaque est une meilleure idée, cela permettrait plus de souplesse (on choisit la direction où on veut que l&#8217;adversaire soit éjecté), mais pour l&#8217;exemple courant cela suffit.</p>
<h3>Intelligence artificielle</h3>
<p>L&#8217;IA fonctionne comme une simple machine à états, tellement simple qu&#8217;elle est réalisée avec une série de if/else.</p>
<p>En fait elle est aussi simple qu&#8217;inefficace : l&#8217;ennemi se rapproche du joueur jusqu&#8217;à être à sa portée, et décide alors de réaliser une action au hasard entre attaquer, sauter, se baisser et se défendre. Vraiment, qui espère gagner un combat comme ça ?</p>
<p>Je n&#8217;ai pas encore eu le temps de vraiment me pencher sur cette partie là, donc pour le moment ça restera comme ça.</p>
<p>Toutefois je pense qu&#8217;une machine à état devrait être suffisant pour faire une bonne IA, à condition qu&#8217;elle soit bien pensée et assez complète bien sûr.</p>
<h3>Animations #2</h3>
<p>L&#8217;inconvénient des sprite sheets, c&#8217;est que ça demande beaucoup de boulot, et beaucoup de mémoire. Et si vous augmentez la résolution, ce qui devient une nécessité avec les écrans d&#8217;ajourd&#8217;hui, vous augmentez le temps nécessaire pour créer chaque frame ainsi que le poids de chaque image.</p>
<p>Une autre solution, est d&#8217;emprunter une technique du monde de la 3D : <strong>l&#8217;animation squelettale</strong>.</p>
<p>On commence par découper notre personnage en plusieurs parties :</p>
<p><a href="http://gamedev.dreamnoid.com/files/2011/01/fg_parts.png"><img class="aligncenter size-full wp-image-361" title="fg_parts" src="http://gamedev.dreamnoid.com/files/2011/01/fg_parts.png" alt="" width="439" height="354" /></a></p>
<p>Puis on les rassembles et les animes, comme on le ferait avec un système d&#8217;animation 3D à base des bones.</p>
<p>Bien réalisée, l&#8217;animation squelettale peut être complétement transparente et bluffante.</p>
<div id="attachment_357" class="wp-caption aligncenter" style="width: 510px"><a href="http://gamedev.dreamnoid.com/files/2011/01/odinsphere.jpg"><img class="size-full wp-image-357" title="Odin Sphere" src="http://gamedev.dreamnoid.com/files/2011/01/odinsphere.jpg" alt="" width="500" height="281" /></a><p class="wp-caption-text">Les jeux Vanillaware en sont l&#39;exemple parfait</p></div>
<p>Mal réalisée, cela donne un effet &#8220;marionnette&#8221; complètement ridicule. Bon malheureusement, ce que je vais vous montrer à l&#8217;instant tombe dans cette catégorie.</p>
<p>Pour être bien réalisé, il faut :</p>
<ul>
<li>Bien sûr, permettre la rotation de chaque bone (c&#8217;est la base)</li>
<li>Permettre également la translation</li>
<li>Ainsi que la la mise à l&#8217;échelle</li>
<li>Et enfin permettre le changement d&#8217;image associée à chaque bone</li>
</ul>
<p>Ensuite avec de la patience, du temps et des compétences on peut arriver à l&#8217;exemple ci-dessus.</p>
<p>Voici une capture d&#8217;écran de mon éditeur d&#8217;animation :</p>
<div id="attachment_358" class="wp-caption aligncenter" style="width: 310px"><a href="http://gamedev.dreamnoid.com/files/2011/01/anim_editor.png"><img class="size-medium wp-image-358" title="Editeur d'animation" src="http://gamedev.dreamnoid.com/files/2011/01/anim_editor-300x215.png" alt="" width="300" height="215" /></a><p class="wp-caption-text">Cliquez pour voir en grand</p></div>
<p style="text-align: left;">Sur la gauche, on a la liste des &#8220;parts&#8221;, il s&#8217;agit d&#8217;une image qui se comporte comme un bones.</p>
<p style="text-align: left;">En dessous, il y a un petit espace pour configurer la &#8220;part&#8221; sélectionnée, notamment le point d&#8217;origine du bone par rapport à l&#8217;origine de l&#8217;image, la position par rapport au bone parent (et le bone parent en question) et enfin l&#8217;ordre d&#8217;affichage (Z).</p>
<p style="text-align: left;">Sur la droite, c&#8217;est la liste des animations.</p>
<p style="text-align: left;">Comme il n&#8217;y a pas d&#8217;interpolation pour le moment, on peut changer la durée de chaque frame séparément. Ensuite il est possible de changer l&#8217;angle de rotation de chaque &#8220;part&#8221;.</p>
<p style="text-align: left;">Si vous faites attention, vous verrez derrière un autre sprite légèrement transparent, il est là pour l&#8217;<strong>onion skinning</strong>. Il s&#8217;agit de la frame précédente, affichée pour servir de repère.</p>
<p style="text-align: left;">Le personnage présenté est <span style="text-decoration: line-through;">décalqué</span> inspiré de Ragna, de BlazBlue.</p>
]]></content:encoded>
			<wfw:commentRss>http://gamedev.dreamnoid.com/2011/02/20/comment-ca-marche-un-jeu-de-combat/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Les bases de la 3D, partie 2</title>
		<link>http://gamedev.dreamnoid.com/2009/12/25/les-bases-de-la-3d-partie-2/</link>
		<comments>http://gamedev.dreamnoid.com/2009/12/25/les-bases-de-la-3d-partie-2/#comments</comments>
		<pubDate>Thu, 24 Dec 2009 22:35:56 +0000</pubDate>
		<dc:creator>Dri</dc:creator>
				<category><![CDATA[3D]]></category>
		<category><![CDATA[Développement]]></category>
		<category><![CDATA[Théorie]]></category>

		<guid isPermaLink="false">http://www.planet-dev.com/?p=235</guid>
		<description><![CDATA[Dans le précédent article on a vu les fondations de la 3D, notamment la projection et les axes. Seulement tout ça n&#8217;a d&#8217;intérêt que si on affiche quelque chose à l&#8217;écran ! On va donc voir dans cet article comment sont décrites les formes géométriques que l&#8217;on affiche en 3D. Les primitives Les primitives sont les formes de base qui nous serviront à décrire toute notre géométrie. Elles sont très simples et permettent de faire déjà beaucoup de choses. Les Points : de simples points dans l&#8217;espace, on peut leur donner une épaisseur Les Lignes : des lignes. Les Triangles [...]]]></description>
			<content:encoded><![CDATA[<p>Dans <a href="http://www.planet-dev.com/developpement/les-bases-de-la-3d-partie-1">le précédent article</a> on a vu les fondations de la 3D, notamment la projection et les axes.</p>
<p>Seulement tout ça n&#8217;a d&#8217;intérêt que si on affiche quelque chose à l&#8217;écran ! On va donc voir dans cet article comment sont décrites les formes géométriques que l&#8217;on affiche en 3D.</p>
<h3>Les primitives</h3>
<p>Les primitives sont les formes de base qui nous serviront à décrire toute notre géométrie. Elles sont très simples et permettent de faire déjà beaucoup de choses.</p>
<ul>
<li>Les <strong>Points</strong> : de simples points dans l&#8217;espace, on peut leur donner une épaisseur</li>
<li>Les <strong>Lignes</strong> : des lignes.</li>
<li>Les <strong>Triangles </strong>: c&#8217;est la primitive principale, la plus utilisée.</li>
<li>Les <strong>Quadrangles </strong>: Comme un triangle mais avec quatre côtés.</li>
<li>Les <strong><em>n</em>-gones</strong> : très peu utilisés pour la 3D temps réel, ce sont des polygones qui ont <em>n</em> côtés (plus de 4, sinon ce sont des triangles ou des quadrangles). Je ne m&#8217;attarderai pas là dessus car leur usage en 3D temps réel est extrêmement marginal (pour ne pas dire inexistant).</li>
</ul>
<p>Mis à part les <em>n</em>-gones, les cartes graphiques actuelles sont capables d&#8217;afficher directement toutes ces primitives. Cela n&#8217;a pas toujours été le cas, et beaucoup d&#8217;anciens modèles de cartes découpent les quadrangles en deux triangles.</p>
<p>D&#8217;une façon générale, les triangles permettent de représenter un vaste panel de formes, et tous les jeux actuels sont basés sur eux.</p>
<p>On préfèrera donc utiliser uniquement des triangles pour le rendu, par soucis d&#8217;homogénéité. En revanche, rien n&#8217;empêche d&#8217;utiliser des quadrangles lors de la modélisation, pour &#8220;y voir plus clair&#8221;.</p>
<div id="attachment_347" class="wp-caption aligncenter" style="width: 804px"><a href="http://gamedev.dreamnoid.com/files/2009/12/bag_tri_quad1.jpg"><img class="size-full wp-image-347" title="bag_tri_quad" src="http://gamedev.dreamnoid.com/files/2009/12/bag_tri_quad1.jpg" alt="" width="794" height="320" /></a><p class="wp-caption-text">A gauche, le sac lors de la modélisation. A droite, lors du rendu en utilisant uniquement des triangles.</p></div>
<h3>Vertices</h3>
<p>Les <strong>vertices </strong>(singulier <strong>vertex</strong>, <em>sommet</em> en français) sont des points dans l&#8217;espace 3D qui définissent une forme. Ces points sont les sommets de nos primitives.</p>
<p>Un seul vertex suffit à définir un point, deux font une ligne, trois un triangle et quatre un quadrangle.</p>
<div id="attachment_348" class="wp-caption aligncenter" style="width: 420px"><a href="http://gamedev.dreamnoid.com/files/2009/12/vertices1.jpg"><img class="size-full wp-image-348" title="vertices" src="http://gamedev.dreamnoid.com/files/2009/12/vertices1.jpg" alt="" width="410" height="388" /></a><p class="wp-caption-text">Les points en orange sont les vertices</p></div>
<p>Ces vertices peuvent être <em>partagés</em> et servent à former plusieurs primitives (comme c&#8217;est le cas sur l&#8217;image au dessus).</p>
<p>Dans ce cas il va falloir dire au programme quels vertices forment une primitive, pour cela on utilisera des <strong>indices</strong>.</p>
<h3>Indices</h3>
<div id="attachment_350" class="wp-caption alignright" style="width: 110px"><a href="http://gamedev.dreamnoid.com/files/2009/12/vertexbuffer1.png"><img class="size-full wp-image-350" title="vertexbuffer" src="http://gamedev.dreamnoid.com/files/2009/12/vertexbuffer1.png" alt="" width="100" height="240" /></a><p class="wp-caption-text">Un tableau de vertices, aussi nommé vertex buffer</p></div>
<p>Les <strong>indices</strong> (singulier <strong>index</strong>) servent à <em>décrire</em> nos primitives.</p>
<p>Imaginons que nous souhaitions partager nos vertices pour économiser de la mémoire (un seul vertex sera utilisé pour 3 ou 4 triangles par exemple), nous allons les stocker dans un tableau appelé <strong>vertex buffer</strong> (voir ci-contre).</p>
<p>Les indices correspondront à la colonne <em>ID</em>. On compte toujours à partir de 0, ainsi le premier élément dans le tableau aura l&#8217;index 0, le second 1, le troisième 2, et ainsi de suite.</p>
<p>On utilisera donc ces indices pour décrire notre primitive, si on veut par exemple décrire un triangle, on dira que ses trois sommets sont les vertices numéro 0, 4 et 6 (au hasard).</p>
<p>La carte graphique va donc regarder dans le vertex buffer à quoi correspondent ces indices. 0 ? c&#8217;est 0,0,0. 4 ? c&#8217;est 100,3,45. 6 ? 12,30,0.</p>
<p>Et avec ça elle va donc afficher notre triangle. Plusieurs primitives peuvent donc ré-utiliser les même indices, et donc les même vertices.</p>
<p>On fournit cette liste de vertices à la carte graphique à travers un autre tableau que l&#8217;on nomme logiquement <strong>index buffer</strong>.</p>
<p>Mais les indices ne servent pas seulement à partager des vertices, ils permettent par exemple de choisir la géométrie à afficher.</p>
<p>Imaginons que l&#8217;un de vos personnages porte un fourreau à la ceinture, et que dans certaines circonstances vous souhaitez ne pas l&#8217;afficher : il vous suffira de retirer les indices décrivant le fourreau de votre index buffer</p>
<h3>Textures</h3>
<p>Les textures servent à ajouter du réalisme aux modèles 3D. Et parce qu&#8217;une image vaut mieux qu&#8217;un long discours, voyez vous même :</p>
<div id="attachment_351" class="wp-caption aligncenter" style="width: 688px"><a href="http://gamedev.dreamnoid.com/files/2009/12/textures1.jpg"><img class="size-full wp-image-351" title="textures" src="http://gamedev.dreamnoid.com/files/2009/12/textures1.jpg" alt="" width="678" height="490" /></a><p class="wp-caption-text">A gauche sans textures, à droite avec.</p></div>
<p>Les textures servent donc à ajouter des détails par dessus nos modèles.</p>
<p>Une texture n&#8217;est qu&#8217;une simple image :</p>
<div id="attachment_352" class="wp-caption aligncenter" style="width: 266px"><a href="http://gamedev.dreamnoid.com/files/2009/12/texture1.jpg"><img class="size-full wp-image-352" title="texture" src="http://gamedev.dreamnoid.com/files/2009/12/texture1.jpg" alt="" width="256" height="256" /></a><p class="wp-caption-text">La texture du modèle présenté plus haut</p></div>
<p>On voit tout de suite le challenge : il faut faire correspondre un modèle 3D à une image 2D&#8230; pour cela on doit l&#8217;aplatir !</p>
<p>On appelle cela le dépliage d&#8217;UV ou<strong> UV Unwrapping</strong>, c&#8217;est une technique qui consiste à faire correspondre à chaque vertex un point sur la texture. Je ne vous cacherai pas que c&#8217;est une étape très longue et fastidieuse, heureusement des outils de plus en plus perfectionnés permettent d&#8217;automatiser ou de simplifier la tâche.</p>
<div id="attachment_353" class="wp-caption aligncenter" style="width: 777px"><a href="http://gamedev.dreamnoid.com/files/2009/12/uvunwrapping1.jpg"><img class="size-full wp-image-353" title="uvunwrapping" src="http://gamedev.dreamnoid.com/files/2009/12/uvunwrapping1.jpg" alt="" width="767" height="394" /></a><p class="wp-caption-text">Le dépliage d&#39;UV : on fait correspondre un point sur la texture à chaque vertex</p></div>
<p>Ces coordonnées de textures sont exprimées entre 0 et 1 :</p>
<div id="attachment_354" class="wp-caption aligncenter" style="width: 138px"><a href="http://gamedev.dreamnoid.com/files/2009/12/uvcoords1.png"><img class="size-full wp-image-354" title="uvcoords" src="http://gamedev.dreamnoid.com/files/2009/12/uvcoords1.png" alt="" width="128" height="128" /></a><p class="wp-caption-text">Le coin supérieur gauche de la texture correspond à 0,0 et le coin inférieur droit à 1,1</p></div>
]]></content:encoded>
			<wfw:commentRss>http://gamedev.dreamnoid.com/2009/12/25/les-bases-de-la-3d-partie-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Les bases de la 3D, partie 1</title>
		<link>http://gamedev.dreamnoid.com/2009/11/12/les-bases-de-la-3d-partie-1/</link>
		<comments>http://gamedev.dreamnoid.com/2009/11/12/les-bases-de-la-3d-partie-1/#comments</comments>
		<pubDate>Wed, 11 Nov 2009 22:24:52 +0000</pubDate>
		<dc:creator>Dri</dc:creator>
				<category><![CDATA[3D]]></category>
		<category><![CDATA[Développement]]></category>
		<category><![CDATA[Théorie]]></category>
		<category><![CDATA[Tutoriel]]></category>

		<guid isPermaLink="false">http://www.planet-dev.com/?p=225</guid>
		<description><![CDATA[Cet article est le premier d&#8217;une petite série traitant des bases de la 3D. Je vais couvrir les principaux concepts utilisés en 3D de façon à les introduire. Je ne vais pas les expliquer en détail, ces articles sont juste une première étape pour vous permettre d&#8217;approfondir vos recherches plus tard. Ils sont destinés à n&#8217;importe qui ayant déjà vu la 3D à l&#8217;œuvre (à travers un jeu vidéo ou un film d&#8217;animation par exemple) et qui se souvient de ses cours de géométrie du collège. Ce premier article parlera du monde en trois dimensions et de la façon dont [...]]]></description>
			<content:encoded><![CDATA[<p>Cet article est le premier d&#8217;une petite série traitant des bases de la 3D.</p>
<p>Je vais couvrir les principaux concepts utilisés en 3D de façon à les introduire. Je ne vais pas les expliquer en détail, ces articles sont juste une première étape pour vous permettre d&#8217;approfondir vos recherches plus tard.</p>
<p>Ils sont destinés à n&#8217;importe qui ayant déjà vu la 3D à l&#8217;œuvre (à travers un jeu vidéo ou un film d&#8217;animation par exemple) et qui se souvient de ses cours de géométrie du collège.</p>
<p>Ce premier article parlera du monde en trois dimensions et de la façon dont il est affiché sur un écran en deux dimensions.</p>
<h3>Un monde en 3D, un écran en 2D</h3>
<p>Pour le moment, les écrans (moniteurs comme téléviseurs) sont limités à la 2D. C&#8217;est à dire qu&#8217;ils ne peuvent afficher que des images planes sur leur surface. Cela viendra surement à changer dans un futur plus ou moins proche, mais pour le moment il faut s&#8217;en accommoder. Même la fausse 3D vendue par certains cinémas ces derniers temps n&#8217;est qu&#8217;<a href="http://www.effets-speciaux.info/article?id=131">une image 2D traitée par des lunettes pour donner un semblant de 3D</a>.</p>
<p>L&#8217;enjeu est donc de <strong>projeter</strong> une scène en 3D sur une image 2D.</p>
<div id="attachment_340" class="wp-caption aligncenter" style="width: 310px"><a href="http://gamedev.dreamnoid.com/files/2009/11/world_to_screen1.jpg"><img class="size-medium wp-image-340" title="world_to_screen" src="http://gamedev.dreamnoid.com/files/2009/11/world_to_screen1-300x111.jpg" alt="" width="300" height="111" /></a><p class="wp-caption-text">Projection d&#39;une scène 3D sur un écran 2D</p></div>
<p>Cela se fait au moyen d&#8217;une <strong>caméra</strong> : tout comme un cinéaste utilise une caméra pour capturer &#8220;le monde réel&#8221; en une séquence d&#8217;image, nous utiliserons une caméra pour capturer notre scène en trois dimensions.</p>
<h3>Les repères</h3>
<p>Vous vous souvenez surement de vos cours de géométrie et des repères orthonormés directs, avec les abscisses et ordonnées.</p>
<p>En informatique, les conventions sont légèrement différentes : on considère que le coin haut-gauche de votre écran (ou d&#8217;une image) est l&#8217;origine. L&#8217;axe X est alors l&#8217;axe des abscisses (horizontal) et l&#8217;axe Y celui des ordonnées (vertical).</p>
<p>Quand on donne des coordonnées (en maths comme en informatique) en commence toujours par l&#8217;abscisse (X) puis par l&#8217;ordonnée (Y). Le point (10,5) est alors a pour abscisse 10 et 5 pour ordonnée.</p>
<p>La 3D ajoute une nouvelle dimension, la <strong>profondeur</strong>, que l&#8217;on note Z.</p>
<div id="attachment_342" class="wp-caption aligncenter" style="width: 650px"><a href="http://gamedev.dreamnoid.com/files/2009/11/reperes1.png"><img class="size-medium wp-image-342 " title="reperes" src="http://gamedev.dreamnoid.com/files/2009/11/reperes1.png" alt="" width="640" height="220" /></a><p class="wp-caption-text">Les différents repères</p></div>
<p>Cependant la façon de représenter les repères en 3D n&#8217;est pas normalisée.</p>
<p>Il existe deux tendances principales : main droite (<strong>right-handed</strong>) et main gauche (<strong>left-handed</strong>).</p>
<p>Concrètement ce qui change est l&#8217;orientation de l&#8217;axe Z.</p>
<p>Pour donner un exemple : OpenGL et XNA sont &#8220;right-handed&#8221; alors que DirectX est &#8220;left-handed&#8221;.</p>
<p>Certains intervertissent les axes Y et Z (par exemple l&#8217;Unreal Engine utilise Y pour la profondeur et Z pour la hauteur), ce n&#8217;est qu&#8217;une différence de convention, les concepts derrière sont les même.</p>
<h3>La caméra</h3>
<p>La caméra est définie par plusieurs paramètres :</p>
<ul>
<li>Sa position dans l&#8217;espace 3D</li>
<li>La position de sa cible (l&#8217;objet qu&#8217;elle filme en quelque sorte)</li>
<li>Son champs de vision (<strong>field of view</strong>)</li>
<li>La distance minimale qui définit le &#8220;<strong>near plane</strong>&#8220;</li>
<li>La distance maximale qui définit le &#8220;<strong>far plane</strong>&#8220;</li>
</ul>
<p>Ces informations permettent de définir une pyramide tronquée (un tronc, <strong>frustum</strong> en anglais) :</p>
<div id="attachment_343" class="wp-caption aligncenter" style="width: 621px"><a href="http://gamedev.dreamnoid.com/files/2009/11/camera1.png"><img class="size-full wp-image-343" title="camera" src="http://gamedev.dreamnoid.com/files/2009/11/camera1.png" alt="" width="611" height="449" /></a><p class="wp-caption-text">Le &quot;View Frustum&quot; défini par la caméra</p></div>
<p>Le champs de vision (abrégé <strong>FOV</strong>) est un angle qui définit ce que pourra voir le joueur. Le FOV est également utile pour réaliser un effet de zoom.</p>
<p>Le <strong>View Frustum</strong> permet d&#8217;utiliser une technique nommée <strong>Frustum Culling</strong> qui consiste à n&#8217;afficher que ce qui se trouve entre le &#8220;near plane&#8221; et le &#8220;far plane&#8221; :</p>
<div id="attachment_344" class="wp-caption aligncenter" style="width: 621px"><a href="http://gamedev.dreamnoid.com/files/2009/11/camera21.png"><img class="size-full wp-image-344" title="camera2" src="http://gamedev.dreamnoid.com/files/2009/11/camera21.png" alt="" width="611" height="449" /></a><p class="wp-caption-text">Frustum Culling, tout ce qui est dans la zone verte est affiché, le reste non</p></div>
<p>C&#8217;est cet effet que vous voyez à l&#8217;œuvre quand, dans un jeu vidéo, vous voyez un objet apparaitre soudainement au loin. En réalité l&#8217;objet qui se trouvait au delà du &#8220;far plane&#8221; se trouve désormais dans le view frustum et est affiché. On utilise généralement du brouillard (<strong>fog</strong>) au loin pour adoucir cet effet indésirable.</p>
<h3>Prochainement</h3>
<p>Dans le prochain article j&#8217;expliquerai comment sont décrites les formes en trois dimensions, pour que vous sachiez comment se décompose le personnage que vous voyez à l&#8217;écran.</p>
<p>On parlera de vertices et de triangles, de textures et de normales, etc.</p>
<p>En attendant, si vous avez des remarques, des questions ou des suggestions concernant cet article, les commentaires sont à votre disposition.</p>
<p><a href="http://www.planet-dev.com/developpement/les-bases-de-la-3d-partie-2">Le deuxième article est en ligne !</a></p>
]]></content:encoded>
			<wfw:commentRss>http://gamedev.dreamnoid.com/2009/11/12/les-bases-de-la-3d-partie-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Obtenir des infos sur la carte graphique avec OpenGL</title>
		<link>http://gamedev.dreamnoid.com/2009/07/09/infos_carte_graphique_opengl/</link>
		<comments>http://gamedev.dreamnoid.com/2009/07/09/infos_carte_graphique_opengl/#comments</comments>
		<pubDate>Thu, 09 Jul 2009 12:06:35 +0000</pubDate>
		<dc:creator>Dri</dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[3D]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[GCN]]></category>
		<category><![CDATA[GLSL]]></category>
		<category><![CDATA[OpenGL]]></category>
		<category><![CDATA[Tutoriel]]></category>

		<guid isPermaLink="false">http://www.planet-dev.com/?p=215</guid>
		<description><![CDATA[Comment récupérer des informations comme le modèle, les extensions ou le support des shaders d'une carte graphique avec l'API OpenGL]]></description>
			<content:encoded><![CDATA[<p>Quand on travaille avec OpenGL, on a souvent besoin d&#8217;obtenir des infos sur la carte graphique, notamment la liste des extensions supportées.</p>
<p>On va donc voir comment récupérer le vendeur, le modèle de la carte graphique, une liste d&#8217;extensions et déterminer la version des <em>shader models</em> implémentée.</p>
<p>Toute se fait au travers de la fonction <em>glGetString</em>.</p>
<p>glGetString renvoit une chaine de caractère contenant des informations fournies par le <em>driver</em> de la carte graphique :</p>
<ul>
<li><strong>GL_VENDOR</strong> : le vendeur de la carte graphique (ex: NVidia, ATI ou Intel)</li>
<li><strong>GL_RENDERER</strong> : le modèle exact de la carte graphique (ex: GeForce 8600 GT)</li>
<li><strong>GL_VERSION</strong> : la version d&#8217;OpenGL utilisée (ex: 2.0)</li>
<li><strong>GL_EXTENSIONS</strong> : une liste d&#8217;extensions séparées par des espaces</li>
</ul>
<h3>Récupérer la liste des extensions</h3>
<p>C&#8217;est surtout cette liste d&#8217;extensions qui nous intéresse, mais elle est difficilement exploitable en l&#8217;état, on va voir comment se faciliter la vie :</p>
<pre class="brush: cpp; title: ; notranslate">std::set Extensions;

std::string ext = std::string ( (const char*)glGetString ( GL_EXTENSIONS ) );

std::string extension = &quot;&quot;;
for ( std::size_t i = 0; i &lt; ext.size(); ++i )
{
	const char&amp; c = ext[i];
	if ( c != ' ' )
		extension += c;
	else
	{
		Extensions.insert ( extension );
		extension = &quot;&quot;;
	}
}</pre>
<p>Ce code va parcourir la chaine de caractère et rajouter chaque extension dans un <em>std::set</em>.</p>
<p>Pour savoir si une extension est supportée, il ne nous reste plus qu&#8217;a vérifier qu&#8217;elle est présente dans le <em>set</em> :</p>
<pre class="brush: cpp; title: ; notranslate">bool CheckExtension ( const std::string&amp; extension ) const
{
	return ( Extensions.find ( extension ) != Extensions.end() );
}</pre>
<p>On peut désormais tester la présence d&#8217;une extension facilement.</p>
<h3>Déterminer la présence des shaders GLSL</h3>
<p>Les shaders GLSL permettent de programmer la carte graphique à l&#8217;aide d&#8217;un langage haut niveau similaire au C (voir <a href="http://www.planet-dev.com/developpement/jeux-video/les-shaders-glsl-avec-irrlicht">Les shaders GLSL avec Irrlicht</a> et <a href="http://www.planet-dev.com/developpement/jeux-video/cel-shading-en-glsl">Cel Shading en GLSL</a>).</p>
<p>Pour déterminer si ces shaders sont disponibles, il faut vérifier la présence de quatre extensions :</p>
<ul>
<li>GL_ARB_shading_language_100</li>
<li>GL_ARB_shader_objects</li>
<li>GL_ARB_vertex_shader</li>
<li>GL_ARB_fragment_shader</li>
</ul>
<pre class="brush: cpp; title: ; notranslate">bool CheckGLSLSupport () const
{
	return (
		CheckExtension( &quot;GL_ARB_shading_language_100&quot; ) &amp;&amp; CheckExtension( &quot;GL_ARB_shader_objects&quot;       ) &amp;&amp;
		CheckExtension( &quot;GL_ARB_vertex_shader&quot;        ) &amp;&amp; CheckExtension( &quot;GL_ARB_fragment_shader&quot;      ));
}</pre>
<h3>Déterminer la version des shader models</h3>
<p>Il n&#8217;y a malheureusement aucune fonction directe pour déterminer le niveau de shader models.</p>
<p>Cependant, a chaque niveau de shaders models correspondent des extensions particulières :</p>
<ul>
<li><strong>SM 4</strong>:
<ul>
<li>GL_NV_gpu_program4</li>
<li>GL_NV_geometry_program4</li>
<li>GL_NV_vertex_program4</li>
<li>GL_NV_fragment_program4</li>
<li>GL_EXT_gpu_shader4</li>
<li>GL_EXT_geometry_shader4</li>
</ul>
</li>
<li><strong>SM 3</strong>:
<ul>
<li>GL_NV_vertex_program3</li>
<li>GL_NV_fragment_program2</li>
<li>GL_ATI_shader_texture_lod</li>
</ul>
</li>
</ul>
<p>Si vous n&#8217;avez ni les SM3 ni les SM4, mais que les shaders GLSL sont disponibles, alors vous avez les shader models 2.</p>
<p>Pour résumer :</p>
<pre class="brush: cpp; title: ; notranslate">int GetShaderModel () const
{
	if (
			CheckExtension(&quot;GL_NV_gpu_program4&quot;			) ||
			CheckExtension(&quot;GL_NV_geometry_program4&quot;	) ||
			CheckExtension(&quot;GL_NV_vertex_program4&quot;		) ||
			CheckExtension(&quot;GL_NV_fragment_program4&quot; 	) ||
			CheckExtension(&quot;GL_EXT_gpu_shader4&quot;		 	) ||
			CheckExtension(&quot;GL_EXT_geometry_shader4&quot;	)
		)
	{
		return 4;
	}
	else if (
				CheckExtension(&quot;GL_NV_vertex_program3&quot;		) ||
				CheckExtension(&quot;GL_NV_fragment_program2&quot;	) ||
				CheckExtension(&quot;GL_ATI_shader_texture_lod&quot;	)
			)
	{
		return 3;
	}
	else if ( HasGLSLSupport() )
	{
		return 2;
	}
	else
	{
		return 0;
	}
}</pre>
<p>Et voilà !</p>
<p>Maintenant vous disposez d&#8217;un petit arsenal pour mieux détecter les spécificités de la carte graphique, et adapter votre application en conséquence.</p>
]]></content:encoded>
			<wfw:commentRss>http://gamedev.dreamnoid.com/2009/07/09/infos_carte_graphique_opengl/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SFML et l&#8217;Unicode</title>
		<link>http://gamedev.dreamnoid.com/2009/07/05/sfml-unicode/</link>
		<comments>http://gamedev.dreamnoid.com/2009/07/05/sfml-unicode/#comments</comments>
		<pubDate>Sun, 05 Jul 2009 14:30:33 +0000</pubDate>
		<dc:creator>Dri</dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[GCN]]></category>
		<category><![CDATA[SFML]]></category>
		<category><![CDATA[Tutoriel]]></category>
		<category><![CDATA[Unicode]]></category>

		<guid isPermaLink="false">http://www.planet-dev.com/?p=209</guid>
		<description><![CDATA[Un tutoriel sur la gestion d'Unicode et des caractères spéciaux avec la bibliothèque graphique SFML]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.sfml-dev.org/index-fr.php">SFML</a> est un outil vraiment merveilleux. A se demander comment on a fait pour vivre sans, je me vois mal maintenant revenir vers la vieille SDL.</p>
<p>Habituellement j&#8217;utilise SFML pour le fenêtrage et la gestion des évènements, pour l&#8217;affichage j&#8217;utilise directement OpenGL (3D oblige).</p>
<p>Mais j&#8217;ai décidé de déléguer la gestion et l&#8217;affichage du texte à SFML pour deux raisons : TrueType et Unicode.</p>
<p>Si charger une font TrueType est simple et <a href="http://www.sfml-dev.org/tutorials/1.5/graphics-fonts-fr.php">bien décrit dans les tutoriaux</a>, afficher correctement les caractères Unicode est une autre histoire&#8230;</p>
<h3>Pré-requis</h3>
<p>Tout d&#8217;abord vous allez avoir besoin d&#8217;une font qui gère l&#8217;Unicode et propose tous les caractères nécessaires. Mon but était d&#8217;afficher les caractères japonnais, j&#8217;ai donc utilisé <strong>Arial Unicode MS</strong>, également utilisée par Firefox.</p>
<pre class="brush: cpp; title: ; notranslate">Font.LoadFromFile ( &quot;arial_unicode.ttf&quot; , 14 );
sf::String sftext ( text , Font , 14 );
Window.Draw ( sftext );</pre>
<p>Vous êtes surement familiers avec ce code, il se contente d&#8217;afficher le texte <em>text</em> avec la font <em>arial_unicode.ttf</em> de taille 14.</p>
<p>Attention toutefois, <em>text</em> ne <strong>doit pas</strong> être une <em>std::string</em> si vous comptez utiliser Unicode.</p>
<p><em>std::string</em> est une chaîne de caractères de type <em>char</em>, de l&#8217;ASCII donc. Utilisez donc son équivalent UTF-8 : <em>std::wstring</em> (pour &#8220;wide string&#8221;).</p>
<pre class="brush: cpp; title: ; notranslate">std::wstring text = L&quot;du texte !&quot;;</pre>
<p><em>std::wstring</em> s&#8217;utilise comme <em>std::string</em>, à la différence du <em>L</em> qui précède les chaines. Ce L sert à spécifier que la chaîne qui suit utilise l&#8217;encodage UTF-8 au lieu de l&#8217;ISO-8859-1.</p>
<p>Un exemple avec du texte japonais mélangé à du français (je tire ça d&#8217;un dico français/japonais) :</p>
<pre class="brush: cpp; title: ; notranslate">std::wstring text = L&quot;Texte Japonais : 月 【つき ・ tsuki 】 lune&quot;;</pre>
<p>Si vous utilisez cette chaîne de caractère avec le code précédent, vous verrez que seuls les caractères de l&#8217;alphabet latins s&#8217;affichent. C&#8217;est parce qu&#8217;il faut spécifier un <strong>charset</strong>.</p>
<h3>Le charset</h3>
<p>Le charset est un tableau d&#8217;<em>unsigned int</em> qui spécifie à SFML quels caractères il doit générer à partir de la font. En effet, pour pouvoir afficher du texte, il faut d&#8217;abord transformer les caractères en bitmaps. Et si tous les caractères Unicode devaient être rendus en bitmap, non seulement le temps de chargement serait long, mais la mémoire utilisée serait colossale (plus de 160Mo avec Arial Unicode MS de taille 24 !).</p>
<p>SFML nous laisse donc spécifier les caractères que l&#8217;ont veut générer, et par défaut ce sont les 256 premiers caractères (qui correspondent aux caractères ASCII et quelques étendus).</p>
<p>Les caractères sont identifiés par leur code (un <em>unsigned int</em> donc), et vous pouvez trouver les codes et leurs équivalents sur le site de l&#8217;Unicode : <a href="http://unicode.org/charts/">http://unicode.org/charts/</a>.</p>
<p>Chose à savoir, quand vous spécifiez le charset à SFML, le premier code spécifié doit être <em>0&#215;20</em>, sinon rien ne s&#8217;affichera.</p>
<p>Généralement les codes sont organisés en plages, par exemple : de 0&#215;20 à 0xFF pour les caractères Latins.</p>
<p>Voici donc un petit <em>snippet</em> permettant de spécifier un charset à SFML à partir d&#8217;une liste de plages :</p>
<pre class="brush: cpp; title: ; notranslate">// ===========================================================================================
/// A range of UTF-8 codes used to generate the final font charset
// ===========================================================================================
struct CharsetRange
{
	/// The minimum UTF-8 code
	unsigned int Min;

	/// The maximum UTF-8 code
	unsigned int Max;

	/// Get the range between the two UTF-8 codes
	unsigned int GetRange () const { return Max - Min + 1; }

	/// Constructor
	CharsetRange ( unsigned int min , unsigned int max ) : Min ( min ) , Max ( max ){}
};</pre>
<p>Cette structure représente une plage de codes consécutifs.</p>
<pre class="brush: cpp; title: ; notranslate">// ===========================================================================================
/// A charset is a set of UTF-8 codes organized as ranges
// ===========================================================================================
typedef std::vector&lt;CharsetRange&gt; Charset;</pre>
<p>Et ceci est notre charset : une liste de plages.</p>
<p>Maintenant on va récupérer cette liste de plages pour générer un tableau d&#8217;<em>unsigned int</em> que l&#8217;on spécifiera à SFML lors de la création de la font.</p>
<pre class="brush: cpp; title: ; notranslate">// ===========================================================================================
/// Set the current font
// ===========================================================================================
void SetFont ( const std::string&amp; filename , unsigned int size , const Charset&amp; ranges )
{

	// Determine the number of characters in the charset
	unsigned int totalRange = 0;
	if ( ranges.size() &gt; 0 )
	{
		for ( std::size_t i = 0; i &lt; ranges.size(); ++i )
			totalRange += ranges[i].GetRange();
	}
	else
		totalRange = 0xFF - 0x20;

	sf::Uint32 charset[totalRange];

	// Add the characters to the charset
	int it = 0;
	if ( ranges.size() &gt; 0 )
	{
		for ( std::size_t i = 0; i &lt; ranges.size(); ++i )
		{
			for ( unsigned int character = ranges[i].Min; character &lt;= ranges[i].Max; ++character )
			{
				charset[it++] = character;
			}
		}
	}
	else
	{
		for ( unsigned int character = 0x20; character &lt;= 0xFF; ++character )
		{
			charset[it++] = character;
		}
	}

	// Load the font
	if ( !Font.LoadFromFile ( filename , size , charset ) )
	{
		Font = sf::Font::GetDefaultFont();
	}
}</pre>
<p>Et voilà !</p>
<p>Vous remarquerez qu&#8217;il y a une vérification : si le <em>vector</em> est vide, on spécifie une plage par défaut.</p>
<p>Et pour ceux qui voudraient afficher des caractères japonais et qui ont du mal à trouver les plages correspondantes aux différents alphabets, les voici :</p>
<pre class="brush: cpp; title: ; notranslate">// ===========================================================================================
/// A list of default charsets
// ===========================================================================================
struct DefaultCharsets
{

	// ===========================================================================================
	/// Return the default charset for european and american characters
	// ===========================================================================================
	static Charset GetDefault()
	{
		Charset ranges;
		ranges.push_back ( CharsetRange ( 0x20 , 0xFF ) );		// ANSI
		return ranges;
	}

	// ===========================================================================================
	/// Return the japanese charset
	// ===========================================================================================
	static Charset GetJapanese()
	{
		Charset ranges;
		ranges.push_back ( CharsetRange ( 0x20 , 0xFF ) );	// ANSI
		ranges.push_back ( CharsetRange ( 0x3000 , 0x30FF ) );	// Hiragana
		ranges.push_back ( CharsetRange ( 0x30A0 , 0x30FF ) );	// Katakana
		ranges.push_back ( CharsetRange ( 0x31F0 , 0x31FF ) );	// Ainu
		ranges.push_back ( CharsetRange ( 0x4E00 , 0x9FAF ) );	// Kanji
		ranges.push_back ( CharsetRange ( 0xFF65 , 0xFFFF ) );	// Halfwidth katakana
		return ranges;
	}
};</pre>
<p>Je dois avouer avoir eu du mal à toutes les trouver&#8230;</p>
<p>C&#8217;est quand même assez incroyable à quel point les choses peuvent être simples quand on dispose de bons outils comme SFML !</p>
<p><a href="http://gamedev.dreamnoid.com/files/2009/07/SFML_unicode1.jpg"><img class="aligncenter size-medium wp-image-335" title="SFML et l'Unicode" src="http://gamedev.dreamnoid.com/files/2009/07/SFML_unicode1-300x250.jpg" alt="" width="300" height="250" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://gamedev.dreamnoid.com/2009/07/05/sfml-unicode/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>D2P Team</title>
		<link>http://gamedev.dreamnoid.com/2009/06/02/d2p-team/</link>
		<comments>http://gamedev.dreamnoid.com/2009/06/02/d2p-team/#comments</comments>
		<pubDate>Tue, 02 Jun 2009 18:53:31 +0000</pubDate>
		<dc:creator>Dri</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[D2P Games]]></category>
		<category><![CDATA[Projets]]></category>

		<guid isPermaLink="false">http://www.planet-dev.com/?p=203</guid>
		<description><![CDATA[Paul vient d&#8217;en parler sur son blog, une annonce surprise même pour les autres membres de la team. Alors D2P ça vient d&#8217;un brainstorming de quelques secondes et c&#8217;est l&#8217;acronyme de &#8220;Dax&#8221; , &#8220;Dri&#8221; et &#8220;Paul&#8221;, les surnoms (ou noms) des membres de l&#8217;équipe. Oui je sais, c&#8217;est d&#8217;une originalité terrible. Mais on s&#8217;en moque de ce qu&#8217;est D2P, ce qui nous intéresse c&#8217;est ce que fait et va faire D2P : du jeu vidéo. Pourquoi Depuis quelques années, le jeu vidéo s&#8217;est démocratisé à une vitesse ahurissante et a intégré le quotidien de la plupart des foyers.  En 2004, [...]]]></description>
			<content:encoded><![CDATA[<p>Paul vient d&#8217;en parler <a href="http://www.maboiteadisques.com/MGR/?post/2009/06/02/Quasi-officialisation-de-la-D2P-Team">sur son blog</a>, une annonce surprise même pour les autres membres de la team.</p>
<p>Alors D2P ça vient d&#8217;un brainstorming de quelques secondes et c&#8217;est l&#8217;acronyme de &#8220;Dax&#8221; , &#8220;Dri&#8221; et &#8220;Paul&#8221;, les surnoms (ou noms) des membres de l&#8217;équipe. Oui je sais, c&#8217;est d&#8217;une originalité terrible.</p>
<p>Mais on s&#8217;en moque de ce qu&#8217;est D2P, ce qui nous intéresse c&#8217;est ce que <strong>fait</strong> et <strong>va faire</strong> D2P : du jeu vidéo.</p>
<h3>Pourquoi</h3>
<p>Depuis quelques années, le jeu vidéo s&#8217;est démocratisé à une vitesse ahurissante et a intégré le quotidien de la plupart des foyers.  <a href="http://games.slashdot.org/games/04/12/19/2350234.shtml?tid=98&amp;tid=10">En 2004, l&#8217;industrie du jeu vidéo pouvait déjà se venter d&#8217;avoir dépassé Hollywood</a>. Et la tendance ne s&#8217;est pas inversée depuis, bien au contraire, on le voit avec le succès de la Nintendo DS et de la Wii : le marché du jeu vidéo grandit de jour en jour.</p>
<p>Pour notre part, nous avons toujours été passionné de jeu vidéo, personnellement ce fut ma porte d&#8217;entrée dans l&#8217;univers de l&#8217;informatique, alors nous avons décidés de &#8220;passer la seconde&#8221;, et de nous mettre au travail.</p>
<h3>Nos projets</h3>
<p>Nous compensons notre faible effectif et le peu de temps que nous avons  (pour le moment nous travaillons sur notre temps libre) par la technique et l&#8217;organisation.</p>
<p>La clé d&#8217;un travail efficace réside dans la qualité des outils employés, et c&#8217;est en grande partie mon rôle de m&#8217;assurer que tout aille bien de ce côté là.</p>
<p>Pour commencer, nous voulons toucher un public le plus large possible, nous voulons pouvoir déployer nos jeux sur quasiment toutes les plates-formes possibles et imaginables, avec le moins d&#8217;effort possible.</p>
<p><strong>Uniscript</strong> est la réponse à ce problème. Uniscript est un langage de script interprété qui fait sien la philosophie de Java : <em>&#8220;code once, run everywhere&#8221;</em>.</p>
<p>Concrètement, Uniscript est un langage très simple et très léger proposant tout de même le support de la programmation orientée objet. Son avantage par rapport aux autres langages de script est qu&#8217;il est très facile d&#8217;écrire un interpréteur pour ce langage (il y a peu d&#8217;instructions).</p>
<p>Un compilateur nous sert à transformer le code (qui partage en grande partie la syntaxe du C++) en bytecode, pour être ensuite exécuté par des machines virtuelles.</p>
<p>A chaque fois que nous portons nos jeux vers un nouveau support, nous créons une nouvelle machine virtuelle spécifique à ce support. Le code du jeu ne change absolument pas.</p>
<p>Un système d&#8217;extension nous permet de profiter de fonctionnalités en plus, offertes par certains supports.</p>
<p>Notre premier projet utilisant <strong>Uniscript</strong> sera un jeu orienté pour le web (Flash), à priori on se tournerait vers un <em>shoot em up</em>, même si nous ne sommes encore que dans la phase de conception et que tout peux changer.</p>
<h3>Les plans pour le futur</h3>
<p>Nous envisageons de monter une véritable structure l&#8217;an prochain (aux alentours de novembre surement) afin de travailler de façon plus officielle, et surtout à mi-temps (et non plus sur notre temps libre).</p>
<p>Les choses devraient donc s&#8217;accélérer à ce moment là.</p>
<p>En attendant, vous trouverez des informations régulièrement sur le blog de Paul : <a href="http://www.maboiteadisques.com/MGR/?">My Game Is Rich</a> et bien sur, ici même. Alors comme on dit, <em>stay tuned</em> !</p>
<p>PS : si Paul avait pu, c&#8217;est à Los Angeles qu&#8217;il aurait fait l&#8217;annonce je pense :p</p>
]]></content:encoded>
			<wfw:commentRss>http://gamedev.dreamnoid.com/2009/06/02/d2p-team/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cel Shading en GLSL</title>
		<link>http://gamedev.dreamnoid.com/2009/03/11/cel-shading-en-glsl/</link>
		<comments>http://gamedev.dreamnoid.com/2009/03/11/cel-shading-en-glsl/#comments</comments>
		<pubDate>Wed, 11 Mar 2009 19:07:29 +0000</pubDate>
		<dc:creator>Dri</dc:creator>
				<category><![CDATA[Jeux vidéo]]></category>
		<category><![CDATA[3D]]></category>
		<category><![CDATA[GCN]]></category>
		<category><![CDATA[GLSL]]></category>
		<category><![CDATA[OpenGL]]></category>
		<category><![CDATA[Shaders]]></category>
		<category><![CDATA[Tutoriel]]></category>

		<guid isPermaLink="false">http://www.planet-dev.com/?p=182</guid>
		<description><![CDATA[Un tutoriel pour faire un effet de cel shading (effet "dessin animé") avec OpenGL et GLSL]]></description>
			<content:encoded><![CDATA[<p>Un petit article rapide pour expliquer la création d&#8217;un effet de <strong>cel shading</strong> avec OpenGL et GLSL.</p>
<p>Le cel shading, c&#8217;est l&#8217; &#8220;effet cartoon&#8221; que vous pouvez voir à l&#8217;œuvre dans Jet Set Radio ou Zelda The Wind Waker.</p>
<p>Le nom de cet effet viens des <strong>cel</strong>lulos utilisés lors de la création d&#8217;un dessin animé, ce sont des feuilles de papier transparentes dont on peint le verso afin de colorier les personnages tracés au recto.</p>
<p>Toutefois, je n&#8217;expliquerai que la création du dégradé, pas des bordures noires. Ces dernières sont un autre sujet, passablement plus compliqué.</p>
<p>Je pars du principe que vous avez quelque base en GLSL, au moins savoir comment réaliser un shader tout simple (par exemple colorier un modèle en rouge).</p>
<p>Tout d&#8217;abord, analysons l&#8217;effet :</p>
<p style="text-align: left;">&nbsp;</p>
<div id="attachment_330" class="wp-caption aligncenter" style="width: 310px"><a href="http://gamedev.dreamnoid.com/files/2009/03/cel_zww1.jpg"><img class="size-medium wp-image-330" title="Cel shading de Zelda The Wind Waker" src="http://gamedev.dreamnoid.com/files/2009/03/cel_zww1-300x225.jpg" alt="" width="300" height="225" /></a><p class="wp-caption-text">Capture d&#39;écran de Zelda The Wind Waker</p></div>
<p>Ce qui donne cet effet cartoon, c&#8217;est avant tout les textures unies, les modèles non réalistes et les couleurs pastelles. Le but du shader sera d&#8217;appliquer les ombres sur le modèle 3D. Contrairement au rendu dit &#8220;photo-réaliste&#8221;, le cel shading emploie des ombres franches, bien marquées, comme dans les dessins animés.</p>
<h3 style="text-align: left;">Le Vertex Shader</h3>
<p>Le vertex shader est ici très simple, puisqu&#8217;il ne fait rien de spécial.</p>
<pre>varying vec3 Normal;

void main(void)
{

// Front color
gl_FrontColor = gl_Color;

// Determine the normal of the vertex
Normal = gl_NormalMatrix * gl_Normal;

// Textures coordinates
gl_TexCoord[0] = gl_MultiTexCoord0;

// The position of the vertex
gl_Position = ftransform();

}</pre>
<p>Si vous êtes un minimum familier avec GLSL, ce code vous sera sans doute très parlant. Il fait le minimum que l&#8217;on exige d&#8217;un vertex shader : transformer les sommets, récupérer les coordonnées de texture et déterminer les normales.</p>
<p>La variable Normal sera passée au pixel shader grâce au mot-clé <strong>varying</strong>.</p>
<h3>Le Pixel Shader</h3>
<p>Voyons maintenant un pixel shader tout simple, qui affiche le modèle 3D de façon unie :</p>
<pre>uniform sampler2D Texture0;

varying vec3 Normal;
void main (void)
{

vec4 color = texture2D( Texture0 , vec2( gl_TexCoord[0] ) );

gl_FragColor = color;
}</pre>
<p>Une fois de plus, le code est vraiment très simple : il se contente de récupérer le pixel sur la texture aux coordonnées données, puis déclare que c&#8217;est ce pixel là qui sera utilisé pour l&#8217;affichage.</p>
<p>Remarquez que l&#8217;on retrouve notre variable Normal qui est la normale du sommet, on va en avoir besoin pour réaliser le cel shading.</p>
<p>Comme tout modèle d&#8217;éclairage, le cel shading a besoin d&#8217;une lumière pour fonctionner. Pour faire simple, on va se content de gérer une seule source de lumière, incolore.</p>
<p>On va donc rajouter dans la déclaration des variables la direction de la lumière  :</p>
<pre>uniform vec3 LightDir;</pre>
<p>En général, on s&#8217;en sert pour représenter le soleil.</p>
<p>Créons maintenant une nouvelle fonction :</p>
<pre>vec4 CelShading ( vec4 color )

{

return color;

}</pre>
<p>que l&#8217;on va appeller comme ceci :</p>
<pre>void main (void)
{

vec4 color = texture2D( Texture0 , vec2( gl_TexCoord[0] ) );

color = CelShading ( color );

gl_FragColor = color;
}</pre>
<p>C&#8217;est dans cette fonction que l&#8217;on appliquera l&#8217;effet du cel shading. L&#8217;avantage de le faire dans une fonction plutôt que directement dans main est multiple :</p>
<ul>
<li>Vous pouvez rajouter une couche de &#8220;pré-processeur&#8221; à votre code qui gère les programmes afin de réaliser un équivalent du #include du C/C++ : dans ce cas vous pourrez séparer vos différents effets dans différents fichiers.</li>
<li>Et ainsi mélanger les effets entre eux facilement, par exemple :</li>
</ul>
<pre>color = RimLighting ( color );
color = CelShading ( color );</pre>
<p>(Pour info, le Rim lighting est la technique appliquant à un modèle 3D une fausse lumière semblant venir de derrière lui. Mario Galaxy l&#8217;utilise sans cesse)</p>
<p>Revenons à notre fonction, on va calculer l&#8217;intensité de la lumière à un point donné :</p>
<pre>float Intensity = dot( LightDir , normalize(Normal) );</pre>
<p>C&#8217;est actuellement la partie la plus compliqué du cel shading (si si !).</p>
<p>On fait un <a href="http://fr.wikipedia.org/wiki/Produit_scalaire">produit scalaire</a> entre le vecteur tracé entre la direction de la lumière, et la normale de notre sommet. Cela nous retourne l&#8217;intensité de la lumière sur ce dit sommet.</p>
<p>Mon but n&#8217;est pas d&#8217;expliquer la partie mathématique derrière tout ça&#8230; je pense que j&#8217;en serai bien incapable !</p>
<p>L&#8217;intensité est une valeur entre 0 et 1. 0 signifie pas éclairé, et 1 entièrement éclairé.</p>
<p>Prenez le temps d&#8217;essayer ce code :</p>
<pre>vec4 CelShading ( vec4 color )
{
float Intensity = dot( LightDir , normalize(Normal) );

float factor = Intensity;

color *= vec4 ( factor, factor, factor, 1.0 );

return color;
}</pre>
<p>On a alors un ombrage de Gouraud (<strong>gouraud shading</strong>), les ombres sont douces, il y a un dégradé.</p>
<p>Notre but sera de &#8220;casser&#8221; ce dégradé pour faire des ombres franches.</p>
<p>Comment faire ? C&#8217;est très simple : en testant la valeur de l&#8217;intensité non plus comme une valeur linéaire, mais comme des bornes.</p>
<pre>vec4 CelShading ( vec4 color )
{
float Intensity = dot( LightDir , normalize(Normal) );
float factor = 1.0;
if ( Intensity &lt; 0.5 ) factor = 0.5;
color *= vec4 ( factor, factor, factor, 1.0 );

return color;
}</pre>
<p>Si l&#8217;intensité est inférieure à 0,5 (la moitié), alors on obscurcit le pixel, sinon (si c&#8217;est au dessus), on le laisse tel quel.</p>
<p>L&#8217;effet est là :</p>
<p style="text-align: left;">&nbsp;</p>
<div id="attachment_331" class="wp-caption aligncenter" style="width: 310px"><a href="http://gamedev.dreamnoid.com/files/2009/03/01_glsl_shaders_celshading_.jpg"><img class="size-medium wp-image-331" title="Cel Shading en GLSL" src="http://gamedev.dreamnoid.com/files/2009/03/01_glsl_shaders_celshading_-300x225.jpg" alt="" width="300" height="225" /></a><p class="wp-caption-text">L&#39;effet de cel shading</p></div>
<p>Il est désormais possible de faire des réglages, par exemple en rajoutant plusieurs étapes au dégradé :</p>
<pre>float factor = 0.5;

if      ( Intensity &gt; 0.95 ) factor = 1.0;
else if ( Intensity &gt; 0.5  ) factor = 0.7;
else if ( Intensity &gt; 0.25 ) factor = 0.4;</pre>
<p style="text-align: left;">&nbsp;</p>
<p style="text-align: left;">Maintenant c&#8217;est à vous d&#8217;expérimenter !</p>
]]></content:encoded>
			<wfw:commentRss>http://gamedev.dreamnoid.com/2009/03/11/cel-shading-en-glsl/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Afficher un sprite</title>
		<link>http://gamedev.dreamnoid.com/2009/02/09/afficher-un-sprite/</link>
		<comments>http://gamedev.dreamnoid.com/2009/02/09/afficher-un-sprite/#comments</comments>
		<pubDate>Mon, 09 Feb 2009 11:50:45 +0000</pubDate>
		<dc:creator>Dri</dc:creator>
				<category><![CDATA[XNA]]></category>
		<category><![CDATA[2D]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Tutoriel]]></category>

		<guid isPermaLink="false">http://www.planet-dev.com/?p=119</guid>
		<description><![CDATA[Dans le précédent article nous avons préparé notre projet. Cet article a pu paraitre un peu compliqué et rebutant, je le conçois. C&#8217;est parce qu&#8217;il montre une façon non conventionnelle d&#8217;installer XNA. Rassurez-vous, ce qui est fait n&#8217;est plus à faire et cet article (ainsi que ceux qui suivront) seront plus simples et plus intéressants. Maintenant que vous voilà rassurés, place à la 2D ! Notre but dans cette étape est de gérer l&#8217;affichage dans notre programme et d&#8217;afficher une image à l&#8217;écran. Cela n&#8217;a rien de compliqué, bien au contraire. La théorie Avant d&#8217;implémenter quoi que ce soit nous [...]]]></description>
			<content:encoded><![CDATA[<p>Dans <a href="http://www.planet-dev.com/developpement/xna/xna-un-premier-programme">le précédent article</a> nous avons préparé notre projet. Cet article a pu paraitre un peu compliqué et rebutant, je le conçois. C&#8217;est parce qu&#8217;il montre une façon non conventionnelle d&#8217;installer XNA.</p>
<p>Rassurez-vous, ce qui est fait n&#8217;est plus à faire et cet article (ainsi que ceux qui suivront) seront plus simples et plus intéressants.</p>
<p>Maintenant que vous voilà rassurés, place à la 2D !</p>
<p>Notre but dans cette étape est de gérer l&#8217;affichage dans notre programme et d&#8217;afficher une image à l&#8217;écran.</p>
<p>Cela n&#8217;a rien de compliqué, bien au contraire.</p>
<h2>La théorie</h2>
<p>Avant d&#8217;implémenter quoi que ce soit nous devons comprendre comment fonctionne un jeu.</p>
<p style="text-align: center;"><a href="http://gamedev.dreamnoid.com/wp-content/uploads/2008/09/boucle_jeu.png"><img class="size-full wp-image-121 aligncenter" src="http://gamedev.dreamnoid.com/wp-content/uploads/2008/09/boucle_jeu.png" alt="Shéma montrant une boucle de jeu classique" /></a></p>
<p>Un jeu est en perpétuelle évolution, il est sans arrêt mis à jour. L&#8217;emploi d&#8217;une &#8220;boucle infinie&#8221; qui ne s&#8217;arrête que lorsque le jeu est quitté est la base de tout jeu vidéo.<br />
Voyons les différentes étapes en détails :</p>
<p><strong>Initialisation :</strong> c&#8217;est dans cette étape que nous chargeons nos ressources : images, sons, modèles 3D, etc. Nous préparons le terrain pour la suite, c&#8217;est le chargement du jeu.</p>
<p><strong>Traitements : </strong>la gestion du jeu en lui même. C&#8217;est cette partie qui s&#8217;occupera de prendre en charge les contrôles du jeu. C&#8217;est là qu&#8217;intervient toute la logique du jeu, comme l&#8217;IA par exemple.</p>
<p><strong>Affichage :</strong> maintenant que la situation du jeu est à jour, il faut que le joueur en ai un retour. C&#8217;est le but de l&#8217;affichage : envoyer au joueur une image qui reflète la situation actuelle. C&#8217;est sur cette partie que nous allons nous concentrer cette fois-ci.</p>
<p><strong>Libération : </strong>sous entendu, des ressources. On fait le ménage en quelque sorte, on passe le balais après la fête. Il s&#8217;agit de détruire toutes les ressources chargées et de rendre la main au système.</p>
<p>Si vous regardez bien, la partie &#8220;libération&#8221; mise à part, cela correspond exactement aux trois méthodes de l&#8217;objet GameManager créer précédemment :</p>
<pre>protected override void Initialize ()
{
	base.Initialize ();
}

protected override void Update ( GameTime gameTime )
{
	base.Update ( gameTime );
}

protected override void Draw ( GameTime gameTime )
{
	base.Draw ( gameTime );
}</pre>
<p>XNA s&#8217;occupe donc déjà de mettre en place cette boucle de jeu, tout ce que nous avons à faire c&#8217;est compléter ces trois fonctions.</p>
<p>Il sera peut être nécessaire de rajouter une méthode &#8220;Delete&#8221; à notre objet GameManager, mais pour le moment le <em>Garbage Collector</em> du framework .NET fera très bien l&#8217;affaire.</p>
<p>Revenons-en donc à notre boucle infinie, et notamment à la partie &#8220;affichage&#8221;.</p>
<p>Pour bien comprendre comment marche l&#8217;affichage dans un jeu vidéo, il faut comprendre le <strong>double buffering</strong>.</p>
<p>Le principe du double buffering est simple : afficher une image prend du temps, on ne peut donc pas se permettre de l&#8217;afficher directement à l&#8217;écran. Ou alors le joueur verrait l&#8217;image se construire sous ses yeux, très rapidement, ce qui provoquerait un scintillement permanent des plus déplaisants.</p>
<p>Il faut donc tout dessiner sur un autre écran, caché, et permuter les deux lorsque tout est prêt. C&#8217;est le principe même du double buffering : dessiner sur le <strong>back buffer</strong> (la mémoire de la carte graphique) puis échanger avec le <strong>front buffer</strong> (l&#8217;écran).</p>
<p>Cette notion est très importante.</p>
<p>Une fois que les deux buffers ont été permutés et que l&#8217;image finale apparait à l&#8217;écran, il convient de dessiner la suivante. Pour cela nous devons d&#8217;abord <strong>effacer la précédente</strong> qui est restée dans le buffer.</p>
<p>Ensuite nous redessineront notre scène, puis nous invertirons de nouveau les buffers. Et <em>bis repetita</em>.</p>
<p>L&#8217;opération doit se faire au moins 24 fois par secondes pour que l&#8217;animation soit crédible et que l&#8217;œil la voie bien comme une animation, et pas une simple suite d&#8217;images. Toutefois, la <strong>fréquence de rafraichissement</strong> idéale est celle de l&#8217;écran. Le nombre d&#8217;images dessinées par seconde est alors appelé <strong>framerate</strong> ou <strong>FPS</strong> (frames per seconds).</p>
<p>C&#8217;est quelque chose que vous retrouverez tout le temps par la suite, le FPS est notamment un très bon indicateur de performances.</p>
<p>Notre fonction d&#8217;affichage se résume alors à :</p>
<ol>
<li>Effacer le contenu du back buffer</li>
<li>Afficher nos images</li>
<li>Dire à la carte graphique qu&#8217;il est temps d&#8217;intervertir les buffers</li>
</ol>
<p>Par chance, XNA s&#8217;occupe tout seul de la dernière étape.</p>
<h2>GraphicManager</h2>
<p>Toujours a la recherche d&#8217;une architecture propre pour notre programme, nous allons créer une classe pour gérer l&#8217;affichage.</p>
<p>On va alors créer une classe <strong>GraphicManager</strong> :</p>
<pre>using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace ArticleXNA
{
    class GraphicManager
    {
	public GraphicManager ( GameManager game )
	{

	}
    }
}</pre>
<p>C&#8217;est notre GameManager qui s&#8217;occupera de gérer le GraphicManager, il lui faudra donc une référence vers l&#8217;objet :</p>
<pre>private GraphicManager _GraphicManager = null;</pre>
<p>Et dans la méthode <em>Initialize</em> :</p>
<pre>protected override void Initialize ()
{
_GraphicManager = new GraphicManager ( this );

base.Initialize ();
}</pre>
<p>Nous passons une référence à notre game manager vers GraphicManager pour pouvoir créer un <strong>GraphicDeviceManager</strong><span style="color: #888888;">.</span></p>
<p>Cette classe est celle qui s&#8217;occupe de gérer le contexte graphique (<strong>GraphicDevice</strong>) sous XNA. Elle s&#8217;occupera notamment de le recréer si besoin est (par exemple lorsqu&#8217;on minimise le jeu en plein écran).</p>
<pre>class GraphicManager
{

    public GraphicManager ( GameManager game )
    {
        _GDM = new GraphicsDeviceManager ( game );
    }

    private GraphicsDeviceManager _GDM = null;

}</pre>
<p>C&#8217;est à cet objet que nous fournirons des informations telle la résolution du jeu, si on l&#8217;affiche en plein écran ou pas, etc.</p>
<pre>_GDM.PreferredBackBufferWidth = 800;

_GDM.PreferredBackBufferHeight = 600;

_GDM.IsFullScreen = false;

_GDM.ApplyChanges ();</pre>
<p>Notre fenêtre devrait désormais avoir une taille de 800*600 pixels.</p>
<h2>L&#8217;affichage : SpriteBatch</h2>
<p>De nos jours, la 2D n&#8217;est plus que de la 3D sans profondeur. La 2D est donc gérée exactement comme la 3D par la carte graphique, à l&#8217;exception près que la perspective est remplacée par une projection orthogonale (concrètement, la caméra fait face à la scène).</p>
<p>Heureusement, XNA nous simplifie la tâche en nous proposant de faire de la 2D facilement, sans connaissances en 3D.</p>
<p>Tout cela se fait par l&#8217;intermédiaire de la classe <strong>SpriteBatch</strong>.</p>
<p>Nous allons donc rajouter une instance de SpriteBatch dans notre GraphicManager :</p>
<pre>private SpriteBatch _SpriteBatch = null;</pre>
<p>Et dans le constructeur :</p>
<pre>public GraphicManager ( GameManager game )
{
    _GDM = new GraphicsDeviceManager ( game );
    _GDM.PreferredBackBufferWidth = 800;
    _GDM.PreferredBackBufferHeight = 600;
    _GDM.IsFullScreen = false;
    _GDM.ApplyChanges ();

    _SpriteBatch = new SpriteBatch ( _GDM.GraphicsDevice );
}</pre>
<p>Pour afficher un sprite, il faut le faire entre les instructions Begin() et End() de SpriteBatch.</p>
<p>Un sprite est une texture (une image) que l&#8217;on affiche à une position donnée, pour charger une texture avec XNA, on a deux solutions :</p>
<ol>
<li>Passer par le Content Pipeline, l&#8217;avantage est que c&#8217;est portable sur XBox 260, le problème, c&#8217;est game studio (il faut rajouter l&#8217;image à sa solution Visual Studio&#8230;)</li>
<li>Pour Windows uniquement : Texture2D.FromFile ( _GDM.GraphicsDevice , &#8220;texture.jpg&#8221; )</li>
</ol>
<p>Par exemple :</p>
<pre>Texture2D TextureLogo = Texture2D.FromFile ( _GDM.GraphicsDevice , "logo.png" );</pre>
<p>Puis pour l&#8217;afficher :</p>
<pre>_SpriteBatch.Begin ();
_SpriteBatch.Draw ( TextureLogo , new Vector2 () , Color.White );
_SpriteBatch.End ();</pre>
<p>On spécifie la position en second argument, et la couleur qui agira comme un filtre.</p>
<p>La position est définie par ses composantes X (abscisses) et Y (ordonnées) de la façon suivante :</p>
<p style="text-align: center;"><a href="http://gamedev.dreamnoid.com/wp-content/uploads/2008/09/ecran2d.png"><img class="size-full wp-image-175 aligncenter" src="http://gamedev.dreamnoid.com/wp-content/uploads/2008/09/ecran2d.png" alt="Le système de coordonnées pour un écran 2D" /></a></p>
<p>Avec le code suivant, on obtient :</p>
<p><a href="http://gamedev.dreamnoid.com/wp-content/uploads/2008/09/seconde_app.png"><img class="size-medium wp-image-176 aligncenter" src="http://gamedev.dreamnoid.com/wp-content/uploads/2008/09/seconde_app.png" alt="Notre seconde application qui affiche un sprite à l'écran" /></a></p>
<p>Voici le code source complet (mais temporaire) :</p>
<p>GameManager.cs</p>
<pre>using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace ArticleXNA
{
    class GameManager : Game
    {

        public GameManager ()
        {
            _GraphicManager = new GraphicManager ( this );
        }

        protected override void Initialize ()
        {
            Window.Title = "Article XNA";
            IsMouseVisible = true;

            _GraphicManager.Initialize ( 800 , 600 , false );

            base.Initialize ();
        }

        protected override void Update ( GameTime gameTime )
        {
            base.Update ( gameTime );
        }

        protected override void Draw ( GameTime gameTime )
        {
            _GraphicManager.Clear ();

            base.Draw ( gameTime );
        }

        private GraphicManager _GraphicManager = null;

    }
}</pre>
<p>GraphicManager.cs</p>
<pre>using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace ArticleXNA
{
    class GraphicManager
    {

        public GraphicManager ( GameManager game )
        {

            _GDM = new GraphicsDeviceManager ( game );

        }

        public void Initialize (int width , int height , bool fullscreen)
        {
            _SpriteBatch = new SpriteBatch ( _GDM.GraphicsDevice );

            _GDM.PreferredBackBufferWidth = 800;
            _GDM.PreferredBackBufferHeight = 600;
            _GDM.IsFullScreen = false;

            _GDM.ApplyChanges ();

            // Cela n'a en pratique rien à faire dans le GraphicManager, il est ici pour l'exemple !
            TextureLogo = Texture2D.FromFile ( _GDM.GraphicsDevice , "logo.png" );
        }

        public void Clear ()
        {
            _GDM.GraphicsDevice.Clear ( Color.CornflowerBlue );

            // Cela n'a en pratique rien à faire dans le GraphicManager, il est ici pour l'exemple !
            _SpriteBatch.Begin ();
            _SpriteBatch.Draw ( TextureLogo , new Vector2 () , Color.White );
            _SpriteBatch.End ();

        }

        private GraphicsDeviceManager _GDM = null;
        private SpriteBatch _SpriteBatch = null;

        // Cela n'a en pratique rien à faire dans le GraphicManager, il est ici pour l'exemple !
        private Texture2D TextureLogo = null;

    }
}</pre>
<p>Program.cs</p>
<pre>using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ArticleXNA
{
    class Program
    {
        static void Main ( string[] args )
        {
            try
            {

                GameManager game = new GameManager ();

                game.Run ();

            }
            catch ( Exception e )
            {
                Console.WriteLine ( e.ToString () );
            }
        }
    }
</pre>
]]></content:encoded>
			<wfw:commentRss>http://gamedev.dreamnoid.com/2009/02/09/afficher-un-sprite/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

