I am making a test game where I want the level to be constantly scrolling. To create this effect I have established a camera class which simply stores a vector2 position and an enum direction. It also contains a public method to 'move' which simply changes the position at a fixed rate. I then use this position when looping through my array of tiles when drawing. This all works fine.
However, I have been told that I should be using a Transform matrix to move the camera, and that I should provide this when I start the spritebatch. I am a little confused a.) how this works? as if I am only giving it when spritebatch begins how does it know to keep changing position? b.) Why do it as surely I still need the camera position for when I loop through tiles?
AT the moment I can't get it to work, but that's no surprise as I dont completely understand how it is meant to work. Currently in my attempt (code to follow) the tiles being drawn changes which means the cameras position is changing, but the position of the viewport remains unchanged (i.e. at the camera origin). I would really appreciate some advice/guidance on how its supposed to be used?
Camera:
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));
}
}
Level:
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();
}
Game - just calls the draw within level:
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:
Firstly, thank you craftworkgames for your help thus far.
I played around with the suggestion. When I did draw all tiles, the fr tanked to around 15 from 30 - probably because the levels are pretty big.
So what I have done is apply the matrix and move in update (as suggested) but in draw I use the cameras position for looping through tiles (i.e. start counter at left and end at right tile). This all works well and I'm happy with it :-)
My new issue lies in the player. Obviously as I am now moving the camera rather than the level, the player gets left behind by the camer as its position stays fixed. I have thought of two solutions to this problem, the first is to simply consider the cameras position when drawing the player. I.e. in the draw funcion simply add the camera position to the player position. The second is to start a new sprite batch for the player which has no transform. i.e. end the spritebatch after drawing the tiles then start a new one when drawing the player. I know both will work, but I cant make heads of tails of which would be better in terms of performance/good coding? I am not sure what the performance implications are from starting the batch twice?
No comments:
Post a Comment