Didacticiel XNA : Partie 4 – Déplacements, collisions, rotations

Image hosted by uppix.net

Objectifs :

Cette partie est dédiée à tout ce qui peut remplir la méthode Update() : collisions et déplacements en particulier.

Sommaire :

XNA : Logique d’un jeu, Entrées / Sorties (Update())

Maintenant que vous connaissez les principales techniques d’affichages 2D, il est temps de passer au contrôle et à la logique de votre (futur) jeu.

Pour cela il va falloir se demander ce que vous voulez faire. Je vous propose ceci : l’image du cactus (voir partie 2) qui tourne sur elle-même et qui se déplace comme une balle de Pong sur l’écran, en rebondissant sur les côtés.

Réutilisez le code de la partie 2, car l’affichage et le chargement de l’image se fait exactement comme cela a été décrit précédemment. On va s’intéresser presque uniquement au remplissage de la méthode Update().

Rotation du sprite sur lui-même

Assurez-vous d’avoir un attribut rotation de type float et initialisé à 0.0f dans votre code.

Vous vous souvenez du cactus incliné ? Eh bien on va le dessiner pareil, sauf que l’on va incrémenter l’angle de rotation dans la méthode Update() :

protected override void Update(GameTime gameTime)
{
...
rotation += 0.01f;

//0.01f est arbitraire. La méthode étant appelée plusieurs fois par seconde (plus de 60 fois), mieux vaut mettre une valeur pas trop grande pour voir quelque chose...
...
}

et pour rappel, dans Draw() :

protected override void Draw(GameTime gameTime)
{
...
spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
spriteBatch.Draw(sprite, dst, src, Color.White, rotation, Vector2.Zero, SpriteEffects.None, 1.0f);
spriteBatch.End();
...
}

Générez, lancez, et Tada ! C’est magnifique ! Le cactus tourne… sur le coin en haut à gauche… Eh oui pour rappel la rotation « par défaut » est à cet emplacement (entre guillemets oui car c’est simplement le Vector.Zero qui le met ici).

Image hosted by uppix.net

Or on a dit que l’on voulait un cactus tournant sur lui même. Ok ! Facile !

Quel est le centre du sprite ? Même si l’image que je vous ai fourni contient du vide, on va considérer le cactus comme centré. Donc le milieu de l’image est

(sprite.Width/2,sprite.Height/2)

sprite est l’objet Texture2D qui contient l’image du cactus en mémoire.

Changer le vecteur origin par le centre de l’image :

spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
spriteBatch.Draw(sprite, dst, src, Color.White, rotation, new Vector2(sprite.Width/2,sprite.Height/2), SpriteEffects.None, 1.0f);
spriteBatch.End();

Ce qui nous donne un truc un peu comme ça (dessin approximatif) :

Image hosted by uppix.net

Voilà pour la rotation ! Ce n’est vraiment pas compliqué, mais ça peut le devenir quand vous voulez une rotation précise. Vous n’avez plus qu’à ressortir vos vieux cours de trigonométrie, ça va servir…

Déplacement d’un objet

Faisons mieux qu’une simple rotation : le déplacement.

Pour éclaircir le code nous allons utiliser deux nouvelles variable sous forme de vecteurs : la position actuelle et la vitesse de l’objet.

Vector2 location,speed;

La vitesse sera une sorte de coefficient multiplicateur pour faire varier la direction. Vous comprendrez plus en détails par la suite.

Initialisons celles-ci à coté des autres, avec une valeur de (100,100) par exemple pour location et (150,150) pour speed :

location = new Vector2(100, 100);
speed = new Vector2(150, 150);

Vous vous souvenez de la variable dst ? Jusqu’à présent on forçait son X et son Y à 300. Supprimez ces lignes (et vite !), et dans la méthode Update() ajoutez celle-ci :

protected override void Update(GameTime gameTime)
{
... //Rotation avant
dst.X = (int)location.X;
dst.Y = (int)location.Y;
...
}

