Je fais un jeu de test où je veux que le niveau défile constamment. Pour créer cet effet, j'ai créé une classe de caméra qui stocke simplement une position vector2 et une direction enum. Il contient également une méthode publique de «déplacement» qui modifie simplement la position à un taux fixe. J'utilise ensuite cette position lors de la boucle à travers mon tableau de tuiles lors du dessin. Tout cela fonctionne bien.
Cependant, on m'a dit que je devrais utiliser une matrice de transformation pour déplacer la caméra et que je devrais fournir cela lorsque je démarre le spritebatch. Je suis un peu confus a.) Comment ça marche? comme si je ne le donnais qu'au début du spritebatch, comment sait-il continuer à changer de position? b.) Pourquoi le faire, car j'ai sûrement encore besoin de la position de la caméra pour parcourir les tuiles?
Pour le moment, je ne peux pas le faire fonctionner, mais ce n'est pas une surprise car je ne comprends pas complètement comment il est censé fonctionner. Actuellement, dans ma tentative (code à suivre), les tuiles dessinées changent, ce qui signifie que la position des caméras change, mais la position de la fenêtre reste inchangée (c'est-à-dire à l'origine de la caméra). J'apprécierais vraiment quelques conseils / conseils sur la façon dont il est censé être utilisé?
Caméra:
class Camera {
// The position of the camera.
public Vector2 Position {
get { return mCameraPosition; }
set { mCameraPosition = value; }
}
Vector2 mCameraPosition;
public Vector2 Origin { get; set; }
public float Zoom { get; set; }
public float Rotation { get; set; }
public ScrollDirection Direction { get; set; }
private Vector2 mScrollSpeed = new Vector2(20, 18);
public Camera() {
Position = Vector2.Zero;
Origin = Vector2.Zero;
Zoom = 1;
Rotation = 0;
}
public Matrix GetTransform() {
return Matrix.CreateTranslation(new Vector3(mCameraPosition, 0.0f)) *
Matrix.CreateRotationZ(Rotation) *
Matrix.CreateScale(Zoom, Zoom, 1.0f) *
Matrix.CreateTranslation(new Vector3(Origin, 0.0f));
}
public void MoveCamera(Level level) {
if (Direction == ScrollDirection.Up)
{
mCameraPosition.Y = MathHelper.Clamp(mCameraPosition.Y - mScrollSpeed.Y, 0, (level.Height * Tile.Height - level.mViewport.Height));
}
}
Niveau:
public void Update(GameTime gameTime, TouchCollection touchState) {
Camera.MoveCamera(this);
}
public void Draw(SpriteBatch spriteBatch) {
//spriteBatch.Begin();
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullCounterClockwise, null, mCamera.GetTransform());
DrawTiles(spriteBatch);
spriteBatch.End();
}
Jeu - appelle simplement le tirage au sein du niveau:
protected override void Draw(GameTime gameTime) {
mGraphics.GraphicsDevice.Clear(Color.Black);
//mSpriteBatch.Begin();
// Draw the level.
mLevel.Draw(mSpriteBatch);
//mSpriteBatch.End();
base.Draw(gameTime);
}
================================================== =============================== EDIT:
Tout d'abord, merci craftworkgames pour votre aide jusqu'à présent.
J'ai joué avec la suggestion. Quand j'ai dessiné toutes les tuiles, le fr a atteint environ 15 sur 30 - probablement parce que les niveaux sont assez grands.
Donc, ce que j'ai fait, c'est appliquer la matrice et se déplacer dans la mise à jour (comme suggéré), mais dans le dessin, j'utilise la position des caméras pour parcourir les tuiles (c'est-à-dire commencer le compteur à gauche et terminer à droite). Tout fonctionne bien et j'en suis satisfait :-)
Mon nouveau problème réside dans le joueur. Évidemment, comme je déplace maintenant la caméra plutôt que le niveau, le joueur est laissé par le camer car sa position reste fixe. J'ai pensé à deux solutions à ce problème, la première est de simplement considérer la position des caméras lors du dessin du lecteur. C'est-à-dire dans la fonction de dessin, ajoutez simplement la position de la caméra à la position du joueur. La seconde consiste à démarrer un nouveau lot de sprites pour le joueur qui n'a pas de transformation. c'est-à-dire terminer le spritebatch après avoir dessiné les tuiles puis en commencer une nouvelle lorsque vous dessinez le joueur. Je sais que les deux fonctionneront, mais je ne peux pas faire de têtes de queues qui seraient meilleures en termes de performances / bon codage? Je ne sais pas quelles sont les implications en termes de performances du démarrage du lot deux fois?
Réponses:
Les transformations de la matrice de la caméra sont faciles
La création d'une caméra de base est simple. Vous obtiendrez ci-dessous les bases. Déplacement, rotation et mise à l'échelle. Déplacer chaque sprite 2D n'est pas vraiment un problème, mais si vous tenez compte de l'échelle ou de la rotation, il devient très difficile de l'appliquer individuellement à chaque sprite.
Il facilite la conversion entre les définitions de système de coordonnées
Pour passer de l'écran à l'espace mondial simplement. Ceci est couramment utilisé pour obtenir l'emplacement de la souris dans le monde pour la cueillette d'objets.
Pour passer du monde à l'espace écran, faites simplement le contraire.
Il n'y a aucun inconvénient à utiliser une matrice autre que cela demande un peu d'apprentissage.
Il est facile d'obtenir la zone visible
Vous pouvez simplement transformer les coins des caméras et obtenir leur emplacement dans l'espace mondial. Min max les valeurs x, y et vous pouvez obtenir un rectangle autour de l'espace visible. Très utile pour éliminer et optimiser les appels de tirage.
la source
L'application d'une matrice à votre SpriteBatch transforme tout l'appel de tirage en une seule fois. Cela signifie que vous n'avez pas du tout besoin d'utiliser votre caméra dans votre méthode DrawTiles.
Cela pourrait devenir beaucoup plus simple comme ceci:
Le but de l'utilisation d'une matrice est donc de ne pas avoir à y penser. Il suffit de dessiner des choses et de déplacer la caméra de manière indépendante.
De plus, votre méthode MoveCamera semble un peu étrange. Il est très inhabituel d'avoir une classe de caméra qui prend un niveau comme dépendance. Une implémentation plus typique ressemblerait à ceci:
Ensuite, dans votre méthode de mise à jour, vous pourriez faire quelque chose comme ceci:
Dans l'ensemble, ma suggestion est de rester simple. Faites-le fonctionner de la manière la plus simple et construisez-le. Essayez de ne pas écrire de code hautement optimisé tant que les bases ne fonctionnent pas en premier. Vous pouvez constater que le rendu de chaque tuile à chaque image n'est pas si mauvais.
EDIT: Pour la deuxième partie de la question.
Bien qu'il soit vrai que vous souhaitez maintenir votre nombre de lots bas, avoir 2 ou 3 ne devrait pas être un problème du tout. Donc, si vous avez une bonne raison de créer un deuxième lot de sprites, faites-le.
Cela dit, il n'y a probablement pas de bonne raison d'utiliser un deuxième lot de sprites dans ce cas. Plus probablement, vous voulez dessiner votre joueur de la même manière que vous dessinez des tuiles dans le même lot de sprites avec la transformation de caméra appliquée.
Il est un peu difficile de dire pourquoi votre joueur est laissé sans regarder un code, mais il va de soi que si vous dessinez votre joueur exactement à la même position qu'une tuile, il apparaîtra à la même position avec la même lot de sprites.
Par exemple, si vous voulez que le joueur apparaisse sur la tuile 10, 10 vous pouvez faire ceci:
Essayez d'entrer dans la mentalité de penser à dessiner les choses où elles sont et la caméra met littéralement toute la «scène» en vue. C'est ce que fait votre transformation matricielle.
la source