SDL Maps
SDL Tutorials March 15th, 2008As I stated in the last lesson, we’re going to be looking at making a Map class that will be tile based. In addition to the maps, we’ll be creating Areas that enhouse many Maps. While we could create one giant map, it’s far easier to manage many smaller maps, and also opens the possibility of tiling maps as well. By the way, head on over to the SDL Image tutorial if you haven’t already done so, we will be making the switch over to SDL Image and stop using SDL_LoadBMP. No more chatter, lets get started.
We’re going to need several files in the beginning, Define.h, CArea.h, CArea.cpp, CMap.h, CMap.cpp, CTile.h, and CTile.cpp. So create these blank files. What we are going to do is have one Area object, this Area object will have many children Map objects in a vector (like the Entities in a vector). Within each of these Map objects, they will have a vector of each individual tile. So basically, we have a bunch of tiles that make up a map, and a bunch of maps make up an area.

Lets start by opening up Define.h. This file is going to hold some constant values, as defines, that will define things like map width and height, screen width and height, and tile size. These are going to be some values that we will be using throughout making our Maps and such. Add the following below to define.h.
#define _DEFINE_H_
#define MAP_WIDTH 40
#define MAP_HEIGHT 40
#define TILE_SIZE 16
#define WWIDTH 640
#define WHEIGHT 480
#endif
We’ll get back to what these values mean later, but WWIDTH and WHEIGHT are the values set in SDL_SetVideoMode. So open up CApp_Init and change that function call to the following:
return false;
}
Simple enough. Next, open up CTile.h. This class is going to define a single tile on a map. In gaming terms, a tile is basically a single square graphic that we draw to the screen. Remember the animation tutorial, each frame of Yoshi could be thought of as a tile. So when I say we have a map made up of many tiles, we are taking these tiles and repeating them in a grid sequence.
And since we have a single graphic containg all of our tiles, we only have to load one graphic, and not several for each tile. Each tile then needs some properties. The most obvious is which graphical tile to use. Take a look at an example tileset below:

You’ll notice that the very top left has an ID of 0, and going to the left it increments in 1s. This is called the Tile ID. By using the ID, and the size of each tile (TILE_SIZE), we can know which tile to draw to the screen. The next important thing is TypeID. This determines what type of tile it is. Some examples might be, invisible (don’t draw a tile), block (like a wall), or ground (player can walk on it). You can define whatever TypeIDs you want, but these are the most basic (other examples might be water, fire, ice, etc…). That’s basically it, this Tile class only has two members (for now, later on it will contain information for animated tiles). So lets push this class together inside of CTile.h:
#define _CTILE_H_
enum {
TILE_TYPE_NONE = 0,
TILE_TYPE_NORMAL,
TILE_TYPE_BLOCK
};
class CTile {
public:
int TileID;
int TypeID;
public:
CTile();
};
#endif
Notice the enum used. This lets us assign or check the TypeID, and know what it is at the same time. So if I did TypeID == TILE_TYPE_BLOCK, I would be able to notice in my code that I am checking for a block type of tile. TypeID == 2 isn’t as easy to interpret. If you never used enums, think of them like const variables. The value never changes. Also, the starting value defines the rest, notice I have = 0 on TILE_TYPE_NONE. From there the rest of the variables would automatically be assigned values in increments of 1.
Now, lets open up CTile.cpp and finish the code:
CTile::CTile() {
TileID = 0;
TypeID = TILE_TYPE_NONE;
}
Pretty straight forward. Next, lets look at making some maps. The first thing we need to consider is that our maps will be text files. So we need to come up with a file format, that way we can easily edit our maps outside of our code. And possibly later you could create a map editor.
Each map is going to have a width and height, defining the number of tiles. So a map of 10×10, would have 100 tiles in it. We are going to make all of our maps the same width and height, so we don’t have to define that within the map files (MAP_WIDTH and MAP_HEIGHT). The part that we do need to add though is the TileID and TypeID for each individual tile. We are going to use the file format that I came up with, as it is relatively simple. Take a look at the 5×5 map example below:
0:0 0:0 0:0 0:0 0:0
1:0 1:0 1:0 0:0 0:0
1:0 1:0 1:0 0:0 0:0
1:0 1:0 1:0 0:0 0:0
1:0 1:0 1:0 0:0 0:0
Each tile within the file would consist of 0:0, effectively being the TileID:TypeID. A space would be the deliminator between the tiles. A concept rendering if this map may look like this:

