Délimiter son terrain de jeu avec Farseer & XNA 4 (Polygone de collision)

Dans tous les jeux qui font appels aux lois de notre physique, nous retrouvons les mêmes problématiques: gérer les collisions entre 2 images.

Je vais rapidement présenter une petite astuce pour permettre de délimiter une zone de collision en fonction du contenu d’une texture.

Présentation

Pour l’exemple, prenons un jeu de palet.

Le principe du jeu est connu, il suffit, à l’aide d’un maillet, de frapper un palet afin que celui ci se retrouve dans les cages de l’adversaire.

Le terrain de jeu est délimité par des bordures et des cages.

Lorsque les palets ou les maillets vont rentrer en collision avec les bords de la table, ils vont rebondir et réagir selon l’inclinaison et la vitesse de collision.

Pour gérer la collision, je vous conseille d’utiliser le moteur physique Farseer, disponible pour XNA 4.0.
Farseer: http://farseerphysics.codeplex.com/

L’utilisation du moteur Farseer n’est pas si compliquée.
Je ne rentrerai pas dans les détails, mais pour l’implémenter, il suffit de rajouter aux textures sur lesquelles on souhaite appliquer les lois de notre physique, un corps physique et une enveloppe « corporelle ».

Il faut donc créer un corps physique aux palets et maillets, mais aussi aux bordures du terrain.

Notre terrain se présente comme une simple texture pour le moment.
Nous allons lui préparer un corps physique. Il doit être figé et réagir aux collisions:

this._body = BodyFactory.CreateBody(GameRoot.GameWorld);
this._body.IsStatic = true;
this._body.CollisionCategories = Category.All;
this._body.CollidesWith = Category.All;

Une fois notre corps créé, nous devons lui attacher une enveloppe, une « fixture ». C’est elle qui délimitera la zone de collision. Le corps, lui, permet de gérer la physique (vitesse, masse, friction, forces, accélération…)

L’enveloppe de notre terrain va devoir tenir compte des coins arrondis de notre table. Là où notre texture est arrondie, l’enveloppe devra être arrondie pour donner l’impression que la collision s’effectue sur le rebord de la table.

Dans ce cas de figure, il est beaucoup trop fastidieux de créer soit même une liste de coordonnées pour délimiter le terrain.

Il faut créer un polygone qui viendra se calquer sur notre texture.

Et pour se faire, la première étape consiste à découper cette texture.

Zones visuelles de collisions

La découpe doit permettre de ne conserver que les parties qui délimiterons précisément le terrain. Il faut supprimer les ombres portée par exemple. Les zones de non-collisions doivent être transparentes. C’est la « couleur transparente » qui va délimiter la zone de collisions.

Nous obtenons ainsi une nouvelle image:

Cette image viendra naturellement se positionner derrière la précédente.

Attention ! Notez l’encoche à gauche sur l’image, dans les cages.

Cette encoche n’est pas anodine. L’algorithme de création de polygones du moteur Farseer va parcourir la texture et construire les vertex en suivant la bordure de l’image sans tenir compte de la couleur transparente. Il faut donc un point d’entrée pour parcourir l’intérieur de la texture.

Polygone de collisions

Nous allons donc utiliser l’outil spécifique de Farseer pour créer un polygone selon les zones de couleurs de notre image:

Vertices verts = PolygonTools.CreatePolygon(data, polygonTexture.Width, polygonTexture.Height, true);

L’appel de cette méthode statique renvoi un tableau de coordonnées contenant les vecteurs de notre polygone. Notre polygone à normalement la forme de notre texture pleine. C’est magique !

Voici le code complet:

///
<summary>
/// Création des bords de la table de jeu
/// </summary>
private void CreateBorders()
{
    // Chargement de la texture

    Texture2D polygonTexture = this.Layer.Content.Load("Borders");

    // Création d'un tableau pour stocker les données de la texture

    uint[] data = new uint[polygonTexture.Width * polygonTexture.Height];

    // Remplissage du tableau avec les données de la texture

    polygonTexture.GetData(data);

    // Création des vertex à partir de notre texture

    Vertices verts = PolygonTools.CreatePolygon(data, polygonTexture.Width, false);

    // Redimensionnement

    Vector2 scale = new Vector2(0.01f, 0.01f);
    verts.Scale(ref scale);

    // Partitionnement des vertex

    List convexPolygons = BayazitDecomposer.ConvexPartition(verts);

    // Attache notre polygone au corps physique

    List compund = FixtureFactory.AttachCompoundPolygon(convexPolygons, 1f, this._body);
}

Voici le résultat final:
Les traits verts représentent les vecteurs qui constituent mon polygone.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s