I have a map, containing many objects in an area sized 5000*5000. my screen size is 800*600.
how can i scroll my map, i don't want to move all my objects left and right, i want the "camera" to move, But unfortunately i didn't found any way to move it.
Thanks
I think you are looking for the transformMatrix
parameter to SpriteBatch.Begin
(this overload).
You say you don't want the objects to move, but you want the camera to move. But, at the lowest level, in both 2D and 3D rendering, there is no concept of a "camera". Rendering always happens in the same region - and you must use transformations to place your vertices/sprites into that region.
If you want the effect of a camera, you have to implement it by moving the entire world in the opposite direction.
Of course, you don't actually store the moved data. You just apply an offset when you render the data. Emartel's answer has you do that for each sprite. However using a matrix is cleaner, because you don't have to duplicate the code for every single Draw
- you just let the GPU do it.
To finish with an example: Say you want your camera placed at (100, 200). To achieve this, pass Matrix.CreateTranslation(-100, -200, 0)
to SpriteBatch.Begin
.
(Performing a frustum cull yourself, as per emartel's answer, is probably a waste of time, unless your world is really huge. See this answer for an explanation of the performance considerations.)
Viewport
You start by creating your camera viewport. In the case of a 2D game it can be as easy as defining the bottom left position where you want to start rendering and expand it using your screen resolution, in your case 800x600
.
Rectangle viewportRect = new Rectangle(viewportX, viewportY, screenWidth, screenHeight);
Here's an example of what your camera would look like if it was offset off 300,700
(the drawing is very approximate, it's just to give you a better idea)
Visibility Check
Now, you want to find every sprite that intersects the red square
, which can be understood as your Viewport
. This could be done with something similar to (this is untested code, just a sample of what it could look like)
List<GameObject> objectsToBeRendered = new List<GameObject>();
foreach(GameObject obj in allGameObjects)
{
Rectangle objectBounds = new Rectangle(obj.X, obj.Y, obj.Width, obj.Height);
if(viewportRect.IntersectsWith(objectBounds))
{
objectsToBeRendered.Add(obj);
}
}
Here's what it would look like graphically, the green sprites are the ones added to objectsToBeRendered
. Adding the objects to a separate list makes it easy if you want to sort them from Back
to Front
before rendering them!
Rendering
Now that we found which objects were intersecting we need to figure out where on the screen the will end up.
spriteBatch.Begin();
foreach(GameObject obj in objectsToBeRendered)
{
Vector2 pos = new Vector2(obj.X - viewportX, obj.Y - viewportY);
spriteBatch.Draw(obj.GetTexture(), pos, Color.White);
}
spriteBatch.End();
As you can see, we deduce the X
and Y
position of the viewport to bring the world position of the object into Screen Coordinates
within the viewport. This means that the small square that could be at 400, 800
in World Coordinates
would be rendered at 100, 100
on the screen given the viewport we have here.
Edit:
While I agree with the change of "correct answer", keep in mind that what I posted here is still very useful when deciding which animations to process, which AIs to update, etc... letting the camera and the GPU make the work alone prevents you from knowing which objects were actually on screen!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With