For this tutorial we will be using 40×40 maps, since that is a pretty decent size. And instead of printing an example out for you to copy, click on this link here:
First create a folder in the same directory as your exe called maps. This folder is where all your maps will be. Save that map as 1.map. Also, make another folder called tilesets in the same directory as your exe, and save the tileset above as 1.png.
Now that we have a file format for our maps, lets start designing the class that will render this thing. Open up CMap.h:
#define _CMAP_H_
#include <SDL.h>
#include <vector>
#include "CTile.h"
#include "CSurface.h"
class CMap {
public:
SDL_Surface* Surf_Tileset;
private:
std::vector<CTile> TileList;
public:
CMap();
public:
bool OnLoad(char* File);
void OnRender(SDL_Surface* Surf_Display, int MapX, int MapY);
};
#endif
A few of the basic things are here, OnLoad and OnRender. OnLoad does what you expect, loads a map from a file, and populates the TileList. The OnRender also does what you expect, properly puts each tile on the screen and draws them using the Surf_Tileset. Lets define what these functions do, now open up CMap.cpp:
CMap::CMap() {
Surf_Tileset = NULL;
}
bool CMap::OnLoad(char* File) {
TileList.clear();
FILE* FileHandle = fopen(File, "r");
if(FileHandle == NULL) {
return false;
}
for(int Y = 0;Y < MAP_HEIGHT;Y++) {
for(int X = 0;X < MAP_WIDTH;X++) {
CTile tempTile;
fscanf(FileHandle, "%d:%d ", &tempTile.TileID, &tempTile.TypeID);
TileList.push_back(tempTile);
}
fscanf(FileHandle, "\n");
}
fclose(FileHandle);
return true;
}
void CMap::OnRender(SDL_Surface* Surf_Display, int MapX, int MapY) {
if(Surf_Tileset == NULL) return;
int TilesetWidth = Surf_Tileset->w / TILE_SIZE;
int TilesetHeight = Surf_Tileset->h / TILE_SIZE;
int ID = 0;
for(int Y = 0;Y < MAP_HEIGHT;Y++) {
for(int X = 0;X < MAP_WIDTH;X++) {
if(TileList[ID].TypeID == TILE_TYPE_NONE) {
ID++;
continue;
}
int tX = MapX + (X * TILE_SIZE);
int tY = MapY + (Y * TILE_SIZE);
int TilesetX = (TileList[ID].TileID % TilesetWidth) * TILE_SIZE;
int TilesetY = (TileList[ID].TileID / TilesetWidth) * TILE_SIZE;
CSurface::OnDraw(Surf_Display, Surf_Tileset, tX, tY, TilesetX, TilesetY, TILE_SIZE, TILE_SIZE);
ID++;
}
}
}
Also, int TilesetY = (TileList[ID].TileID / TilesetHeight) * TILE_SIZE; should have been int TilesetY = (TileList[ID].TileID / TilesetWidth) * TILE_SIZE; (note the TilesetWidth). Thanks PAW!
Lets start at the top. The constructor sets the Tileset to NULL, obviously. Next we have the OnLoad function. First, we are clearing out any old tiles, that way if we load twice, it won’t have double the amount of tiles, effectively loading a new map. We then open up a FileHandle, and try to open the requested map file. Now, we go through the map file and grab each tile. This is accomplished by using the two loops. The outer loop is the Y axis loop, going from the top row to the bottom row of the map file. The inner loop is the X axis loop, going from the left most tile, to the right most tile. Pay attention to how this loop works, because it is also used below in the OnRender function. It basically goes from the top left tile, to the bottom right tile, 1 tile at a time. Inside of those loops we create a temporary tile, and load the file information into it. We then push that into our TileList, effectively saving the tile. We close the filehandle, and we are done.
Next, we have the function to render a map. Notice the MapX and MapY arguments. These tell use where to render this map on the screen. This is useful later on for moving maps around. First in the function we check for a valid tileset, because we are going to access this tileset directly and don’t want to cause a crash. We then grab the TilesetWidth and TilesetHeight in Tiles. This is important, because we need to know how many tiles a tileset contains, not its actual width and height. That way we can match up a TileID to a tileset. So, a Tileset with a Width and Height, in tiles, of 2×2, would have 4 tiles on it, but in reality it would be 32×32 pixels. So, a TileID of 0 would match the first tile, a TileID of 1 would be the next, and so on. TileIDs repeat on the next row, from left to right.
Okay, next we have that same loop again, going through each tile (Please note that these X and Y coordinates here in the loop are also in number of tiles, they aren’t actual pixels). This time, however, we have an ID variable. This ID is incremented by one each loop, and will allow us to grab each tile in the map. So, first we check to see if this Tile should even be drawn, by checking the TypeID. If it is TILE_TYPE_NONE, we skip over it with continue. After that we figure out where to draw this tile on the screen. This is done by taking the MapX and MapY (effectively offset coordinates, because they offset a map from 0, 0 to somewhere, which makes it seem like a map is moving), and taking the X and Y coordinates in the loop. We have to convert these X and Y coordinates back to pixel coordinates, which is done by multiplying it by the size of a tile.
After that, we do something with the Tileset. What we are doing is calculating where on the Tileset to grab the appropriate tile. This is by grabing the TileID of the tile first, and then converting that to a Tile coordinate. A little bit of explanation here. We have our 2×2 tileset, and a TileID of 1. Figuring out X, we would get 1 % 2, which would be 1 still. We when multiply that by the TILE_SIZE, and get 16. That is the correct X coordinate for the Tile. Same with the Y, we put 1 / 2, which is 0.5. Since this an integer operation, the .5 is automatically dropped. Thus we are left with 0. Which is also the correct row. Now, say we had a TileID of 2. 2 % 2 = 0, and 2 / 2 = 1. See how the X repeats in a pattern? 0, 1, 0, 1… And notice how Y increases every time it goes past the Tileset Width? 0, 0, 1, 1. I hope this is clear, as it is somewhat hard to explain.
Next, we actually draw the tile to the screen using the coordinates we just calculated, and then increase the ID to go to the next tile. A little side note here, we could, for the sake of speed, create an OnRender_Cache function that would perform this same operation, but would draw to a Surface defined in the CMap class. Something like SDL_Surface* Surf_Map. Then, the OnRender function would render the Surf_Map only, and not perform any operations. But also take note that that method does not necessarely work later on when we want to animate tiles.
Okay, cool! I know that is quite a bit to take in at once, but don’t fret! It’s really not too bad once you get the hang of it. I want to say that right now we could create Map objects and render maps just fine. This would be ideal for games like Mario and Megaman, as they are just one big map. But for games like Zelda and Metroid, it won’t work too well. That is where Areas come in. Just like maps having file formats, each area will have its own file and file format. Each area is going to have a tileset to load, the size of the area, and the maps that are to be loaded in each area. Here is the area we are going to be using below:
./tilesets/1.png
3
./maps/1.map ./maps/1.map ./maps/1.map
./maps/1.map ./maps/1.map ./maps/1.map
./maps/1.map ./maps/1.map ./maps/1.map
Save this into a file called 1.area, and save it in your maps directory. Just like maps, this area will tile maps. I won’t get into detail because I think you all have the point by now.
Open up CArea.h and lets begin:
#define _CAREA_H_
#include "CMap.h"
class CArea {
public:
static CArea AreaControl;
public:
std::vector<CMap> MapList;
private:
int AreaSize;
SDL_Surface* Surf_Tileset;
public:
CArea();
bool OnLoad(char* File);
void OnRender(SDL_Surface* Surf_Display, int CameraX, int CameraY);
void OnCleanup();
};
#endif
This class is going to similar to the Map class in some ways, but different in others. Similarly, we have MapList that will hold our maps, just like the Map class had a list of tiles. Also, as have a Load function and Render function. Now the differences, we have a static AreaControl, much like Entities have a static control. This will allow us to manipulate an Area from any class by using this object. Next, we have the AreaSize which is the number of maps. We are going to assume that areas will always be square, so an AreaSize of 3, would be a 3×3 area. If you wanted to, and I don’t think it’s necessary, you would have AreaWidth and AreaHeight. Next, we have a surface for the Tileset. You probably noticed that within the CMap class we never actually loaded a tileset. That’s because the Area is going to do it for us, and then pass that pointer to the CMap class. That way each map doesn’t load a tileset for itself, but effectively all maps share the same tileset. Again, if you wanted each Map to have its own tileset you can easily modify the class to do so.
Okay, now open up the CArea.cpp class:
CArea CArea::AreaControl;
CArea::CArea() {
AreaSize = 0;
}
bool CArea::OnLoad(char* File) {
MapList.clear();
FILE* FileHandle = fopen(File, "r");
if(FileHandle == NULL) {
return false;
}
char TilesetFile[255];
fscanf(FileHandle, "%s\n", TilesetFile);
if((Surf_Tileset = CSurface::OnLoad(TilesetFile)) == false) {
fclose(FileHandle);
return false;
}
fscanf(FileHandle, "%d\n", &AreaSize);
for(int X = 0;X < AreaSize;X++) {
for(int Y = 0;Y < AreaSize;Y++) {
char MapFile[255];
fscanf(FileHandle, "%s ", MapFile);
CMap tempMap;
if(tempMap.OnLoad(MapFile) == false) {
fclose(FileHandle);
return false;
}
tempMap.Surf_Tileset = Surf_Tileset;
MapList.push_back(tempMap);
}
fscanf(FileHandle, "\n");
}
fclose(FileHandle);
return true;
}
void CArea::OnRender(SDL_Surface* Surf_Display, int CameraX, int CameraY) {
int MapWidth = MAP_WIDTH * TILE_SIZE;
int MapHeight = MAP_HEIGHT * TILE_SIZE;
int FirstID = -CameraX / MapWidth;
FirstID = FirstID + ((-CameraY / MapHeight) * AreaSize);
for(int i = 0;i < 4;i++) {
int ID = FirstID + ((i / 2) * AreaSize) + (i % 2);
if(ID < 0 || ID >= MapList.size()) continue;
int X = ((ID % AreaSize) * MapWidth) + CameraX;
int Y = ((ID / AreaSize) * MapHeight) + CameraY;
MapList[ID].OnRender(Surf_Display, X, Y);
}
}
void CArea::OnCleanup() {
if(Surf_Tileset) {
SDL_FreeSurface(Surf_Tileset);
}
MapList.clear();
}
Quickly, going from the top, we declare the static object, and then set the AreaSize to 0. Then we have our Load function. It works just like the Load function within CMap, except there are a few differences. We have to load tileset first. We try to load this tileset into the surface, and if it fails return false. We then load the size of the Area. Okay, after that we have two loops, just like maps, that will go through and grab each map filename. It will then create a map object, load the map, set the tileset to be used, and then push it into the list. Pretty simply and straight forward.
Next, we have the Render function. We calculate the actual Map width and height, in pixels, first. This will let us find the first map to render. Some explanation first of what I am trying to do. Since an area can be of any size, like 100×100 maps, we don’t want to go through all the trouble and render every single map. We only want to render the maps that are visible in the screen area. For our size of a screen, 640×480, only a possible 4 maps can be visible at one time (like standing at the corner of 4 maps). So what we have to do is calculate the first Map ID to grab. This is going to the first map to render. From the first ID, we know the next 3 maps to render. The one to the right of the first map, the one at the bottom of the first map, and the one at the bottom right of the first map. How is that accomplished? Look at the image below:

