Archives de
Catégorie : Flixel

Flixel : Afficher et animer un Sprite

Flixel : Afficher et animer un Sprite

Dans le dernier tutoriel Flash je vous ai présenté Flixel, une bibliothèque très puissante qui permet de créer rapidement des jeux type arcade (mais pas que 😉 ). Aujourd’hui nous allons poursuivre notre découverte et voir comment afficher, animer et déplacer un personnage en utilisant la classe FlxSprite. Je vous invite à récupérer la feuille de sprite ci-dessous qui sera utilisée tout au long de ce tutoriel.

spritesheet-mario
Une feuille de sprite avec Mario

Les Sprite sheet

Une « Sprite Sheet » ou feuille de Sprite en Français, est une image qui contient en général un personnage avec toutes ses animations. Vous pouvez voir sur l’image du dessus qu’il y a 4 animations : bas, gauche, droite, haut. Lorsque vous utiliserez une feuille de Sprite il faudra récupérer les informations suivantes avant d’aller plus loin :

  1. Largeur et hauteur d’un Sprite
  2. Largeur et hauteur de la feuille de Sprite
  3. Nombre d’image par animation

L’image que nous utilisons ici fait 200 pixels de largeur pour 276 pixels de hauteur et il y a 4 animations différentes. On obtient donc la largeur et la hauteur d’un sprite comme suis :

var spriteWidth:int = 200 / 4; // soit 50px
var spriteHeight:int = 277 / 4; // soit 69px

Flixel ne va pas afficher l’image entière mais juste une partie qui correspondra à un Sprite parmi ceux présents sur la feuille. Vous pouvez voir l’image comme un tableau à 2 dimensions où chaque image de personnage correspond à un indice du tableau. Ainsi la première image de la feuille a l’index 0, la deuxième 1, la troisième 2, etc… Le sens de lecture de gauche à droite et du haut vers le bas. L’indice de la dernière image de notre feuille de Sprite est donc 15 😛 ((4 x 8) – 1).

Maintenant que nous avons ces informations, passons à la pratique ! La première étape conscite à créer un objet de type FlxSprite, il sera un conteneur graphique représentant notre personnage. Cette classe contient une méthode addAnimation() qui va découper et afficher pour nous, les bonnes images, quand il faudra. Dans un premier temps créez simplement un nouveau projet Flixel et copiez l’image dans le dossier assets (à créer si vous ne l’avez pas déjà fait).

Pour créer un nouveau Sprite avec Flixel, il faut instancier un objet de type FlxSprite, ou dérivé.

var sprite:FlxSprite = new FlxSprite(positionX, positionY);

Ce code va créer un objet graphique de type FlxSprite aux coordonnées positionX, positionY et il n’aura aucune apparence. Pour lui attacher une image vous pouvez soit le faire à la construction, soit le faire après avec la méthode loadGraphic().

// A la création
var sprite:FlxSprite = new FlxSprite(positionX, positionY, image);

// Ou après la création
sprite.loadGraphic(image);

On peut créer directement un Sprite avec une seule image mais dans notre cas on veut un sprite animé qui utilise une feuille de Sprite, on ne peux donc pas donner l’image avec toutes les animations au constructeur de FlxSprite. La méthode loadGraphic() sera donc utilisée, elle prend plusieurs paramètres qui permettent d’indiquer à Flixel si l’image à utilisée doit être découpée et si le Sprite doit être animé.

loadGraphic(image:Class, animer:Boolean, inverser:Boolean, largeur:int, hauteur:int)

Les noms des paramètres sont assez explicites je pense 😉 Vous aurez remarqué que les 2 dernières valeurs permettent de spécifier la taille final de l’image (le sprite animé). Il est donc très important d’avoir des feuilles de Sprites correctement réalisées, avec des valeurs en hauteur et largeur juste (on ne veux pas un sprite de 45.45654px de largeur par exemple). Passons maintenant au code.

Main.as : Le point de démarrage

package
{
  import org.flixel.FlxGame;

  [SWF(width="640", height="480", backgroundColor="#00000000")]
  public class Main extends FlxGame
  {
    public function Main():void
    {
      super(640, 480, PlayState);
    }
  }
}

