2010-08-25 5 views
4

Je travaille sur un jeu XNA et j'utilise ViewPort.Project et ViewPort.Unproject pour traduire vers et depuis les coordonnées du monde. Actuellement, je les utilise pour chaque objet que je dessine avec SpriteBatch. Ce que je voudrais faire est de calculer une matrice que je peux envoyer à SpriteBatch.Begin pour faire la transformation d'espace-écran pour moi.Projection XNA ViewPort et SpriteBatch

Voici les fonctions que j'utilise actuellement pour traduire vers et à partir screenspace:

 Vector2 ToWorldCoordinates(Vector2 pixels) 
    { 
     Vector3 worldPosition = graphics.GraphicsDevice.Viewport.Unproject(new Vector3(pixels, 0), 
       Projection, View, Matrix.Identity); 
     return new Vector2(worldPosition.X, worldPosition.Y); 
    } 

    Vector2 ToScreenCoordinates(Vector2 worldCoords) 
    { 
     var screenPositon = graphics.GraphicsDevice.Viewport.Project(new Vector3(worldCoords, 0), 
       Projection, View, Matrix.Identity); 
     return new Vector2(screenPositon.X, screenPositon.Y); 
    } 

View est réglé sur Matrix.Identity et projection est défini comme ceci:

Projection = Matrix.CreateOrthographic(40 * graphics.GraphicsDevice.Viewport.AspectRatio, 40, 0, 1); 

Et voici comment je dessine actuellement des choses:

  spriteBatch.Begin(); 
     foreach (var thing in thingsToDraw) 
     { 
      spriteBatch.Draw(thing.Texture, ToScreenCoordinates(thing.PositionInWorldCoordinates), thing.Color); 
      spriteBatch.End(); 
     } 
     spriteBatch.End(); 

C'est ce que je voudrais faire à la place (en utilisant XNA 4.0 v ersion de SpriteBatch.Begin())

  // how do I calculate this matrix? 
     Matrix myTransformationMatrix = GetMyTransformationMatrix(); 

     spriteBatch.Begin(SpriteSortMode.Immediate, null, null, null, null, null, 
      myTransformationMatrix); 

     foreach (var thing in thingsToDraw) 
     { 
      // note: no longer converting each object's position to screen coordinates 
      spriteBatch.Draw(thing.Texture, thing.PositionInWorldCoordinates, thing.Color); 
      spriteBatch.End(); 
     } 
     spriteBatch.End(); 

Répondre

12

J'ai écrit au sujet SpriteBatch et les différents "espaces" (monde, projection, client, etc.) here, here et here. Ces réponses valent probablement la peine d'être lues.

SpriteBatch suppose que votre espace Monde est la même chose que l'espace Client - qui est cependant de plusieurs pixels de haut et large, la fenêtre d'affichage est en haut à gauche, Y + est en baisse. Il semble que (selon votre utilisation de CreateOrthographic) vous voulez que votre espace Monde apparaisse comme 40 unités de hauteur, à l'écran, et que de nombreuses unités soient ajustées dans le sens de la largeur. Vous voulez aussi l'origine du monde au centre de l'écran et Y + est en hausse.

Vous devez donc coller une autre matrice entre les deux pour convertir votre espace Monde en espace Client. Je crois que la matrice correcte est (en psudocode): scale(40/viewport.Height) * scale(1, -1) * translate(viewport.Width/2, viewport.Height/2). Échelle, retourner et traduire pour aller du monde au client.

Vous devez également vous rappeler que les sprites supposent que Y + est en panne. Donc, vous devez passer une échelle (1, -1) en SpriteBatch.Draw, sinon ils seront dessinés inversés (et, en raison de l'élimination de la face arrière, être invisibles).

+0

Réponse fantastique. Pour les autres qui lisent, si vous voulez aussi avoir une matrice de vue représentant une caméra, je pense que l'ordre correct est de faire View * scale (40/viewport.Height) * scale (1, -1) * translate (viewport. Width/2, viewport.Height/2), où les transformations de vue sont dans les unités spatiales du monde. –