We have a guy, the circle, in the very center of the screen, represented by the red square. The other squares are each Map, and we have a Camera position of -700, -700. Why negative? Think about it, the screen itself never really moves, everything else does. So, for something to move up, it must increase its Y in the negative direction. Same with the X coordinate. So, to get to the 4th map, we have to move the area in the negative direction. Now, notice the grayed out maps, these are maps not visible within the players view, so they shouldn’t be rendered. To figure out the First ID, which is 4 in this case, we need to use the specified Camera coordinates. We translate those Camera coordinates into Map coordinates. So, taking -(-700) / 640 (which is 40 * 16, remember the MapWidth calculation done above) we get 1 (dropping the decimal because its an integer operation). This is the X coordinate in Maps, but we aren’t done. We then calculate the Y coordinate in Maps the same way -(-700) / 640, but we multiply that by the AreaSize. That’s because we are grabbing the ID. So, it would become 1 * 3, which is 3, and adding that to the first calculation of 1, we get 4. And what do you know, the First ID on the map!
Okay, so we go through each of the four maps now. Since I did a regular loop of i < 4, we need to figure out how to add that to the First ID, to actually figure out each of the four Map IDs. This is done by taking the First ID as an offset first. We then take i, our position in the loop, divide by two and multiply by the area size. What does this do? Much like the Map class, it creates a pattern, 0, 0, 1, 1. Same with the last operation i % 2, it creates a pattern of 0, 1, 0, 1. This then gives us the correct pattern of, 4, 5, 7, 8. Which are the correct map to render.
We do a little check to make sure the ID is good, since the ID may not exist. And now the last calculation (yes, I know, a lot of complex calculations). It works just like the way we calculated which tile to grab on the tileset. It's turning an ID into actual pixel coordinates, and then offsetting those coordinates by the camera (making it seem like it moved). We then finally render the map, passing the coordinates of where to draw it.
Lastly, we have our cleanup function that frees the surface and clears the maps.
What a load! I hope all of the various calculations don't get you confused. There are really only two basic things we are trying to do, turn pixel coordinates into grid based coordinates. Such as with tiles, and with the maps. The other thing was turning those grid based coordinates back and forth into IDs.
Okay, we are not quite done yet, still a little bit to do (now you see why this tutorial took so long to complete!). You may have noticed that I called the arguments on the Render function on the CArea class CameraX and CameraY. We are going to need to make a camera class that defines the viewing area. This is what we are going to manipulate to move around on a map!
So create two new files, CCamera.cpp and CCamera.h. Open up the header file first:
#define _CCAMERA_H_
#include <SDL.h>
#include "Define.h"
enum {
TARGET_MODE_NORMAL = 0,
TARGET_MODE_CENTER
};
class CCamera {
public:
static CCamera CameraControl;
private:
int X;
int Y;
int* TargetX;
int* TargetY;
public:
int TargetMode;
public:
CCamera();
public:
void OnMove(int MoveX, int MoveY);
public:
int GetX();
int GetY();
public:
void SetPos(int X, int Y);
void SetTarget(int* X, int* Y);
};
#endif
First, we have a control member object, just like area. Then we have the coordinates of where the camera is. An extra thing I threw in, was the ability to target something. For example, in a Megaman game the camera would target Megaman himself. That way, when Megaman moves the camera would automatically update. So we have two pointers for X and Y coordinates. If these are null, the camera will automatically revert to the cameras position. Next, we have a target mode, which, for now, is either normal (the camera will position to the top left of the target) or center (will center the camera to the target). Pretty simply I think.
We then have a few functions, the first is the OnMove, which will increase the X and Y of the camera by MoveX and MoveY. So OnMove(0, -1) would move the camera to the left one pixel. We then have Get functions for the coordinates, and the ability to set the coordinates and set a target.
Okay, now open up CCamera.cpp:
CCamera CCamera::CameraControl;
CCamera::CCamera() {
X = Y = 0;
TargetX = TargetY = NULL;
TargetMode = TARGET_MODE_NORMAL;
}
void CCamera::OnMove(int MoveX, int MoveY) {
X += MoveX;
Y += MoveY;
}
int CCamera::GetX() {
if(TargetX != NULL) {
if(TargetMode == TARGET_MODE_CENTER) {
return *TargetX - (WWIDTH / 2);
}
return *TargetX;
}
return X;
}
int CCamera::GetY() {
if(TargetY != NULL) {
if(TargetMode == TARGET_MODE_CENTER) {
return *TargetY - (WHEIGHT / 2);
}
return *TargetY;
}
return Y;
}
void CCamera::SetPos(int X, int Y) {
this->X = X;
this->Y = Y;
}
void CCamera::SetTarget(int* X, int* Y) {
TargetX = X;
TargetY = Y;
}
From top to bottom, like usual, we have are static member first. We then have the constructor defaulting some variables. The OnMove function will increase the X and Y, like I said before. We then have GetX. It will check to see if we have a valid target, and if so return the targets coordinates as the camera coordinates, otherwise return the camera x. For centering mode, we take the screen width and divide by two to find the center of the screen, and then subtract it from the target coordinates. This will center the camera to the target. We then have the SetPos and SetTarget functions, which are self-explanatory.
So lets put all this junk together! Open up CApp.h and modify it to include the new header files:
#include "CArea.h"
#include "CCamera.h"
Also, add a new function prototype:
We are going to checking that event for move our map around with the keyboard. So, open up CApp_OnEvent.cpp and add the function:
switch(sym) {
case SDLK_UP: CCamera::CameraControl.OnMove( 0, 5); break;
case SDLK_DOWN: CCamera::CameraControl.OnMove( 0, -5); break;
case SDLK_LEFT: CCamera::CameraControl.OnMove( 5, 0); break;
case SDLK_RIGHT: CCamera::CameraControl.OnMove(-5, 0); break;
default: {
}
}
}
We check the SDL keys, and according to the key move the camera around. Next, open up CApp_OnCleanup.cpp and add the cleanup function for the Area:
Open up CApp_OnRender.cpp and add the Render call too:
Notice that we are passing the Camera coordinates to the OnRender. And lastly, open up CApp_OnInit.cpp:
return false;
}
SDL_EnableKeyRepeat(1, SDL_DEFAULT_REPEAT_INTERVAL / 3);
SDL_EnableKeyRepeat call sets the keyboard repeat count. So if we hold down a key it will keep calling the event above. And we are done! Compile the code and try it out. I hope it all works as expected, this was a very lengthy tutorial. Please check out the tutorial files below if you are having a bit of trouble. And please let me know if for some reason I left some important code out.
SDL Maps - Tutorial Files:
Win32: Zip, Rar
Linux: Tar (Thanks Gaten), Binary (Thanks Thomas)