Le langage C# est fortement typé : toute conversion (cast) doit être explicite. En cas de problème utilisez la classe Convert qui dispose de nombreuses méthode statiques pour faire du bon travail. Par exemple Convert.ToInt32("10") transformera (String) « 10″ en (int) 10.

Revenons à nos vecteurs. Comme la position va être mise à jour dynamiquement, à chaque passage d’Update(), il faut mettre à jour dst puisque c’est là que sera affichée l’image. Bien sûr pour l’instant rien ne change, mais quand location changera, l’image se synchronisera avec les nouvelles coordonnées.

Bon c’est bien beau mais comment on peut faire que le sprite se déplace ?

La méthode Update() possède un paramètre extrêmement intéressant : le GameTime. Le GameTime est une horloge (timer) qui est mise à jour automatiquement par XNA. Elle connaît : la durée totale du jeu, le temps écoulé sur votre PC (si la fenêtre est en arrière plan le timer du jeu s’arrête mais pas celui du PC), le temps écoulé depuis le dernier appel à Update(), et tout ça dans toutes les unités possibles…

Bref l’outil rêvé pour avoir des déplacements synchronisés entre la vitesse de la machine et le jeu. En effet, si nos déplacements dépendent du timer, alors si le PC ralentit le jeu ralentira uniformément aussi.

Ce qui va nous intéresser est le temps écoulé (en secondes) depuis le dernier appel à la méthode Update(). Nous allons le récupérer sous forme de float dans une variable :

float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

Vous aurez constaté en tapant ces lignes qu’il y a moult attributs / méthodes disponibles qui pourront vous servir. Consultez la documentation (Touche F1 dans Visual Studio sur un élément) pour bien connaître le fonctionnement de chaque élément.

Nous avons toutes les cartes en main pour mettre à jour les coordonnées de l’image (Pour mieux vous situez, j’ai remis la mise à jour de l’angle et de dst) :

protected override void Update(GameTime gameTime)
{
...
rotation += 0.01f;
...
float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
int deplacementX = (int)(speed.X * elapsedTime);
int deplacementY = (int)(speed.Y * elapsedTime);
location.X += deplacementX;
location.Y += deplacementY;
dst.X = (int)location.X;
dst.Y = (int)location.Y;
...
}

Essayez !

Image hosted by uppix.net

Le cactus se fait la malle ! Logique : les vitesses sont positives et nous n’avons mis aucune notion de collision.

En tout cas, vous en conviendrez : votre cactus bouge. Essayez de modifier les valeurs du vecteur vitesse pour comprendre son impact.

Collisions avec l’écran

Faisons maintenant rebondir notre cactus sur le bord de l’écran.

Quand notre image arrive à un bord, il faut le détecter et inverser une de ses trajectoires (ici, sa vitesse).Rien de bien compliqué :

if ((location.X < 0) || (location.X > 800))
{
speed.X = -speed.X;
}
if ((location.Y < 0) || (location.Y > 600))
{
speed.Y = -speed.Y;
}

L’écran de base ayant une résolution de 800*600, vous devriez voir votre cactus rebondir :)

Vous pouvez récupérer la valeur exact de la résolution grâce à l’attribut graphics et à ses propriétés PreferredBackBufferWidth / PreferredBackBufferHeight (entre autre moyen)

Ici on regarde la collision pour le point (0,0) de l’image, mais rien de vous empêche d’utiliser la taille de l’image pour faire en sorte qu’elle ne sorte jamais de l’écran.

Dans la prochaine partie on utilisera les entrées utilisateur (claviers et manettes) pour améliorer notre jeu, et je vous présenterai les quelques sorties possibles brièvement.

2 commentaires sur “Didacticiel XNA : Partie 4 – Déplacements, collisions, rotations”

  1. Bitcrushr dit :

    Merci pour ces rappels clairs de l’utilisation des méthodes de XNA, ce site devrait me servir pour un de mes Projets de BTS.

    En espérant que votre Shmup puisse avancer.

Laisser une réponse

Spam Protection by WP-SpamFree