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?

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?

\$\begingroup\$"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." Just read this and I am so confused why on earth would you not move the player within the level's coordiante system?\$\endgroup\$
– ClassicThunderJul 19 '13 at 19:39

2 Answers
2

Camera matrix transformations are easy

Creating a basic camera is easy. Below will get you started with the basics. Moving it around, rotating, ans scaling. Moving every 2d sprite isn't much of an issues but if you factor in either scaling or rotation then it gets really hard to apply to every sprite individually.

You can simply transform the cameras corners and get their location in world space. Min max the x,y values and you can get a rectangle around the viewable space. Very useful for culling and optimizing draw calls.

Applying a matrix to your SpriteBatch transforms the entire draw call at once. This means you don't need to use your camera in your DrawTiles method at all.

It could become a lot simpler like so:

// Loop through the number of visible tiles.
for (int y = 0; y <= tiles.GetUpperBound(1); y++) {
for (int x = 0; x <= tiles.GetUpperBound(0); x++) {
// If the tile is not an empty space.
if (tiles[x, y].Texture != null) {
// Get the position of the visible tile within the viewport by multiplying the counters by the tile dimensions
// and subtracting the camera offset values incase the position of the camera means only part of a tile is visible.
Vector2 tilePosition = new Vector2(x * Tile.Width, y * Tile.Height);
// Draw the correct tile
spriteBatch.Draw(tiles[x, y].Texture, tilePosition, Color.White);
}
}
}

So the point of using a matrix is so that you don't have to think about it. Just draw things and move the camera around independently.

Also, your MoveCamera method looks a little strange. It's very unusual to have a camera class that takes a Level as a dependency. A more typical implementation would look like this:

Overall, my suggestion is to keep it simple. Get it working the simplest way fist and build on it. Try not to write highly optimized code until you've got the basics working first. You may find that rendering every tile every frame is not so bad.

EDIT: For second part of question.

While it's true that you want to keep your batch count low, having 2 or 3 shouldn't be a problem at all. So if you have a good reason to create a second sprite batch just do it.

That said, there's probably not a good reason to use a second sprite batch in this case. More likely, you want to draw your player in the exact same way you draw tiles in the same sprite batch with the camera transform applied.

It's a little hard to tell why your player is getting left behind without looking at some code but it stands to reason that if you draw your player at the exact same position as a tile, he / she will appear at the same position with the same sprite batch.

For example, if you want the player to appear on tile 10, 10 you could do this:

\$\begingroup\$That's really helpful and cleared things up loads! Thanks for the info; much appreciated. I will try to implement your advise later today and will let you know how I get on. Thanks again.\$\endgroup\$
– Pectus ExcavatumJul 18 '13 at 8:37

\$\begingroup\$Also, just out of interest, is there a way to use the matrix transform to only draw tiles in the viewport?\$\endgroup\$
– Pectus ExcavatumJul 18 '13 at 9:38

\$\begingroup\$There is a way to do that, but I don't know off the top of my head. I suspect it will have something to do with using the viewport rectangle, maybe after applying the camera transform to it. I dunno, you'll have to experiment. Use your debugger.\$\endgroup\$
– craftworkgamesJul 18 '13 at 11:29

\$\begingroup\$Ok, thanks. I have played around with it and got somewhere but have run into an question about what to do with the player - please see edits to question.\$\endgroup\$
– Pectus ExcavatumJul 18 '13 at 13:14

\$\begingroup\$Thanks, I took your advice and went with the option of using the same sprite batch and just getting the camera position in the update and applying it to the players position when drawing. Seems to work well. Thanks for all your help, been stuck on the camera for a while. Much clearer now :-)\$\endgroup\$
– Pectus ExcavatumJul 19 '13 at 15:45