On se contente d’initialiser Flixel en dérivant FlxGame, le jeu sera lancé avec une résolution de 640×480. On passe en 3éme paramètre la classe à instancier après l’initialisation, PlayState dans notre cas.

PlayState.as : L’écran de jeu

package
{
  import org.flixel.FlxState;

  public class PlayState extends FlxState
  {
    // Le joueur (Sprite) animé
    private var _player:Player;

    // Le constructeur reste vide
    public function PlayState() { }

    // Création du Joueur et ajout à la liste d'affichage
    override public function create():void
    {
      _player = new Player();
      add(_player);
    }
  }
}

La classe PlayState représente l’écran de jeu et elle doit dériver de FlxState. On surcharge la méthode create() pour initialiser l’objet Player (voir plus bas) qui est le joueur. Toutes les modifications logiques ou visuelles du joueur sont réalisées dans la classe Player.

Player.as : Le joueur, ses animations, sa gestion

package
{
  import org.flixel.FlxPoint;
  import org.flixel.FlxSprite;
  import org.flixel.FlxG;

  public class Player extends FlxSprite
  {
    [Embed("../assets/spritesheet-mario.png")]
    private const SpriteSheetMario:Class;

    public function Player()
    {
      super(0, 0);

       loadGraphic(SpriteSheetMario, true, false, 50, 69);

	// Création de ses animations
	// 1 - Nom de l'animation
	// 2 - partie de l'image à prendre pour cette animation
	// 3 - Vitesse de transition entre chaque image
	// 4 - Répétition à l'arrêt
	addAnimation("down", [0, 1, 2, 3], 10, false);
	addAnimation("left", [4, 5, 6, 7], 10, false);
	addAnimation("right", [8, 9, 10, 11], 10, false);
	addAnimation("up", [12, 13, 14, 15], 10, false);

	// Position au centre de l'écran
	this.x = (FlxG.width / 2) - (this.width / 2);
	this.y = (FlxG.height / 2) - (this.height / 2);
      }

      override public function update():void
      {
        super.update();

	// Déplacement du personnage
	// Mise à jour de l'animation à jouer
	if (FlxG.keys.UP)
	{
	  this.y--;
	  play("up");
	}

	if (FlxG.keys.DOWN)
	{
	  this.y++;
	  play("down");
	}

	if (FlxG.keys.LEFT)
	{
	  this.x--;
	  play("left");
	}

	if (FlxG.keys.RIGHT)
	{
	  this.x++;
	  play("right");
	}
      }
   }
}

La première étape consiste à charger la feuille de Sprite, c’est une image donc rien de plus simple. Le constructeur de la classe mère est ensuite appelé et positionne l’objet aux coordonnées 0, 0 par rapport au coin en haut à gauche de l’écran. Un appel à la méthode loadGraphic() permet de configurer l’objet graphique en lui attachant une image et en spécifiant que ce sprite sera animé (valeur true en 2éme paramètre).

addAnimation("down", [0, 1, 2, 3], 10, false);

C’est dans cette méthode que les animations sont explicitement déclarées, on passe en premier le nom de l’animation puis un tableau d’indice qui correspondent à une ou plusieurs images de la feuille de Sprite. Enfin on spécifie le temps de transition entre chaque image et on désactive la répétition.

Si on prend l’extrait de code précédent vous pouvez voir que j’ai passé en paramètre un tableau de 4 valeurs (0, 1, 2, 3). C’est le fameux tableau d’indice qui permet d’identifier chaque image de la feuille de Sprite. L’animation « bas » par exemple utilise les images 0, 1, 2 et 3.

if (FlxG.keys.RIGHT)
{
  this.x++;
  play("right");
}

Jouer une animation est vraiment simple, il faut utiliser la méthode play() avec le nom de l’animation en paramètre et le tour est joué il n’y a pas besoin de faire autre chose ! Vous aurez remarqué qu’on utilise aussi l’objet FlxG pour récupérer la touche pressée. FlxG.keys.#TOUCHE# prendra la valeur true si la touche #TOUCHE# est pressée. Je vous invite à consulter la documentation pour plus d’informations.

Conclusion

Nous avons vue aujourd’hui comment charger, afficher, animer et déplacer un Sprite avec Flixel. Le Framework nous simplifie vraiment beaucoup le travail car il suffit juste d’avoir une feuille de Sprite bien faite, avec les bonnes informations (les tailles et le nombre d’animations) pour avoir un personnage animé très rapidement.

Flixel propose encore beaucoup de fonctionnalités magiques, comme la caméra qui vous permettra de créer des niveaux avec scrolling en 2 lignes de code 🙂 Nous verrons ça très prochainement dans un article dédié à la camera et son utilisation. Vous pouvez retrouver le projet entier sur mon espace Github.

A la découverte de Flixel

A la découverte de Flixel

Bienvenue dans cette nouvelle série de tutoriels consacrés à Flixel, une bibliothèque Open Source écrite en ActionScript 3 qui va nous permettre de créer très facilement et très rapidement des jeux de type arcade et rétro. En réalité nous pouvons même parler de moteur car Flixel embarque un tas de classes et d’outils pour nous faciliter la vie dans nos développement. Rassurez vous, vous pouvez faire ce que vous voulez comme jeu, mais Flixel est avant tout dédiée au monde des jeux rétro et arcade.

Présentation des fonctionnalités

  • Gestion avancée des Sprites et des animations de Sprites ;
  • Gestion des cartes (tilemap) de jeu au format CSV et des caméras (scrolling, etc…) ;
  • Gestion des collisions entre Sprites et entre groupes de Sprites ;
  • Gestion facile du clavier et de la souris ;
  • Enregistrement et lecture de « replay » ;
  • Possibilité de faire du « Split Screen » (écran coupé en deux pour le mode 2 joueurs) ;
  • Algorithme de Pathfinding ;
  • Possibilité d’utiliser des plugins ;
  • Et bien plus encore.

Je vous invite d’ailleurs à aller sur la page des fonctionnalités de Flixel et de tester les différentes démonstrations technique pour vous faire un avis sur les possibilité de ce petit bijoux 🙂

Enfin pour terminer cette petite introduction, voici quelques exemples de jeux réalisés avec Flixel (source flixelgames.net):

Spuck Gamma4 Entry G-Switch Grave e Tea
Essayer Spuck Gamma4 Entry Essayer G Switch Essayer Grave e Tea

Téléchargement et installation

Rendez vous sur la page de téléchargement et récupérez la version « Latest Master » qui correspond à la dernière version stable du moteur, quand vous serez plus à l’aise avec Flixel vous pourrez essayer les versions de développement (beta et dev) pour tester les dernières fonctionnalités. Nous avons vue dans le premier tutoriel consacré à ActionScript 3 comment installer une bibliothèque externe sous Windows avec FlashDevelop et sous Linux ou Mac OS X en ligne de commande, c’est donc ici exactement pareil, vous décompressez le dossier org de l’archive dans le dossier lib de votre projet, ensuite il faut mettre à jour le classpath du projet.

Une autre méthode simple consiste à copier directement le dossier org dans le dossier src de votre projet, de là vous n’avez pas besoin de mettre à jour le classpath car le moteur Flixel sera directement intégré à votre projet. Cette méthode est pratique pour les tests et les petits projets (on peut compiler très facilement en ligne de commande).

Vous pouvez donc choisir la méthode que vous voulez, dans la pratique j’utilise le dossier lib quand je travail sur un vrai projet car j’aime séparer mon code, cependant sur des petits projets ou des exemple je copie systématiquement le dossier lib dans src.

FlxGame : le point d’entrée du jeu

La première étape va être de créer un fichier Main.as dans le dossier src. Le point d’entrée de votre jeu se trouvera dans le constructeur de la classe Main qui contiendra le code nécessaire à l’initialisation de Flixel. La classe Main devra alors hériter de la classe FlxGame qui est le cœur de tout jeu reposant sur Flixel. Voyons tout de suite comment initialiser Flixel.

package
{
	import org.flixel.FlxGame;

	public class Main extends FlxGame
	{
		public function Main():void
		{
			super(800, 600, GameState, 1);
		}
	}
}

Le code est relativement simple et il n’y a presque rien à faire, on fait dériver Main de FlxGame puis on appel le constructeur de la classe mère avec les paramètres suivants :

  1. GameSizeX:uint -> Largeur de la fenêtre (800 px)
  2. GameSizeY:uint -> Hauteur de la fenêtre (600px)
  3. InitialState:Class -> Classe à instancier lors du démarrage du jeu (de type FlxState)
  4. Zoom:Number  -> (par defaut 1) Taux de zoom à appliquer