March 24th, 2008 at 11:17 am
Not sure if this is a hard tutorial or what, or that it just takes a while to understand. Kind of curious about the lack of comments.
March 25th, 2008 at 5:21 pm
Hi Tim,
Been wanting to post a comment but was waiting till I’d had time to go through the tutorial properly.
March 25th, 2008 at 11:23 pm
For me it was a deviation from the last couple tutorials (Animation and Entities), and as I’m trying to combine your lessons into something complete, this one kinda threw me off (it’s huge and I’m having trouble figuring out how to incorportate it into my current code).
I’m personally waiting for entity collision handling.
March 26th, 2008 at 6:25 am
Ahh yes, it is quiet big. I’m sure you’ll all get a handle of it though. For the next game within this series though it’s necessary step. Don’t worry about collision detection, that is the next thing coming up!
March 28th, 2008 at 4:41 pm
I found your blog some days ago and i really like it, the tutorials are easy to follow and they are very useful to practice some more advanced object oriented stuff beside SDL. In the textbooks the examples are usually very simple so it’s nice to see them in work. I also like that the tutorials are built on each other I think it’s more interesting this way.
I think i’ve found a bug, in the CMap.cpp during the rendering in:
if(TileList[ID].TypeID == TILE_TYPE_NONE) continue;
we should also increase ID to continue rendering the other tiles
March 29th, 2008 at 6:27 am
Thanks for the compliments!
Yes, you indeed found a bug (doh). I fixed it, and changed the Win32 package. Thanks for letting me know!
April 5th, 2008 at 6:40 pm
Your tutorials suck. Good day.
April 6th, 2008 at 12:34 pm
—Very good tutorial—
April 7th, 2008 at 7:02 am
Sorry you don’t like them Joseph. Feel free to leave.
P.S.
Sorry, I had to take the URL off; it’s a little inappropriate.
April 9th, 2008 at 10:32 am
Super stuff!
Is there any reason why this is always returning NULL for me:
if((Surf_Tileset = CSurface::OnLoad(TilesetFile)) == false) {
fclose(FileHandle);
return false;
}
SDL_image is fine. ALL the #includes are in. Commenting out the ‘return false;’ above allows the program to run (but obviously with a blank screen!). Substituting TilesetFile for an actual file eg “data/1.png” makes no difference.
CSurface::OnLoad() works fine when called from CApp_OnInit()…. just not from here, ie CArea::OnLoad().
I’ve been right through the downloads, I’m wondering if my Dev-C++ compiler has anything to do with it??
Sorry about this!!
April 9th, 2008 at 10:42 am
Have you tried compiling the project files only? If so, you might want to ensure your SDL_image is in working order (latest build and everything). To test it, try using SDL_LoadBMP instead of IMG_Load in the OnLoad function. If it work, then your SDL_image isn’t working for some reason.
April 9th, 2008 at 11:01 am
I’ve tried that! SDL_LoadBMP wont have it either. I’ve tried #including CSurface inside CArea.h, nothing. I’ve been over and over it today, and my eyes are hurting now! I’ll let you know if i come up with anything later!
Thanks Tim.
April 9th, 2008 at 11:04 am
Can you try sending your complete code to my email? That way I have something to look at.
April 13th, 2008 at 4:28 pm
Just wanted to say thank you for your really good tutorials.
They helped me a lot. So I’m looking forward to the next one. (on colision detection?)
April 13th, 2008 at 7:26 pm
You’re welcome! Yes, the next one will include collision detection, along with some other things.
April 14th, 2008 at 5:52 pm
thanks for all the tutorials…they are very usefull and very object oriented! also i am looking forward to the collision detection tutorial
thanks a lot…
April 15th, 2008 at 11:47 am
I tried to design a kind of “player” today, that can move in TILE_SIZE steps across the screen…
The only probleme is, that if i start my camera with TARGET_MODE_CENTER, my (0;0) coordinate isn’t at the top left corner of my area.
i don’t get whats wrong with it…
my player is
Player : public Entity
its render method basically does:
Surface::Draw ( Screen , Entity_Surface , x - Camera::CameraControl.getx() , y - Camera::CameraControl.gety() , anim_state * width , Animation_Control.getCurrentFrame() * height , width , height );
those x and y coordinates are also the Target coordinates of my Camera…
i can’t figuer out, where my mistake is.
April 21st, 2008 at 4:56 am
Hi as usual: awesome tutorial man!
When will the tutorial on collision detection be up? I can“t barely wait, need to have it for my new revolutionary RPG.
April 21st, 2008 at 6:11 pm
hi magnus, i can suggest you to download “Kiazare” that is game you can find in the SDL game section of the site. It’s not a tutorial but reading the code i’have found some useful information also regarding collision detection. Now i’m triyng to face the animations in order to simulate the moviment of my hero
April 23rd, 2008 at 1:12 pm
i cant find where the CEntity::Collides is called,…
doesnt this game check the collision between different Entitys?
for the Map-Colision i already implemented something quite similar to this, so there are no worries^^
April 23rd, 2008 at 1:20 pm
Hi everyone, I’ve been kind of busy lately, but I have been working on the next tutorial. So no worries, it’ll come soon enough. As Francesco mentioned, you can get some clues from some games I have available to download.
Regarding Sebastian’s comment, are you looking at my Kizare code, or where exactly are you getting the Collides function call from?
April 23rd, 2008 at 2:21 pm
yes sebastian. also i haven’t foud where CEntity::Collides is called nor where CEntity:OnMove (that impelements entity to map collisions) call is. I think this version of the game doesn’t implement entity to entity collision, but the function is defined, and it’s working, i have tryed it!(maybe there’s a little mistake: “X + Height” i think would be “Y + Height”, but i’m not sure :))
i’have called this function on my hero giving as parameters the attributes of the other entityes (using a loop)
the CEntity:OnMove function is called somewhere but we can’t found where i think because of the lua stuff. i think it’s a sort of script or something similar.
The only problem i left is to understend what is the meaning of these Entity’s attributes:
int Col_X;
int Col_Y;
int Col_Width;
int Col_Height;
they are about collision calcolation but i can’t understand very well what they precisely are, and what value to set. Maybe Tim could help

