Estoy haciendo un juego de prueba donde quiero que el nivel se desplace constantemente. Para crear este efecto, he establecido una clase de cámara que simplemente almacena una posición vector2 y una dirección de enumeración. También contiene un método público para 'moverse' que simplemente cambia la posición a una tasa fija. Luego uso esta posición cuando recorro mi conjunto de mosaicos cuando dibujo. Todo esto funciona bien.
Sin embargo, me han dicho que debería usar una matriz de transformación para mover la cámara, y que debería proporcionar esto cuando empiece el spritebatch. Estoy un poco confundido a.) ¿Cómo funciona esto? como si solo lo estuviera dando cuando comience el spritebatch, ¿cómo sabe seguir cambiando de posición? b.) ¿Por qué lo hago con tanta seguridad que todavía necesito la posición de la cámara cuando paso por los mosaicos?
Por el momento no puedo hacer que funcione, pero eso no es una sorpresa, ya que no entiendo completamente cómo debe funcionar. Actualmente, en mi intento (código para seguir), los mosaicos que se dibujan cambian, lo que significa que la posición de las cámaras está cambiando, pero la posición de la ventana gráfica permanece sin cambios (es decir, en el origen de la cámara). Realmente agradecería algún consejo / guía sobre cómo se supone que debe usarse?
Cámara:
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));
}
}
Nivel:
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();
}
Juego: solo llama al sorteo dentro del nivel:
protected override void Draw(GameTime gameTime) {
mGraphics.GraphicsDevice.Clear(Color.Black);
//mSpriteBatch.Begin();
// Draw the level.
mLevel.Draw(mSpriteBatch);
//mSpriteBatch.End();
base.Draw(gameTime);
}
================================================== =============================== EDITAR:
En primer lugar, gracias craftworkgames por tu ayuda hasta ahora.
Jugué con la sugerencia. Cuando dibujé todas las fichas, el franco se redujo a alrededor de 15 desde 30, probablemente porque los niveles son bastante grandes.
Entonces, lo que he hecho es aplicar la matriz y moverme en la actualización (como se sugiere), pero en el dibujo uso la posición de la cámara para recorrer los mosaicos (es decir, iniciar el contador a la izquierda y terminar en el mosaico derecho). Todo esto funciona bien y estoy feliz con eso :-)
Mi nuevo problema radica en el jugador. Obviamente, como ahora estoy moviendo la cámara en lugar del nivel, el jugador se queda atrás por la cámara mientras su posición permanece fija. He pensado en dos soluciones a este problema, la primera es simplemente considerar la posición de las cámaras al dibujar el reproductor. Es decir, en la función de sorteo simplemente agregue la posición de la cámara a la posición del jugador. El segundo es comenzar un nuevo lote de sprites para el jugador que no tiene transformación. es decir, finalizar el spritebatch después de dibujar las fichas y luego comenzar una nueva al dibujar el jugador. Sé que ambos funcionarán, pero no puedo determinar cuál sería mejor en términos de rendimiento / buena codificación. No estoy seguro de cuáles son las implicaciones de rendimiento al comenzar el lote dos veces.
Respuestas:
Las transformaciones de la matriz de la cámara son fáciles.
Crear una cámara básica es fácil. A continuación, comenzará con los conceptos básicos. Moviéndolo, girando y escalando. Mover cada sprite 2D no es un gran problema, pero si tiene en cuenta la escala o la rotación, se vuelve realmente difícil aplicarlo a cada sprite individualmente.
Hace que sea muy fácil convertir entre definiciones de sistemas de coordenadas
Para ir de la pantalla al espacio mundial simplemente. Esto se usa comúnmente para obtener la ubicación del mouse en el mundo para la selección de objetos.
Para ir del mundo al espacio de la pantalla, simplemente haga lo contrario.
No hay inconveniente en usar una matriz que no sea un poco de aprendizaje.
Es fácil obtener el área visible
Simplemente puede transformar las esquinas de las cámaras y obtener su ubicación en el espacio mundial. Min max los valores x, y y puede obtener un rectángulo alrededor del espacio visible. Muy útil para seleccionar y optimizar llamadas de sorteo.
fuente
La aplicación de una matriz a su SpriteBatch transforma toda la llamada de sorteo a la vez. Esto significa que no necesita usar su cámara en su método DrawTiles en absoluto.
Podría ser mucho más simple así:
Entonces, el punto de usar una matriz es para que no tenga que pensar en ello. Simplemente dibuja cosas y mueve la cámara de forma independiente.
Además, su método MoveCamera se ve un poco extraño. Es muy inusual tener una clase de cámara que tome un Nivel como dependencia. Una implementación más típica se vería así:
Luego, en su método de actualización, puede hacer algo como esto:
En general, mi sugerencia es que sea simple. Haz que funcione de la manera más simple y construye sobre él. Intente no escribir código altamente optimizado hasta que tenga lo básico funcionando primero. Puede encontrar que renderizar cada mosaico cada cuadro no es tan malo.
EDITAR: Para la segunda parte de la pregunta.
Si bien es cierto que desea mantener un recuento bajo de lotes, tener 2 o 3 no debería ser un problema en absoluto. Entonces, si tiene una buena razón para crear un segundo lote de sprites, simplemente hágalo.
Dicho esto, probablemente no haya una buena razón para usar un segundo lote de sprites en este caso. Lo más probable es que quieras dibujar a tu jugador exactamente de la misma manera que dibujas fichas en el mismo lote de sprites con la transformación de la cámara aplicada.
Es un poco difícil saber por qué su jugador se queda atrás sin mirar algún código, pero es lógico que si dibuja a su jugador exactamente en la misma posición que un mosaico, aparecerá en la misma posición con el mismo lote de sprites
Por ejemplo, si desea que el jugador aparezca en el mosaico 10, 10 puede hacer esto:
Trate de entrar en la mentalidad de pensar en dibujar cosas donde están y la cámara literalmente mueve toda la "escena" a la vista. Eso es lo que está haciendo su transformación de matriz.
fuente