La classe à instancier au lancement doit dériver de FlxState et représentera une partie visuelle de votre jeu (le menu, l’écran de jeu, l’écran de game over, etc…), on spécifie un nom de classe et pas directement un objet car c’est Flixel qui va se charger d’instancier pour nous un nouvel objet de ce type. Dans mon exemple j’aurais donc une classe nommée GameState qui dérivera de FlxState.

Le taux de zoom est assez pratique si vous voulez faire des jeux de type « retro » avec de gros pixels, concrètement vous allez par exemple utiliser de petites images qui seront automatiquement zoomée au taux que  vous aurez spécifié.

Vous pouvez aussi spécifier d’autres paramètres au constructeur de FlxGame comme le taux de rafraîchissement désiré par exemple (fixé à 60 pour Flixel et 30 pour le lecteur Flash).

FlxState : la face visible du jeu

On va directement commencer par ajouter un nouveau fichier qu’on appellera GameState.as dans le projet (donc dans le dossier src) et créer la classe qui va bien, mais avant un peut de théorie car il faut bien.

Dans Flixel tout repose sur le système d’états, un état va représenter à un moment donné une partie (en général) visuelle de votre jeu, par exemple on aura un état pour le menu, un autre pour l’écran de jeu, un autre pour l’écran de game over, etc… Vous pouvez donc commencer à penser « Etat » et vous dire que vous aurez besoin d’un état pour :

  1. Le ou les menu(s)
  2. L’écran de chargement
  3. Le jeu en lui même
  4. L’écran de gestion des scores
  5. L’écran d’information (vous avez perdu, vous avez gagné, etc..)
  6. L’écran des crédits
  7. etc…

Un état sera au final une classe qui dérivera de FlxState et qui surchargera plusieurs méthodes. Le mécanisme utilisé par Flixel (mais aussi par beaucoup d’autres bibliothèques de jeux) repose sur le design pattern Game State ( patron de conception Etat de jeu). Le principe est le suivant, dans un premier temps on initialise les variables et les objets de travail puis on charge les ressources, ensuite on rentre dans une boucle infinie où deux méthodes seront exécutées chacune leur tour, une de mise à jour de la logique et une de mise à jour de l’affichage. Si vous avez consulté le lien que j’ai donné vous aurez surement remarqué la présence d’une méthode unload() ou cleanup() qui sert à décharger le programme des ressources non utilisés, c’est une bonne chose d’implémenter cette méthode mais si vous faites de petits jeu ça ne sera pas nécessaire dans l’immédiat. Je vous recommande vivement d’implémenter cette méthode quand vous serrez à l’aise avec Flixel mais nous en reparlerons.

Vous pouvez voir votre classe d’état comme un calque dans gimp ou photoshop, ils représente une partie d’affichage (je pense que vous avez compris à force 🙂 ). On utilisera au final plusieurs états ce qui formera le jeu.

Le pattern Game State
Fonctionnement d'un état : Le pattern Game State

On commence avant tout par surcharger la méthode create(), c’est ici que nous initialiseront les différents objets graphique comme les textes, les sprites, les sons, etc… Voyez la méthode create comme le constructeur « graphique » de la classe.

Le constructeur de la classe va servir à initialiser uniquement les variables qui n’ont pas de rapport avec Flixel (des variables de score par exemple ou des objets de l’API Flash).

Ensuite la boucle principale du jeu commence et se répète jusqu’à ce que l’état se termine (ou que l’on quitte carrément le jeu), les méthodes update() puis draw() sont alors appelées chacune leur tour.

On utilisera la méthode update() pour mettre à jour la logique du jeu, cela veut dire que si vous avez des tests de collisions à faire, des déplacements de personnage, des modifications non visuelles c’est dans cette méthode qu’il faudra les mettre.

La méthode draw() quand à elle sera chargée de mettre à jour l’affichage du jeu, donc la partie visible (afficher des sprites, afficher une map, etc…).

Pour résumer

  • public function MaClasseState() -> Constructeur de la classe qui dérive de FlxState (le nom MaClasseState est totalement arbitraire hein), il permet d’initialiser les attributs privés, protégés et publiques qui n’ont pas de rapport avec Flixel
  • public override function create():void -> Initialisation des objets en relation avec Flixel (Textes, Sprites, TileMap, etc…)
  • public override function udpate():void -> Mise à jour de la position des joueurs, des textes, tests de collisions entre Sprites, etc..
  • public override function draw():void -> Afficher sur l’écran les Sprites, les TileMap, les textes, etc…)

Je vous invite à remplir votre fichier GameState.as avec ce contenu, pour l’instant ce n’est pas énorme et ça n’affiche qu’un message (un message retro s-il vous plaît ^^ )

package
{
	import org.flixel.FlxState;
	import org.flixel.FlxText;
	import org.flixel.FlxG;

	public class GameState extends FlxState
	{
		private var m_titre:FlxText;
		private var m_texte:String;

		public function GameState()
		{
			m_texte = "Hello Flixel :)";
		}

		override public function create():void
		{
			m_titre = new FlxText(0, FlxG.height / 2, FlxG.width, m_texte);
			m_titre.setFormat(null, 24, 0x00ff00, "center", 0x005500);
			this.add(m_titre);
		}

		override public function update():void
		{
			super.update();
		}

		override public function draw():void
		{
			super.draw();
		}
	}
}

La variables m_texte est initialisée dans le constructeur car elle ne fait pas partie de Flixel, par contre m_titre est un objet de type FlxText qui lui est un objet graphique provenant de Flixel, il est donc initialisé dans la méthode create(). Comme vous l’aurez compris les objets de type FlxText permettent d’afficher du texte à l’écran. On utilise ensuite la méthode add() pour attacher m_titre à la scène (en fait cette méthode va dire à Flixel d’ajouter notre texte au stage). La méthode add() fonctionne comme le addChild() de l’API Flash (DisplayObject) à la différence que la version add() prend en paramètre un objet de type FlxObject. Dans tout vos jeux Flixel vous n’utiliserez donc que la méthode addChild().

J’aimerais revenir 15 secondes sur la différence entre le constructeur et la méthode create() car elles font toutes les deux la même chose à première vue car elles permettent toutes les deux d’initialiser des objets/variables. La méthode create est appelée après le constructeur et des traitement sont fait entre la construction de l’objet et son appel dans le programme, il est donc recommandé de l’utiliser pour initialiser les objets issus de Flixel. Ce n’est pourtant pas une convention obligatoire car vous pouvez essayer d’initialiser un FlxText dans le constructeur de la classe et ça fonctionnera, mais pour des raisons de lisibilité et de compatibilité avec les exemples du site officiel nous utiliserons create() pour les objets Flixel.

Je ne vous détail pas trop FlxText car c’est assez simple, à la construction vous spécifiez la position en X et Y par rapport au coin en haut à gauche de l’écran, la largeur de l’objet et une chaine de caractère qui est votre texte. La méthode setFormat() permet de spécifier une police d’écriture personnalisée (True Type Font), dans notre cas on garde celle d’origine donc on passe la valeur  null à la fonction. Ensuite dans l’ordre nous avons la taille du texte sur l’écran, sa couleur, son alignement et enfin la couleur d’ombrage du texte. Il existe d’autres paramètres mais je vous invite à consulter la documentation car elle est faite pour ça 😉

FlxG : la classe utilitaire incontournable

Et pour finir voici une présentation rapide de la classe FlxG, elle comporte plusieurs méthodes statiques qui vont franchement nous simplifier la vie. Depuis cette classe on peut par exemple

  • Accéder au stage (en lecture uniquement)
  • Connaître quelle touche à été pressée (elle gère les événements pour nous)
  • Connaître la position de la souris
  • Connaitre les paramètres globaux du jeu (Taille de la fenêtre, score du joueur, etc…)

Vous avez surement constaté que dans mon exemple j’utilise FlxG pour récupérer la largeur de l’écran (qui est de 800 pixels) et sa hauteur. Nous reviendrons largement sur cette classe utilitaire car on s’en servira lorsque l’on voudra déplacer des personnages au clavier, jouer des sons ou mettre à jour le score du joueur (oui Flixel gère aussi le score de l’utilisateur, elle est pas belle la vie 😉 )

Rendez vous dans le prochain tutoriel, cette fois ci nous verrons des choses plus concrètes comme déplacer et animer un personnage dans un petit décors.