sorry for my English
bye
April 23rd, 2008 at 5:01 pm
yes, im talking of the kizare game,…
i think of the 1.0.5 version, so of the latest release.
I can imagine to do this in a loop for all entities, but what to do, if you loaded an area , lets say with 100×100 tiles, and some entity at every 5th tile ( would be 100*100/5=2000 entities ), wouldn’t it be too much work to check all of them? ( I know, thats not a probleme for now, but i think if there’s a reasonable idea for a game, tha maps will grow really fast, and so the number of tiles and entities)
could it work better, if you just get the important x values, sort the vector of tiles( in a new function that could be handled by the area) and just check those.
or is there a fast way to grab a tile just by its coordinates ( i don’t use pixel movements, just move from one tile to the other ;))
if anyone can imagine a usable idea how to implement this, i would be very glad.
@Tim again: I’m happy to hear this. maybe this tutorial contains a solution for all of our problemes
April 24th, 2008 at 7:27 am
Yes, I have not implemented Entity to Entity collision in Kizare yet, so it’s missing.
And yes, the script is handling calling the movement. Look in CLua_Entity.cpp, and look for Lua_Entity_Move. The Col_* variables are for offsetting for collision. Though I might have a sprite of 32×32, perhaps I don’t the sprite to collide with a wall until it actually looks like it’s hitting his face. So I can offset the width and height by a certain amount to perform a more exact collision, without messing with rendering.
Regarding Tiles, no that shouldn’t be problem. Within this tutorial, and Kizare, I’ve implemented a sort of 2D quad-tree. Meaning, only maps within the display are rendered. So if I had a thousand maps it wouldn’t matter, as only 4 are rendered at any given time. For entities though, it all depends. If you want all entities to collide with each other, sorry, there is no way to get around checking everyone against each other. Of course though, you can speed things up by only checking the entities for collision that are moving. Or, if the case is that only the player can collide with entities (as most RPGs, and RTSs are), then you would only have to do one check for the player against all entities. Keep in mind that we really want to optimize our condition checks (i.e., checking against 0 is always faster than checking against any other number). Also, perhaps only those entities within the screen should be checked. So, it depends usually on the type of game we are going for. But I cannot really imagine a game with more than 100 entities on the screen at a time (only an RTS, in which RTS’s don’t have entity to entity collision at all).
I experimented a bit with the 1000s of entities thing. Currently, I have a game getting around 800-900 FPS, because of OpenGL mostly. I dropped in a 1000 entities with map to entity collision only, and it dropped to 300-400 FPS (because of rendering, had nothing to do with my movement algorithm). So optimization could be made here for rendering, but not too big a deal. I then turned on entity to entity collision as well, and it dropped to unbearable (1-2 FPS). So, I’ll try at optimizing this, but like I said in rare cases will we need something like this for 1000s of entities. Anything else that uses 1000s sprites at a time usually deals with it in a different way, what these tutorials are ending up at is an RPG/Platformer/RTS type of games. (One idea might be to partition the screen for entities, much like the maps. So each entity is assigned a PartitionID for where they are in the world, and you would only check against neighboring partitions).
I’ll upload this new game (which is a Platformer, along the lines of Knytt) to my Games section. It’ll provide a lot more insight, though don’t expect code in the coming tutorial to be the same. It might drastically change.
Sebastian, yes, you can grab a Tile by X and Y coordinates. Take a look at CArea::GetTileID in the new game I am putting up. If you are doing grid based movement, all you would check is the Tile the entity is trying to jump to, in which your work has been dramatically decreased. So, something like (working off the code in the game listed below):
void CEntity::OnMove(int MoveX, int MoveY) {
if(PosValid(X + MoveX, Y + MoveY)) {
X += MoveX;
Y += MoveY;
}
}
//Private
void CEntity::PosValid(int X, int Y) {
CTile* Tile = CArea::AreaControl.GetTile(X * TILE_SIZE, Y * TILE_SIZE);
if(Tile == NULL) {
return true;
}
if(Tile->TypeID == TILE_TYPE_BLOCK) {
return false;
}
return true;
}
That new game I was talking about is here: http://www.sdltutorials.com/downloads/Charlie-Beta1.rar
I hope that helps you guys out.
April 24th, 2008 at 12:07 pm
i now wrote my own entity colision detection:
bool Entity::Entity_Collide ( int newx , int newy )
{
for ( std::vector::iterator iter = EntityList.begin() ;
iter x == newx && (*iter)->y == newy )
{
return true;
}
}
return false;
}
this is a useful one, if you just walk along a grid.
so its just checking if the new x and y coordinates are similar to those of any entity in the entitylist.
If it is, return true ( colided ) else return false.
quite simple i think.
And as its not combined with the map colision, i can decide for every entity weather to check entity_collision or not to check it.
for my projekt this is just a member function of entity ( not virtual ). I think that should be enough for most cases.
I hope this is useful for anybody out there XD
Sorry for my bad english
April 24th, 2008 at 4:51 pm
sorry for doublepost, nut i wanted to add, that i tried this with 3000 Entitys that move every frame randomly around a 80×80 area ( just the movable part^^)
i got a framerate between 50 and 70, so no worries,…
if i change it, that all the entitys just move every 0.5 seconds, i get a framerate of about 400.
( I just use SDL, no GL extension )
so this should be effective enough to let all entitys move in a normal rpg.
thanks for listening
Basti
April 30th, 2008 at 6:13 am
i have continued developing my game and now i have to face a great problem that i can not resolve.
i have started to build my game using as base this map tutorial, and i have also implemented entity to map and
entity to entity collision detection, using the functions i found in kiazare.
because i had some problems with the camera i decided to go on with the game using only the top-left map
of the area (that is a 3×3 area like the map-tutorial). now all here seems to work well; and so i have decided to try to make the game playiable also in the other maps of the area.
i have set “A”"S”"D”"W” keys to move my hero, and the key arrows to move the camera and finally i have changed
my CEntity::OnRender() function from:
CSurface::OnDraw(Surf_Display,
Surf_Entity,
(int)X,
(int)Y,
AnimState * Width,
Anim_Control.GetCurrentFrame() * Height,
Width,
Height);
to:
CSurface::OnDraw(Surf_Display,
Surf_Entity,
(int)X + CCamera::CameraControl.GetX(),
(int)Y + CCamera::CameraControl.GetY(),
AnimState * Width,
Anim_Control.GetCurrentFrame() * Height,
Width,
Height);
this way it seems to work well, because moving the arrow keys my camera followed my hero around the level (i was non able to set the target to let the camera move automatically like in kiazare).
Now the problem i have is that when i go with my hero from the top left map of the area to other maps, i have some map to entity collision detection problems: for example when i go to the map that is under the top left map, the collision detection on the Y axis seems to work well (when i go up and down the player collides in the right way with the map)but the collision detection on the X axes is a little shifted (when i go left or right, it seems like if the blocks where the player had to collide, were placed some pixels to the right of were they had suppose to be)
When i go to the bottom left map of the area the collision detection of the X axes is twice time shifted!
A similar thing append when i go to the map that is on the right of the top left map. This time is the collision detection on the Y axis that seems to be a little shifted, while the collision detection on the X axis seems to work well. Going on the top right map of the area the collision detection on the Y axes is twice time shifted.
i cant understand where the problem is because the map are well renderned on the screen and in the top-left map all seems to work well. Maybe there’s a problem with the OnMove function of my hero, but i have used the one i found in kiazare. Another thing i noticed is that changing
the Col_* values of my hero, the collision detection changes, but the problem persists.
if you have an idea of how this problem can be resolved, please tell me because it’s going to make me crazy
otherwise i’ll wait the collision detection tutorial…maybe it will resolve all my problems…
sorry to bother.
bye
May 2nd, 2008 at 6:30 am
Sebastian, nice to know you got something working for ya!
Francesco, it’s a little hard to tell, but it seems like you have your coordinates offsetted somehow, causing collision to be wrong on the other maps. If you can send me some code, I’ll be happy to look over it. You are right about the Col_* variables, they simple offset the collision. Say you had an entity of 32×32, but his face doesn’t start until 4 pixels into the surface, you would offset it by 4.
I recommend you take a look at Charlie and the Banana, in SDL Games, as that may provide better insight about collision.
May 2nd, 2008 at 5:19 pm
thanks TIM.
ihave solved the problem setting an area with a unique-large 80×80 map. ihave alsto found a way to let the camera follow my player setting this code in the CApp::OnRender function:
CCamera::CameraControl.SetPos((int) -( myPlayer.X - (SCREEN_WIDTH / 2)),(int) -(myPlayer.Y - (SCREEN_HEIGHT / 2)));
i have tryed to use the CCamera::SetTarget() function but it takes to (int *) and i dont know how i could do to pass to the functions two poiters to my hero’s cordinates.
?
any idea
May 2nd, 2008 at 7:45 pm
Francesco,
Are your X and Y coords for your player floats? If they are, I would probably just change the Target variables all to floats as well. And then you could do: CCamera::CameraControl.SetTarget(&myPlayer.X, &myPlayer.Y);
May 13th, 2008 at 9:10 pm
Thanks again Tim. Took me a while and went above my head in a couple parts but was another great tutorial
Did noticed something that may a bug in one part in CMap::OnRender though:
For initializing ‘TilesetY’ shouldn’t we be using ‘TilesetWidth’ instead of ‘TilesetHeight’ to divide.
The thought being:
x: ID % width
y: ID / width
Noticed an issue with rendering when I used a modified version of the tileset you showed us in the “coordinates and blitting” tutorial to create my own little map.
May 16th, 2008 at 11:01 am
Eep, another bug! I hope people realize that as tutorials grow and become more complex, the possibility for bugs also increases. PAW, you are correct, the width should have been used. That’s always the case when transforming coordinates to an ID. Glad you caught on to the concept!
Keep on programming and before you know it all of this will be easy for you.
Thanks again PAW for keeping me on my toes.
June 4th, 2008 at 11:19 pm
Awesome tutorials, Tim :).
I’m following your tutorials and the ones on http://softwarelibre.uca.es/wikijuegos/Portada (spanish only).
I have a problem, I used the yoshi.bmp from the Entity tutorial but when I load it, it shows the bmp without transparency.
I only made some changes in the code but related to the camera move to work on the positive axis which I find more comfortable.
(sorry my bad english)
June 5th, 2008 at 10:55 am
Thanks Kronen! I seem to be generating quite a fan base.
Did you notice at the top of the tutorial we made the switch to SDL Image? If not, that means we are using PNG files from now on which have transparency in them. If you need to get transparency afterwards (like if the image doesn’t have it in it already), then use CSurface::Transparent() to make that pink color transparent. Example: CSurface::Transparent(Surf_Yoshi, 255, 0, 255);
Regarding that Camera code change, it was a mistake on my part having it backwards. It works just fine, but before the next tutorial comes out I’ll need to change it.
June 5th, 2008 at 12:21 pm
I tried with bmp,png and jpg using CSurface::Transparent(Surf_Entity, 255, 0, 255) in the CEntity.OnLoad() function like in your tutorial. No transparency.
The only way I got transparency was converting the bmp to png in photoshop, changing from indexed to RGB color and erasing the background.
June 5th, 2008 at 12:27 pm
Sorry, I forgot to mention if you use SDL_DisplayFormatAlpha, SDL_SetColorKey doesn’t work. You’d need to change it to SDL_DisplayFormat. Again, if you did that, Alpha in PNGs wouldn’t work then.
June 5th, 2008 at 12:45 pm
Yes, I saw the error too, thanks :).
June 20th, 2008 at 5:06 am
My last post was in the wrong place sorry meant to go in the Entities Tutorial. Reposted it there cheers.
June 20th, 2008 at 6:55 am
No problem Gearoid Donnellan. (Repeat deleted).
July 5th, 2008 at 2:55 pm
Havent been here lately but i can see that you’re still doing well. I’ve been working on a game on my spare time (time i allmost doesn’t have) using your code as my “framework”. Its going pretty well so once again i admit that you are doing a very nice job Tim! Good luck with the land and say hello to Eli from me!
July 14th, 2008 at 8:18 am
Nice tutorial!
Not only I learned things about SDL, but also about OOP programming.
Please hurry up with the entity collision tutorial!
I’ve a hard time handling the object collision by passing references to instances. Also, it breaks the encapsulation.
July 14th, 2008 at 8:20 am
Another question, did you use mediator pattern in entity collision?