12
Oct
XNA Camera 2d with zoom and rotation
07/01/2011 – By popular request updated to XNA 4.0, xna 3.1 code is still there too
One of the things I keep finding is people asking how to do a simple camera 2d in XNA. Today I decided to contribute with my own solution.
Most of the time the solution given is to have a class camera with a Vector2 position and when drawing the sprite batch to subtract the camera position to the sprite position itself. Although this work from my point of view it’s not elegant and you can’t have neat features like zooming and rotation. So for my tutorial I’ll do all transformations using a Matrix.
Start off by creating the basic class Camera2d
public class Camera2d { protected float _zoom; // Camera Zoom public Matrix _transform; // Matrix Transform public Vector2 _pos; // Camera Position protected float _rotation; // Camera Rotation public Camera2d() { _zoom = 1.0f; _rotation = 0.0f; _pos = Vector2.Zero; } }
Now that we have the basic setup onto the variables it’s time to create a couple of functions to manipulate the variables
// Sets and gets zoom public float Zoom { get { return _zoom; } set { _zoom = value; if (_zoom < 0.1f) _zoom = 0.1f; } // Negative zoom will flip image } public float Rotation { get {return _rotation; } set { _rotation = value; } } // Auxiliary function to move the camera public void Move(Vector2 amount) { _pos += amount; } // Get set position public Vector2 Pos { get{ return _pos; } set{ _pos = value; } }
And now for the function that calculates all the transformations
public Matrix get_transformation(GraphicsDevice graphicsDevice) { _transform = // Thanks to o KB o for this solution Matrix.CreateTranslation(new Vector3(-_pos.X, -_pos.Y, 0)) * Matrix.CreateRotationZ(Rotation) * Matrix.CreateScale(new Vector3(Zoom, Zoom, 1)) * Matrix.CreateTranslation(new Vector3(ViewportWidth * 0.5f, ViewportHeight * 0.5f, 0)); return _transform; }
So now how can we use it?
Simple on your sprite batch begin you must add the camera transformation.
Camera2d cam = new Camera2d(); cam.Pos = new Vector2(500.0f,200.0f); // cam.Zoom = 2.0f // Example of Zoom in // cam.Zoom = 0.5f // Example of Zoom out //// if using XNA 3.1 spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState, cam.get_transformation(device /*Send the variable that has your graphic device here*/)); //// if using XNA 4.0 spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, null, null, null, cam.get_transformation(device /*Send the variable that has your graphic device here*/)); // Draw Everything // You can draw everything in their positions since the cam matrix has already done the maths for you spriteBatch.End(); // Call Sprite Batch End
Found any errors? Please let me know.

October 23rd, 2009 at 6:00
This looks great, but I am either too new to understand it, or I am missing something, How do I invoke the changes by either using the keyboard or controller. I am trying to pass a new vector2 to cam.move, trying to set _pos… just cant get it. any help appreciated. Thanks
October 23rd, 2009 at 7:50
I posted the other response and just wanted to let you know that I got it figured out. I was trying to set the position the wrong way… I still have a problem with get:set: and stuff like that. But thank you so much for the camera option you have here. works great!
October 23rd, 2009 at 7:56
For using get:set you have to do something like
for using the move
I hope this helped
October 23rd, 2009 at 8:40
Nice camera! how can i make rotation and scaling around cameras center point? not around left top corner?
November 13th, 2009 at 17:19
1rst: Great tutorial and really helpfull source code.
However there are some things i would like to point out to anyone that may be getting a bit confused:
(alexander: look toward bottom of this post for your answer)
First (i did not realize this) the camera is separte from what you are rendering, thus whatever you put on the screen should be in real co-ordinates. I ran into a problem with a tilemap because i was setting the tiles to always being drawn starting at 0,0 and was wondering why when i moved the camera it wasnt showing the rest of the rather large map. What i did was draw the sprites as they would be in their world coordinates. This made it accurate as the camera moves around the map not the map moving around the camera!
Also pay particular attention to this line.
See somthing odd here. The code is taking zoom and multiplying it by itself 3x! This was throwing all my calcluations off. The first thing i did was set that line above to:
Now your zoom level is accurate to how much you are actually zooming.
Now lets concentrate on the last part of code:
This is basically going to adjust for the camera’s movement. (which with normal cameras would just be – posx and – posy right? Well think about what that assumes. It assumes your origin is at the top left of the screen (0,0).
However this piece of code puts your camera origin at the center of the screen! Think of it with camera position of 0,0 with a screen size of 800width and 600height:
Here at no camera movement the origin of the camera is at the center of the screen. This means that if you are drawing your tiles (or whatever it is) starting at position 0,0 then you will see that tile in the upper left part of the screen (rather than in the middle)!
Also dont forget to account for zooming so:
(That will make sure that when you zoom the camera stays at the center point)
Here is a note on zooming that took me a bit to figure out that you might find helpful in calculating things.
Assuming width of tiles are 32, then how large or small is the tile enlarged when zoomed.
well you can (zoom * 32) this will tell you the size of the current tile if it is expanded or minimized
For instance
zoom tile width
.9 28.8
1.0 32
1.1 35.2
If you are handling camera movement where you want the camera to stop if your character is past a certain point (so that you dont
see the black areas of the screen) all you need to do is keep track of a seperate x and y value (that is the character movement) and
when the x passes the center point the appropriate camera value needs to pick up and start updating as well, otherwise it needs to be set at that barrier.
For instance in my game the barrier is 400 x and 300 y.
So when my char.x is < 400 then my camera should be stuck at 400. Else update camera x with char.x –(this will effectively pick up the camera when my char passes a certain point).
Hopefully this will make a little bit of sense. I am still working through the whole camera thing myself.
November 16th, 2009 at 6:53
[...] I followed the tutorial on http://www.david-amador.com/2009/10/xna-camera-2d-with-zoom-and-rotation/ to achieve a camera that follows my player sprite with zoom in/out [...]
November 16th, 2009 at 6:53
[...] I followed the tutorial on http://www.david-amador.com/2009/10/xna-camera-2d-with-zoom-and-rotation/ to achieve a camera that follows my player sprite with zoom in/out [...]
November 22nd, 2009 at 14:35
Hi,
Very nice solution! Congrat.
November 25th, 2009 at 10:21
How would you apply this when you would want to have 2 camera’s to follow 2 separate players?
November 25th, 2009 at 10:32
Nevermind I already figured it out. You can just draw the “scene” twice and place the second camera where you want it.
November 25th, 2009 at 11:49
Exactly. If you want to do a splitscreen for instance just draw the scene twice on different viewports.
I got this result using the camera with viewports http://www.youtube.com/watch?v=w0bELIEC0Q8
December 7th, 2009 at 9:12
Now I got it! You just made my day. Thanks.
December 14th, 2009 at 19:49
Very nice, saved me a bit of time implementing this myself.. There are a few errors that I needed to fix first, but all of them very superficial. Thanks!
December 29th, 2009 at 22:34
Hi, David! Nice tutorial. But can you correct the first block of code?
Use
_pos = Vector2.Zero;
Instead
_pos = new Vector2.Zero;
Thanks!!!! =)
December 29th, 2009 at 22:50
Hi André. Thanks for the tip, you are right Vector2.Zero is static, no need for new before.
Regards =)
January 12th, 2010 at 22:29
Nice solution!
How do i get the world co-ordinates from the mouse cursor when using the camera?
January 13th, 2010 at 18:14
Just add the camera position to the mouse position, do a function like this
Let me know if you run into any trouble.
January 14th, 2010 at 2:22
Thank you! Works great…
February 11th, 2010 at 21:29
Hey man!
I’ve been trying for hours to get a working camera. But I’m really lost and really new to programming ^^
Just wondering why when I copy the code in there’s instantly errors. Is this too advanced for me or what?
thanks.
The errors are “Rotation” Viewportwidth & Viewportheight, and
if (_zoom < 0.1f) _zoom = 0.1f;
February 11th, 2010 at 21:44
Actually you are right, there is something wrong with that function. try replacing the get_transform function with something like this instead
Tell me how it went
February 12th, 2010 at 17:37
Okay, I changed that function and ran the program with no problems(no errors
)
But whenever I move my little sprite he still runs off the screen and I can’t move the screen across the x-axis.
Is there a way to make this camera code follow my Sprite?
or move the camera.
thanks.
February 12th, 2010 at 17:49
Going to rewrite.
Getting myself confused.
When I try to put this above spritebatch begin I get errors
Camera2d cam = new Camera2d();
cam.Pos = Vector2(500.0f,200.0f);
I changed the Camera2d to Camera2D and it changed colour, but the there was errors with the spritebatch below it.
spriteBatch.Begin(SpriteBlendMode.AlphaBlend,
SpriteSortMode.Immediate,
SaveStateMode.SaveState,
cam.get_transformation);
Also there is an error with Vector2, really confused lol
any ideas?
February 12th, 2010 at 18:30
Yes there is. You can move the camera by changing the variable
cam.Pos to your character position.
Each time you move your character update the camera as well
February 12th, 2010 at 18:32
My bad again,
cam.Pos = Vector2(500.0f,200.0f);
should be
cam.Pos = new Vector2(500.0f,200.0f);
February 13th, 2010 at 17:39
could you give an example
of how I update the camera to my sprites position.
i know how to move the camera from its current location, which is center screen thanks to previous feedback.
my sprite is called mMainCharacterSprite
thanks, and sorry for my lack of knowledge
February 13th, 2010 at 17:42
Does your Sprite has a member Vector2 to save it’s position? Where are you saving the mMainCharacterSprite position?
just equal the camera.pos to that vector2
February 14th, 2010 at 13:20
the get_mouse_vpos() method doesn’t work with zooming. Any idea how to fix this? I just can’t get it to work.
February 14th, 2010 at 15:16
I’m not interely sure if this will work but maybe multiplying the mouse position with Zoom before adding the camera position
I’ve only considered Zoom when clicking a rectangle for testing if is inside and I simply multiply it’s size per Zoom so I’m guessing it should work with the mouse position as well. Let me know
February 14th, 2010 at 17:19
Craing something like
cam.pos = player.body.positin
in your update method
February 14th, 2010 at 17:19
ok thanks, got it working. Thanks for your help dude. I
February 15th, 2010 at 11:37
Thank you for your help still doesnt work. How did you do the “clickinsiderectangle” method? i create a rectangle from the virtual position of the mouse and ask if it intersects another rectangle. I also always have to add the middle of my screen as a Vector2(for example 800,600 in my case) to the x,y position of the rectangle I want to click to get valid coordinates. Maybe I have to multiply the zoom with this offset? Tried it…doesn’t do it.
Pretty confused why this isn’t working.
February 21st, 2010 at 11:28
This camera works fine for me
except this camera moves in the world : )) Is there any option that camera position will be fixed and world will be moving around it ? : )
For example i got object in middle of the screen with fixed position (viewPort.Width/2, viewPort.Height/2) and the rest of the world is moving around this object, depending on keyboard input
)
This camera changes the position of my object in world : )
February 21st, 2010 at 14:35
The camera being fixed and the rest moves is kind of the point that I wanted to avoid when I built this class. What makes sense is to move a camera in in world. Not translate everything to be on the camera. The camera itself does not change the position of anything except for itself. The Transformation Matrix simply moves the world to that specific position, draws it and that’s it. Your objects still keep their positions.
If you want to make Fix objects and still move the rest of the stuff you can, let’s take GUI objects for instance, they are always fixed you simply draw it in two batches. One of them with the camera transformation draws everything that moves, the other one, the gui stuff is drawn without that transformation
Hope this helps
February 21st, 2010 at 14:54
I used to check object.IsVisible with if object.position.x >viewPortRect.Width return false …. because my camera i used before was still keeping the followed “sprite” (my spaceship for instance) in its initializated Position : ) and moving were all the objects around
Now i had to check trough object.position.X> viewPortRect.Width + cam.pos.X – viewPortRect.Width/2.
The only problem was i had to repair my code on .. lots of places.. not very good solution though.
)
I already extended my math functions so it works fine with the camera
Thanks for help and swift answer
March 3rd, 2010 at 15:01
Hi there,
Thank you very much for this great tutorial, it helped me a great deal and got me working on my project again. I just have a short question which may be too general to ask here but I’ll do it anyway: How would I go about making the screen rotate smoothly? If I just set the _rotation variable to a certain value the screen instantly snaps to the new position, and something like
for(float i=0f; i < rotation_amount; i += 0.0001f)
{ _rotation += 0.0001f }
doesn't work either as it is too fast, no matter how small the increments are. Can anyone point me in the right direction?
March 3rd, 2010 at 15:15
You could update the rotation on the Update pump, something like camera._rotation+=0.001f; on every update until the value is what you want.
March 10th, 2010 at 19:07
Hey, great tutorial I found it very handy.
Though I have a problem, I am not sure how to solve, to determine if a sprite is displayed within the 2D viewport, when the camera has been rotated. Bascially I want an indicator to show the angle of an object only when the object moves offscreen.
March 10th, 2010 at 20:38
If anyone has a problem getting World – mouse coordinates, use the following way of transforming your matrix and calculating the right coordinates (it works with zooming).
Transformation :
I hope this helps you.
March 14th, 2010 at 13:50
[...] added a 2D Camera to the game. This allows zooming, panning, and rotation of everything in the game word. I'm not [...]
March 17th, 2010 at 12:47
Hey I was wondering why this doesn’t work:
Basically there is an offset which is the camera XY but I’ve dumbed it down for testing.
March 17th, 2010 at 13:02
First of all, don’t ever ever do this spriteBatch.Draw(this.Content.Load(“test1″),
Load it to a Texture2D and pass that variable to the spriteBatch
Second, what are you trying with Matrix.CreateTranslation(new Vector3(-16 + offset, -16 + offset, 0)) ??
What exactly is not working?
March 26th, 2010 at 0:08
Hey David, I have everything working to a good standard now.
I have to Zoom function working to a certain degree, I can put a fixed floating point number on it – But I was wondering if I could create it zooming in/out by keypress
I thought it was something like this
if (s.IsKeyDown(Keys.P))
{
_zoom++;
}
But im not entirely sure where I would put this, doesnt seem to working in my main game code . Any Ideas, maybe even a simpler way because on your youtube video I see that you zoom in and out.
March 26th, 2010 at 0:47
Add this function to the Camera Zoom Class
Then, iside your Update(Gametime gametime) on the Game class do something like this:
Hope it helps. Let me know if you run into any issue. I’m writing this from memory and I can be wrong on some syntax. Cheers
March 27th, 2010 at 19:02
function void IncrementZoom(float amount)
{
Zoom = Zoom + amount;
}
im getting an error with the void saying its not valid.
the rest seems fine.
ive never used function before either.
thanks
March 27th, 2010 at 19:45
Ups, mistyped, just write
public void IncrementZoom(float amount)
April 20th, 2010 at 3:46
Hey David
Thanks for this tutorial!
I have some comments:
1) public class Camera2d : Object2d
I assume that you extend it because it is essentially a 2d object.. are there any special properties to Object2d?
2) I assume the rest of the scripts go into the same class (except for the last one).
What’s up with this line? set { _zoom = value; if (_zoom < 0.1f) _zoom = 0.1f; }
I’m trying to understand this, but judging from the comment, I guess ‘%lt;’ somehow translates into <
3) Rotation does not exist in current context.. of course, use get and set.
Would you need to do _rotation%=360? Or will it appropriate that automatically?
4) ViewportWidth ViewportHeight: I'm still kinda new to XNA. It doesn't exist in the current context.
Am I supposed to initialize a Viewport in Game1.cs?
April 20th, 2010 at 9:15
Hi there Dennis.
1) Yes it’s basically an Object2D, no need to extend it though. It was a mistake of mine copying it from my engine where Object2D is the class that has the Vector2 Position, Rotation and Scale since, but I moved them to Camera2D in this example. Just remove that inheritance.
2) That line is to prevent zooms smaller than 0.1f (you can change to another value. The symbol is
<but wordpress bust have replaced it with weird stuff. It’s fixed now.
3) I’ve added the Get Set for Rotation property. Should work properly. Oh and on a side note, rotations in XNA are measured in Radians, not degrees, so if you want a 180º you should do Rotation = Math.PI, use the function MathHelper.ToRadians() to convert. Something like
Rotation = MathHelp.ToRadians(90); MathHelper is part of XNA Framework
4)In my example I’m abstracting from here you can get Viewport properties, but you can get it by accessing GraphicsDevice.Viewport.Width and GraphicsDevice.Viewport.Height inside your Game1 class.
April 25th, 2010 at 20:07
Thanks a lot.
I was looking for something like this for a whole day.
April 28th, 2010 at 23:45
Great tutorial, it was very helpful!
I have one question if anyone could answer it, I’m trying to figure out a way to translate the sprites world co-ordinates into co-ordinates related to my viewport. My goal is to have the camera start to zoom out as the player approachs the edge of the screen.
Any suggestions? thanks !
April 29th, 2010 at 0:39
if you need to know the sprite position relative to the camera just subtract the camera position to the sprite position. Something like
April 29th, 2010 at 3:07
Wow, I was way over complicating things ! Thanks !
The code that I ended up needed was
(playerPosition – cameraPosition) * cameraZoom
May 7th, 2010 at 8:18
when I rotate the camera then change the position of the camera (e.g. Position.X) then the camera will NOT go to the right only. instead it will go the World’s right (e.g. when rotating clock wise that will be Bottom right).
how can I make it go to the camera’s right while still keeping the rotation around the camera’s center ?
( I noticed that if i multiply the rotation Matrix first it will move to the camera’s right, but that will make the rotation around the Origin of the world, instead the center of the camera.)
and Thank you for the great article.
May 16th, 2010 at 7:05
Let’s say you have 50 to the right of whatever you are doing. So that would mean to move to the right 50 you would have to do x += 50. This works, but if you rotate everything it will no longer go 50 to the right, instead it will go 50 to the old right, or original right. To fix this you have to apply the rotation to the x as well. If you have 50, imagine that the new hypotenuse of a triangle. Now, the center of the screen is the pivot point, and you need to apply the math according to the x position. Let’s say you rotated the screen 25 degree’s. That means that in your right triangle of rotation you have the angle 25 degree’s, 90, and whatever is left.
Now, all you have to do is simply soh cah toa, in this case you have to do soh and cah, so y -= sin(25)/50, and x += cos(25)/50, or something around that.
July 6th, 2010 at 22:06
Excellent tutorial
Worked first time
September 21st, 2010 at 17:33
Hi David, first of all excelent tutorial
I was wondering how to make that the camera just zoom half of the screen insted of the hole thing. Lets say i have the game in the left part of the window and in the right, an option menu, so i dont want that menu to be zoom’d …
thanks in advance
September 21st, 2010 at 17:35
In that case you should use two viewports. One on the left and another one on the right.
Draw the 2 of them with different cameras with different zoom
September 21st, 2010 at 21:58
with two viewports do you mean two graphics device?
September 21st, 2010 at 22:03
Not at all. A viewport is a rectangular area of the screen where you draw.
You know those split screen games where you see one player camera on one side and another on other side?
Those are two viewports.
A letterboxed game is a viewport slightly smaller on Y to make the black bars.
Do a small search on XNA viewports and you’ll find how to implement it
September 21st, 2010 at 23:29
Ok ill take a look tyvm
September 28th, 2010 at 20:19
Hi, where do I put “Camera2D cam = new Camera2D();” when I put it in Draw of my game1.cs I can’t use it in Update and if I put it at the top of game1.cs it won’t update.
Thank you for the great tutorial!
September 28th, 2010 at 20:24
Stupid me…I put the “cam.Pos” code in Update! xD
October 7th, 2010 at 18:31
Thank you! This is just what I was looking for! Simple and clean and really easy to use!
October 16th, 2010 at 9:38
How would you return the dimensions of the camera?
October 16th, 2010 at 9:47
The dimensions of the camera are actually your Game Resolution in GraphicDevice.
If you want to keep track you can add a Vector2 member for easy access but don’t forget to update it each time you change Game Resolution
October 18th, 2010 at 0:29
Does this also consider zoom?
I’ve drawn GraphicsDevice.DisplayMode.Width and GraphicsDevice.Viewport.Width, and they both draw 1280 (my native resolution) even with varying zoom levels.
I’ve also saved the viewport dimensions in get_transformation
Thanks,
Dennis
October 18th, 2010 at 12:22
Hi David, I know XNA 4 has changed everything but what has me stumped is the new spriteBatch.Begin function, because I can’t find where I’d add the camera information.
Old function:
spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState, cam.get_transformation(GraphicsDevice));
New function (from what I gather):
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null);
October 18th, 2010 at 12:34
Hi Chris, It’s the last parameter, you can keep the rest as null.
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null,cam.get_transformation(GraphicsDevice));
October 18th, 2010 at 12:45
Oh I tried that but it told me I couldn’t convert Framework.Matrix to Graphics.Effect.
I tried to cast it to an effect to no avail, though as I did it I thought it was a stupid idea!!
October 18th, 2010 at 12:47
never mind I just needed a 4th null in between the null’s and the camera code!
Thanks David!
October 31st, 2010 at 13:47
Hello everyone!
I was able to study in detail the operation of the array _transform and I noticed that changing a single parameter you can get a function to calculate the position of an object relative to the world, or to the area displayed.
In the function
If you substitute the parameter 0 with the number 1 in the “createscale” function you can write a function that converts the coordinates of an object on the map in the coordinates on the Camera2D (taking as a point O (0, 0) in the top left corner of Camera2D) and another function that converts the coordinates of a object on the screen (like the mouse pointer) in global coordinates (taking as a point O (0, 0) in the top left corner of the board).
In particular:
become
the two functions can be written as follows:
and
this functions work in every situation, with the camera2d zoomed or rotated or both.
November 1st, 2010 at 10:43
Oh, I forgot to say that when you work with matrix the best thing to do is multiply the matrix by the Identity one first. It’s like multiply a number by 1, the result does not change, but it is almost necessary to avoid any kind of trouble. I think is because multiplying by the Identity Matrix normalized the result and makes it more reliable! So the get_transformation function become:
public Matrix get_transformation()
{
transform =
Matrix.Identity *
Matrix.CreateTranslation( new Vector3(-this.position, 0)) *
Matrix.CreateRotationZ(this.rotation) *
Matrix.CreateScale(new Vector3(this.zoom, this.zoom, 1)) *
Matrix.CreateTranslation(new Vector3(this.view.Width * 0.5f, this.view.Height * 0.5f, 0));
return transform;
}
December 5th, 2010 at 12:04
you are a guru of xna !!!
December 10th, 2010 at 23:12
Great solution. With some minor tweaks, it worked for my game. It’s simple and elegant. Thanks a ton
December 15th, 2010 at 15:52
Is there a way to affect also PrimitiveBatch?
December 15th, 2010 at 15:56
Unfortunately no, at least not using SpriteBatch, although you can use matrices to affect PrimitiveBatch, just not the same way as SpriteBatch
December 16th, 2010 at 14:12
Shouldn’t you also compensate for the fact that on the screen the Y axis increases when you go down while in the world it increases when you go up?
January 7th, 2011 at 16:04
How should the code look like in the end? I’m attempting to integrate it but am getting about 28 different errors as a result.
Can you include a source file or a preview example of what the entire file could look like in the end?
Thanks for a great tutorial though, seems to be exactly what I need if I can get it to work.
January 8th, 2011 at 21:13
Thanks for the example David, but I am having trouble getting the camera to work with my spriteManager. For some reason when I run my game everything is black(the default background color). When I remove the “cam.get_transformation” from the SpriteBatch, my sprites are visible once again. I am also updating the camera position to the player position on the update call.
Is the reason for the black screen my spriteManager or do you think I implemented the camera wrong?
January 8th, 2011 at 21:46
Without any code is hard to see what’s wrong, maybe sprites are all out of the camera by accident?
January 9th, 2011 at 22:19
HI David,
How do I get the camera to follow my players sprite without the camera rendering past my levels edges.
I can get the camera to follow my player by settings the camera’s position to my players position, but that still draws the baby blue background even after my player can’t go any further.
The nearest video example I can show is in your multi camera/player video on youtube: http://www.youtube.com/watch?v=w0bELIEC0Q8
Here you have the red player moving about freely but with a grass texture on the ground. What I would like is for my player, and camera, to only move about on the grass area. If that makes sence.
I have tried a few things but can’t get it to work just right.
Do you think you can help with this?
January 9th, 2011 at 22:32
You can check the boundaries of the camera size with the grass area. Basically the camera size is the windows size, something like 800×600 or 1024×768.
Only allow for the camera to move if the camera rectangle is inside the Grass rectangle.
Another way is, if you start drawing grass from x=0 and y=0 till, let’s say x=2000 and y=2000 you only allow the camera pos to go between 0;0 and 2000-cameraSizeX and 2000-cameraSizeY
January 10th, 2011 at 12:39
Great tutorial. Would you happen to know how to make it so that the camera moves with the character?
I’m making a game where you look from a birds eye view and you navigate through a maze. Basically I want the camera to be zoomed in on a character and that camera to move in the same direction as the character when he navigates through the level.
Any help would be great because we need this done for the video game competition that requires our submission by February 15th.
January 10th, 2011 at 12:53
Well just keep updating the camera pos with the character pos. To constrain it to a certain area just check my previous comment. As for the zoom you can already use the Zoom property on this example to zoom in our out
January 11th, 2011 at 17:16
I’ve been trying that.
At the moment I have my level assests loaded in via a text file that start at X 0 and Y0.
The camera code I have been trying is:
cam.Pos = new Vector2(590.0f, 200.0f);
if (playerSprite.Position.X > cam.Pos.X – 100.0f)
{
cam.Pos = playerSprite.Position;
}
Also this:
cam.Pos = playerSprite.Position;
if (cam.Pos.X <= graphics.PreferredBackBufferWidth)
{
cam.Pos = playerSprite.Position;
}
The first does work, but simply jumps to my player once they reach the desired distance away and the later dose nothing.
Do you have any ideas what I'm doing wrong/not getting?
January 14th, 2011 at 9:27
I have a question about rotation:
When I rotate an image 90 degrees using the camera, using the Move() function to move the camera up or down results in the camera moving diagonally. Is there a way to fix this?
This also might be my fault, but when I try moving 16 pixels in one direction, it seems to move 32 pixels. I fixed that by dividing my move amounts in 2, (put 8 into the function, camera moves 16), but is that how it’s supposed to work?
January 17th, 2011 at 2:55
[...] using the David’s 2D camera, it’s very useful, i had to modify part of the script beacuse when i rotate the camera the [...]
January 18th, 2011 at 18:45
Hey,
I think you are going about it the wrong way. Instead of making the camera jump back to your character when it hits the edge, just stop the update cycle from happening when it hits the edge. Something like…
if(cam.Pos.X > 0)
{
update camera position here. Also do for Y
}
That way, if the camera goes out of bounds (aka below 0), it just stops updating at all (therefore avoiding the bounceback). Of course yours is centered on your sprite, so 0 might be the wrong number to put in, but I hope that puts you on the right track.
January 23rd, 2011 at 21:06
Hi David, thanks for the tutorial! I have a minor issue with the zoom though.
I am using a custom piece of code to draw the tiles in my game. they are 64×64. I have 2 different modes to play in full HD and 720p as well. When I am in 720, I want to zoom out (zoom = .75). When I do this, i see grid lines in the map. I don’t understand where the problem is coming from. i chose .75 because 64*.75 is 48 so there should be no issues with floating values, but obviously there is something wrong with my code. To draw the map, the following code is used.
[/]
for (int x = 0; x < mapHeight; ++x)
{
for (int y = 0; y < mapWidth; ++y)
{
//Tile Layer 1
// If there is a visible tile in that position
if (TileLayer1.layer[y, x] != 0)
{
//get the tileSheet bounds so the correct tile is drawn
bounds = tileSet[TileLayer1.layer[y, x] – 1];
//Game1.spriteBatch.Draw(Game1.tileSheet, new Vector2(((y – drawOffset.X) * tileWidth),
//((x – drawOffset.Y) * tileHeight)), bounds, Color.White);
Game1.spriteBatch.Draw(Game1.tileSheet, new Vector2(((y – drawOffset.X) * tileWidth),
((x – drawOffset.Y) * tileHeight)), bounds, Color.White, 0, new Vector2(0), 1f, SpriteEffects.None, 0);
}
}
}
[/code]
any ideas on this? its really been bothering me, I have thought of rendering the entire map to a texture2d before the game and just using one big image, but I really want to learn what is wrong here, and would prefer not to render to one texture. Any help is much appreciated. thanks so much.
January 26th, 2011 at 22:50
Just needed zoom, woks perfect! Thank You.
February 10th, 2011 at 21:20
David,
Great Tutorial but I am having trouble getting it to work. All other code is working and building correctly with the exception of ‘get_transformation’ method. The error I am constantly getting it “ViewportHeight/ViewportWidth do not exist in current context’.
When I declare them as either of the following they each produce their own error:
Private Viewport ViewportHeight – Cannot implicitly convert type ‘float’ to ‘Microsoft.Xna.Framework.Graphics.Viewport’
I tried declaring them as floats, but I was given this error instead:
SimpleGame.Camera2d.get_transformation(Microsoft.Xna.Framework.Graphics.GraphicsDevice)’: not all code paths return a value
Any idea what I am doing wrong? (Using VSC#Expree 2008 and XNA3.1)
February 10th, 2011 at 21:29
That error “not all code paths return a value” is due to some section of your method not returning anything.
See example:
float getnumber(bool returnsomething)
{
if(returnsomething == true)
{
return 10.0f;
}
// I should be return something here as well, this is what is causing that “not all code paths return a value”
}
February 19th, 2011 at 0:47
Mine says that ViewportWidth and ViewportHeight don’t exist in the current context. I do not know why. Any help would, I guess, help.
March 8th, 2011 at 7:09
No overload for method ‘get_transformation’ takes 0 arguments. I got this error, may i know what argument do i nid to put inside the cam.get_transformation() in the spriteBatch.Begin? Thx in advance.
March 15th, 2011 at 13:44
Hi for some reason when i implement this code and run the spriteBatch.Begin(SpriteBlendMode.AlphaBlend,
SpriteSortMode.Immediate,
SaveStateMode.SaveState,
cam.get_transformation(device /*Send the variable that has your graphic device here*/));
i get a purple screen, but when i run normal spritebatch.Begin(); it draws all sprites properly.
can someone please explain this…
March 15th, 2011 at 15:12
Agentnebraska try:
public Matrix get_transformation(GraphicsDevice graphicsDevice)
{
_transform = // Thanks to o KB o for this solution
Matrix.CreateTranslation(new Vector3(-_pos.X, -_pos.Y, 0)) *
Matrix.CreateRotationZ(Rotation) *
Matrix.CreateScale(new Vector3(Zoom, Zoom, 0)) *
Matrix.CreateTranslation(new Vector3(graphicsDevice.ViewPort.Width* 0.5f, graphicsDevice.ViewPort.Height* 0.5f, 0));
return _transform;
}
March 15th, 2011 at 15:18
Sorry i meant:
spriteBatch.Begin(SpriteSortMode.BackToFront,
BlendState.AlphaBlend,
null,
null,
null,
null,
cam.get_transformation(device /*Send the variable that has your graphic device here*/));
This is only with xna 4
March 21st, 2011 at 12:02
Hello there!
I was about to post when I noticed someone above already mentioned this problem. But since it hasn’t been corrected I’ll reinfoce it.
You should really change your scale matrix to Vector3(Zoom, Zoom, 1) instead of Vector3(Zoom, Zoom, 0), because when you try to calculate the inverse of your transformation matrix, that 0 makes the whole calculation fail. It was a quite a nightmare to notice too.
March 21st, 2011 at 12:05
Regarding the recommendation to start with an Identity Matrix multiplication, what is your source for that recommendation?
I’m wondering because I haven’t run into any problems whatsoever without doing that.
March 21st, 2011 at 12:06
Changed it, thanks
March 22nd, 2011 at 15:57
I have been trying to grasp this camera class for a week! I can adjust where the camera is in the world statically but i cant lock it onto my character? And i’ve looked through the class and cant find any part that says move with W,A,S,D for example?
public class Camera2d
{
protected float _zoom; // Camera Zoom
public Matrix _transform; // Matrix Transform
public Vector2 _pos; // Camera Position
protected float _rotation; // Camera Rotation
public Camera2d()
{
_zoom = 1.0f;
_rotation = 0.0f;
_pos = Vector2.Zero;
}
// Sets and gets zoom
public float Zoom
{
get { return _zoom; }
set { _zoom = value; if (_zoom < 0.1f) _zoom = 0.1f; } // Negative zoom will flip image
}
public float Rotation
{
get { return _rotation; }
set { _rotation = value; }
}
// Auxiliary function to move the camera
public void Move(Vector2 amount)
{
_pos += amount;
}
// Get set position
public Vector2 Pos
{
get { return _pos; }
set { _pos = value; }
}
public Matrix get_transformation(GraphicsDevice graphicsDevice)
{
_transform =
Matrix.CreateTranslation(new Vector3(-_pos.X, -_pos.Y, 0)) *
Matrix.CreateRotationZ(_rotation) *
Matrix.CreateScale(new Vector3(Zoom, Zoom, 0)) *
Matrix.CreateTranslation(new Vector3(graphicsDevice.Viewport.Width * 0.5f, graphicsDevice.Viewport.Height * 0.5f, 0));
return _transform;
March 22nd, 2011 at 16:01
Yes you can, just use camera->pos = somevector. That some vector can be your character position
Somewhere on your code, Update() for example just keep the camera position updated with your character position
March 23rd, 2011 at 11:42
i understand the basic premise of what your saying but technically i am awful at programming (Beginner). Could you write that part of the code as if you were talking to a complete novice? And where it goes, i know update but in game1 update, character update, camera2d update?
Thanks
March 25th, 2011 at 16:56
please….: )
March 25th, 2011 at 17:05
You should place that code on your Game1 Update function.
Once again remember you should find out which variables correspond to your real situation. Screenwidth and Screenheight is most probably 1280×720 (Pc/Xbox) or 800×480 (WP7)
March 26th, 2011 at 23:57
I am trying to make the camera go forward in which ever direction the camera is rotated. This is what I have so far but it doesn’t seem to work right.
if (newKeyState.IsKeyDown(Keys.Up))
{
cam.Move(new Vector2(
(float)(Math.Cos(cam.Rotation – MathHelper.PiOver2) * 5.0f),
(float)(Math.Sin(cam.Rotation – MathHelper.PiOver2) * 5.0f)));
}
Thanks.
March 30th, 2011 at 11:24
Thanks for your help but unfortunatly i still cant get it to work. I put the code in the update and most of the phrases it comes up with
e.g “characterpos does not exist in the current context.”
I’ll take a look at other tutorials as well to see what is wrong.
April 5th, 2011 at 23:19
[...] http://www.david-amador.com/2009/10/xna-camera-2d-with-zoom-and-rotation/ [...]
April 24th, 2011 at 1:18
Hello! This is an awesome tutorial.
I’m trying to implement a smooth target change, but I’m having trouble. Can you possible help?
Here is what I have, though it doesn’t work at all =( (cam just keeps moving on vector)
else if (target == “guy2″)
{
if (cam.Pos != guyVector2)
{
cam.Move(guyVector2);
}
}
any ideas?
April 24th, 2011 at 1:37
Ok,
So I’ve gotten this far:
else if (target == “guy2″)
{
if (cam.Pos != guyVector2)
{
direction = guyVector2 – cam.Pos;
direction.Normalize();
cam.Pos = new Vector2
(cam.Pos.X + direction.X,cam.Pos.Y + direction.Y);
}
}
This works, but only sort of. It goes to the guy then stops, but the camera “shakes” and looks really weird. I think it’s because it may not be able to get exactly onto the guyVector2, so it kind of goes back and forth at the end.
Any ideas on how to address this?
April 24th, 2011 at 14:48
Hi ive used this to create a 2d camera in my tile game, but im having problems ‘transforming’ my mouse position. Thing is if i rotate or zoom the camera i cannot seem to compensate for the mouse position. As i zoom or rotate, the mouse x and y positions no longer represent the real world coordinates.
I really need to get this sorted, can someone please help me out?
Thanks a lot if you can.
April 26th, 2011 at 2:20
Casey,
I’m having the same issue. I would like to move the camera )or a sprite the camera is attached to) in the direction the camera is rotated.
Have you had any luck?
May 11th, 2011 at 4:23
[...] Credit to David Amador [...]
May 13th, 2011 at 15:01
It’s a nice camera once you get it working but my tiles aren’t correctly aligned if i dont use interger value (i can see some space between some tiles if i use float value) I corrected the situation making sure the matrix return some “integer” number. Also because of that i can’t use the zoom for now as it will cause to see some empty space between my tiles…
I also had to change the line :
Matrix.CreateTranslation(new Vector3(ViewportWidth * 0.5f, ViewportHeight * 0.5f, 0));
to put 0.001f instead of 0.5f cause i wouldn’t see a thing otherwise.
now i need to find a way to move the camera smoothly when i adjust the position of my player on a slope tile…right now it can go down 10-12 pixel down in one shot hence changing the Y coordinate of the camera and it feel sluggish..
anyway thanks a lot for this tutorial tought i might go back to normal scrolling…
May 24th, 2011 at 18:01
A modification to the Get mouse position script above allows you to keep the matrix centered and still get the mouse position in world coordinates:
[code]
public Vector2 get_mouse_pos()
{
float MouseWorldX = (Mouse.GetState().X - graphicsDevice.Viewport.Width * 0.5f + (Game1.Camera.Pos.X) * (float)Math.Pow(Game1.Camera.Zoom, 1)) /
(float)Math.Pow(Game1.Camera.Zoom, 1);
float MouseWorldY = ((Mouse.GetState().Y - graphicsDevice.Viewport.Height * 0.5f + (Game1.Camera.Pos.Y) * (float)Math.Pow(Game1.Camera.Zoom, 1))) /
(float)Math.Pow(Game1.Camera.Zoom, 1);
return new Vector2(MouseWorldX, MouseWorldY);
}
[/code]
June 9th, 2011 at 16:18
[...] Camera 2D With Zoom and Rotation [...]
June 14th, 2011 at 1:22
Thanks for the tutorial, but I’m having problems. I got a null reference error in the get_transformation method, and it’s beyond me. Does anyone understand this problem?
June 25th, 2011 at 10:51
Nice! I knew about these transformation matrix thing, but I didn’t know exactly how to use them. Thanks David and Tux89!
June 27th, 2011 at 11:37
Hey, I am having some severe problems with the camera breaking the drawing of objects on the screen. Things appear and disappear randomly. I described the problem here :
http://forums.create.msdn.com/forums/p/85582/515490.aspx#515490
and here:
http://stackoverflow.com/questions/6486484/2d-camera-breaking-position-of-everything
I would be very grateful for any help!
July 22nd, 2011 at 11:33
Hello! thanks for the camera code, is perfect and work perfectly.
But I don’t know how implent this in a wp7 game.
If the camera is tourn off, when I want to detect a click over a rectangle, I do: rect.Contains(click)
But, when I turn on the camera and I do a zoom in or zoom out I don’t know how know the correct position and dimensions of the rectangle to do the correct “Contains” of the click.
How can I change this params? (Positions and dimensions of the rectangle)
I’ve try the code that you posted for the mouse click but it don’t work to me.
Thanks for all and sorry for my english, i’m spanish.
Bye!
August 1st, 2011 at 19:07
Hi! When using this camera there’s total anarchy in the drawing order: If I draw texture B after texture A, texture A might aswell apear over texture B wich I don’t get..? Why is that? Great work anyhow.. thanks alot!
August 1st, 2011 at 19:35
I changed the SpriteSortMode to immediate and now it seems to work just fine! thank you very much! regards from sweden..
August 3rd, 2011 at 2:08
Great job…as I just copy&pasted the code, I want to contribute a little. For anyone who needs mouse control for the transformations:
You need those:
Hope html works here…
August 10th, 2011 at 14:41
Hi people.
First of all, great tutorial. And great comments to. It´s a nice contribution.
But I still dont get one thing. This “problem” has been said here. When I rotate my camera and press the button to go to the right, I would like to go to the right of the screen, not to the right of the camera, making my scene go “up”, for example.
I figure out that I must use the method Move of the camera object with a parameter regarding the rotation of this camera, but I missed out the calculations…
Any help?
Thanks a lot.
September 1st, 2011 at 3:35
Thank you so much! I have made several XNA prototypes and always wondered how to use a 2d camera like this. I knew that it HAD to be something with Matrices but I am not really versed in 3d so I’m not used to working with them. From the tutorials I’ve gone through, these calculations look awfully familiar. I might have tried something myself had I realized that SpriteBatch.Begin() took a transformation matrix… go figure.
Awesome job commenters on the contributions! Special thanks to Tux89 for the code to translate vectors between local and world. Works like a charm. Now, there must be a way to move the camera’s position intuitively based on screen orientation while rotated instead of based on world coordinates.
September 12th, 2011 at 17:11
[...] caméra 2D (source pour ceux que ça [...]
September 18th, 2011 at 4:22
September 23rd, 2011 at 8:46
Thank you very much David for this nice piece of code.
Also thanks BrassX for the mouse transformation.
This was really useful for me.
October 5th, 2011 at 9:00
Hi,
Great code but i am wondering,
Is there a way to see if an object is in/out sight of the camera??
Thanks
October 30th, 2011 at 19:55
mac…
[...]XNA Camera 2d with zoom and rotation | David Amador[...]…
November 11th, 2011 at 5:14
[...] http://www.david-amador.com/2009/10/xna-camera-2d-with-zoom-and-rotation/ [...]
December 12th, 2011 at 18:44
[...] but I have a little issue with my camera and mouse. When I add the camera that I use to my game (see here) my mouse pointer seems to be in the wrong location. When I call my Mouse.GetState().X or Y the [...]
December 22nd, 2011 at 21:13
how would i implement side-by-side or over-under stereoscopic 3d modes using this camera?
January 23rd, 2012 at 9:34
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace Learning1
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
KeyboardState newstate;
public class Camera2d
{
protected float _zoom; // Camera Zoom
public Matrix _transform; // Matrix Transform
public Vector2 _pos; // Camera Position
protected float _rotation; // Camera Rotation
public Camera2d()
{
_zoom = 1.0f;
_rotation = 0.0f;
_pos = Vector2.Zero;
}
}
// Sets and gets zoom
public float Zoom
{
get { return _zoom; } // Error
set { _zoom = value; if (_zoom < 0.1f) _zoom = 0.1f; } //Error Negative zoom will flip image
}
public float Rotation
{
get { return _rotation; }
set { _rotation = value; }
}
// Auxiliary function to move the camera
public void Move(Vector2 amount)
{
_pos += amount; // _pos (no ex)tension method to contain argument
}
// Get set position
public Vector2 Pos
{
get { return _pos; }
set { _pos = value; }
}
public Matrix get_transformation(GraphicsDevice graphicsDevice)
{
_transform =
Matrix.CreateTranslation(new Vector3(-_pos.X, -_pos.Y, 0)) *
Matrix.CreateRotationZ(Rotation) *
Matrix.CreateScale(new Vector3(Zoom, Zoom, 1)) *
Matrix.CreateTranslation(new Vector3(ViewportWidth * 0.5f, ViewportHeight * 0.5f, 0));
return _transform;
}
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
Texture2D myTexture;
Vector2 Posp = new Vector2();
Vector2 spritePosition = Vector2.Zero;
Vector2 spriteSpeed = new Vector2(50.0f, 50.0f);
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
myTexture = Content.Load(“orange”);
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
KeyboardState newstate = Keyboard.GetState();
if (newstate.IsKeyDown(Keys.Right))
{
Posp.X += 1;
}
else if (newstate.IsKeyDown(Keys.Left))
{
Posp.X -= 1;
}
else if (newstate.IsKeyDown(Keys.Up))
{
Posp.Y -= 1;
}
else if (newstate.IsKeyDown(Keys.Down))
{
Posp.Y += 1;
}
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
Camera2d cam = new Camera2d();
cam.Pos = new Vector2(500.0f, 200.0f);
spriteBatch.Begin(SpriteSortMode.BackToFront,
BlendState.AlphaBlend,
null,
null,
null,
null,
cam.get_transformation(device /*Send the variable that has your graphic device here*/));
spriteBatch.Draw(myTexture, Pos, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
hi , i really need help with that as i managed to move the char but when i am applying ur code to create the camera to my char it keep giving me error about the 4 variables ( _Pos , _zoom , _ rotation , _transform) beside the ( cam.get_transformation(device
January 23rd, 2012 at 11:43
oh Nvm , i figured it out as i had lots of embarrising mistakes ( including i had 2 classes in the same main code
so it i sworking now except i had to move the camera constructor from “Draw” stage cuz that is crashing my pc as it keep creating the camera in every update/sec ….. your code was so helpful .. thank you
February 2nd, 2012 at 14:24
I am obviously asking a dumb question here but is there a link somewhere to the source code that I have missed?
February 2nd, 2012 at 14:25
Nope, the source is on the Post itself