C++ Tile Engine from Scratch -- Part 3
In the last tutorial, we set up the groundwork for our tile engine by implementing the image manager and a Tile class, and then used those to draw a tile to the screen. Well, if drawing one tile was our goal in the last tutorial, our goal this tutorial is going to be drawing a whole bunch of tiles.

I want to make it clear that the way I am setting up this engine is in no way definitive. There are many ways to design a tile engine, and this is just how I've decided to design it this time. I hope that these tutorials get your mind thinking of cool new ways to design a tile engine, ways to make it faster, etc.

Solving an Issue
The most common use for a top-down 2D tile engine is for an rpg, and that is going to be the target "audience" for our tile engine. So, we have an issue that we need to consider. An RPG map can be large, hundreds of tiles wide and hundreds of tiles tall. So how do we draw all of that?

The answer is, we don't. Instead, we draw only a portion of the map on any frame. How do we decide which tiles to draw and where? The solution I like to use actually comes from 3D programming. We're going to implement a Camera.

The Camera will represent a viewport through which the user sees the map. It will have a position somewhere on our map with absolute pixel coordinates (i.e. if the x position is 200, it's 200 pixels to the right of the map origin, which is the upper left corner). It will also have a size, which we can use to determine how many tiles are visible through it. These two properties together will allow us to keep track of which tiles to draw and where.

I'd also like to implement another effect we can accomplish with a camera class, scrolling. We'll keep a target position, and move the camera towards the target slowly over time.

If that didn't make any sense, compile and take a look at the program included at the end of this tutorial.

The Camera Class
Now let's go ahead and create our Camera class in a new header file called "Camera.h":

Hopefully nothing too complicated. We have members for the camera's position and target, as well as it's size and speed. The speed variable will be used in the Update method to allow the user of the class (whoever that may be) to have some control over how quickly the camera scrolls to the target.

There are two methods for changing the camera's position. The two Move methods will set the camera's position, moving it instantly to the specified coordinates. The two GoTo methods however, will set the camera's target, causing the camera to scroll to the specified coordinates over time.

There's a Center version of both Move and GoTo, that will center the camera or target on the specified coordinates rather than set the camera's upper left corner (the camera's origin). This will be useful for centering over the player later on, and encapsulates the camera's size away from the rest of the engine.

We've implemented inline versions of GetPosition and GetTileOffset, since they are fairly trivial functions and this will remove any unnecessary overhead. GetPosition simply returns the camera's position, while GetTileOffset return the camera's position relative to the nearest tile's origin. Both of these will be useful when drawing our tiles and moving the camera around.

Alright, time to implement all this fun stuff, so let's do so in a new code file called "Camera.cpp":

Most of this code should be self explanatory, except for maybe the Update method. Unfortunately, there is a bit of math involved (oh noes!), but nothing too difficult. I've commented the code enough that anyone with any knowledge of algebra should understand it. If not, then I suggest reading any of the great math primers available here on Dream.In.Code. Hopefully the rest of this code will make sense after we implement a new RenderFrame method.

The Level Class
Alright, we now have a way of determining which tiles to draw and where. Now we need a way of storing each of the tiles. Since we're implementing the framework for an RPG engine, let's call our next class Level. Go ahead and create a new header file, call it "Level.h", and fill it with the following code:

We're going to store our map data in a 2D array. While we could have accomplished this with Tile* map[MAXWIDTH][MAXHEIGHT];, or something similar, we want our engine to be as versatile as possible. Therefore, we want a dynamic array. Unfortunately, there isn't a very simple way of doing that, but this is as simple as it gets. What we're using is a vector of a vector of Tile pointers. The cool part about this, is we can actually access individual Tile pointers with the familiar map[x][y] syntax.

In case it's ever requested later on, we go ahead and keep track of the map's width and height. The map's width and height are changed by the SetDimensions method, which is private right now since it's only needed by the Level constructor. We then have an AddTile method for putting a tile into the map, and a GetTile method for retrieving a tile from the map.

The LoadLevel method will be implemented in our next tutorial, and will load level data from a file on the harddrive.

Alright, time to implement this class in a new code file called "Level.cpp":

This is all very simple actually. The constructor takes in a width and height for defining the dimensions of the Level, which then uses the SetDimensions method to resize the map vector. Notice how we must first resize the map vector, which is a vector of vectors, with the width and then resize each of the vectors in that vector, which are vectors of Tile pointers. We also make sure that we initialize the vector with NULL pointers, so we don't have any nasty access violation exceptions later on.

Using These New Classes in Our Engine
Great, we now have a way to store the level data, and a way to determine how we're going to draw our frames. Now it's time to put this together to create a test demo. First, let's rewrite our RenderFrame method in Engine.cpp:

This will be the method we'll stick to for most of this tutorial series. What this method does is asks the camera which tiles are currently in view as well as how much the camera is offset from those tiles. Then it loops through each row of tiles and each column, starting from bounds.Top and drawing bounds.Height rows, and starting from bounds.Left and drawing bounds.Width columns. Inside the loop we get the current tile we're drawing, and tell it to draw at the current row/column, taking into account the camera's offset.

If it seems complicated, try working through it manually to see if you can figure out how it works. The following method, which we've added to Engine, is a temporary method that generates a simple level for us to look at:

We're letting the user click on a new location to center the camera over, and use GoTo so it scrolls there slowly instead of using Move to do it instantly. Then we remember to call camera->Update(); in the Update function.

Conclusion
Phew! That was a lot of code, but our objective was to draw a lot of tiles, and we have. Unfortunately (and I promise this will never happen again!), I forgot to save a copy of this tutorial's source code before beginning to write the code for the next tutorial, so you'll just have to check out that tutorial! See you soon!

You have this function. Also I don't see any place where you defined the tile size so I assumed this would be done in a header file with constants in it or it would be gained from a config file later on. Am I right or did I miss something?

So far, this tutorial is great, but I still can't get my images to load so I'm not sure what I'm doing wrong. I've checked everything about 10 times now.

you create several instances of Tile objects dynamically, but you never delete them anywhere in your code, which could lead to memory leaks;

let's say we have a map smaller than the screen we're using (like in Pokemon, for example) - the draw tiles loop in Engine::RenderFrame() doesn't take into account the actual size of the map (which could be really small), only the screen resolution - you'll be accessing invalid memory regions;

you don't place restrictions on the Camera target values - if someone tried to click "indefinitely" to reach the edge of the map, eventually target values become invalid and you'll be accessing invalid memory regions.

More than code about tiling engines, I think everyone would appreciate if you put code that avoids problems like memory leaks and accessing invalid memory addresses.

But keep up the good work. Started this tutorial yesterday and I can't wait for the other parts

PS: Try replacing the operator[] with function Vector::at() when you're accessing vector positions. Invalid memory access errors aren't masked this way and are easier to detect.

I'm also very much enjoying this tutorial - as two of my favorite games of all time (Zelda and Shining Force) were written similarly. I think we all are experiencing some confusion however, as some of the functions are not defined, and due to sfml 2.0 being in beta (and constantly changing) some of the code here I've had to change to work with sfml (such as changing most Image class references to Textures)..

This last lesson is throwing me a bit. I had to add a Camera class variable to the Engine, and hope I did it right. But the real kicker seems to be the temporary testing it all in the ProcessInput() from Engine.cpp. So far I've had to change detecting a mouse event (I changed it personally to:

if (sf::Mouse::IsButonPressed(sf::Mouse::Right)) { //camera code
}

but also am having trouble with the code inside there camera->GetTileBounds is not available, and not sure where gettilebounds is even defined (did I miss something)?

You have this function. Also I don't see any place where you defined the tile size so I assumed this would be done in a header file with constants in it or it would be gained from a config file later on. Am I right or did I miss something?

So far, this tutorial is great, but I still can't get my images to load so I'm not sure what I'm doing wrong. I've checked everything about 10 times now.

Add the Tile to it and it should work - I think alot has been missed out on this tutorial, because I'm having issues with several things also. I've cleared most stuff up except I seem to be having issues with:

You have this function. Also I don't see any place where you defined the tile size so I assumed this would be done in a header file with constants in it or it would be gained from a config file later on. Am I right or did I miss something?

So far, this tutorial is great, but I still can't get my images to load so I'm not sure what I'm doing wrong. I've checked everything about 10 times now.

Add the Tile to it and it should work - I think alot has been missed out on this tutorial, because I'm having issues with several things also. I've cleared most stuff up except I seem to be having issues with:

Could anybody explain me about the formula in update method in Camera class ? I can't imagine what's going on in the code.

The algorithm is like this...

(You can imagine that first 2 lines are just variable initializations).

First, it defines the distance between the actual position and the target position (which is calculated with the formula SqrRoot(x^2+y^2),the good-old hypotenuse. x being difference between actual x and target x, and similarly, y being actualY - targetY).

Basically, that distance is used to move the camera by 1/60th of the total distance on each frame.

//We set our velocity to move 1/60th of the distance to the target.
//60 is arbitrary, I picked it because I intend to run this function once every 60th of a second.
//We also allow the user to change the camera speed via the speed member.
v = (d*speed) / 60;
//Keep v above 1 pixel per update, otherwise it may never get to the target.
//v is an absolute value thanks to the squaring of x and y earlier.
if(v < 1.0f)
v = 1.0f;
//Similar triangles to get vx and vy
vx = x * (v/d);
vy = y * (v/d);
//The update camera's position and we're done
position.x += vx;
position.y += vy;

Though I've observed something...

If we have
v = (d*speed) / 60

And then we do
vx = x* (v/d)

...
vx = x * (d*speed/60)/d
vx = x * speed/60

...So is d necessary? I actually removed all d references (and the check for v being > than 1.0f), and, as long as I can see, it works the same.

the semicolons after bounds.height and bounds.width throw several compiling errors for me, and the semicolons are underlined with the error "expected a ')'".
Here's all the errors this bit is throwing: