Checking tile collision with SDL2

This is another question that adds to: http://www.cplusplus.com/forum/general/257650/

I've found out how I can detect a spesific tile out from a map based on an 2D array:

1
2
3
4
5
6
int map[4][4] = {
{0, 0, 1, 1},
{0, 0, 1, 1},
{0, 0, 1, 1},
{0, 0, 1, 1},
}


Through a function that calculates the tile the player is located at, and then checks if that tile is equal to 0. Because in this case, 0 will symbolize a path the player cannot walk on.

1
2
3
4
5
6
7
8
9
10
void checkTiles(const SDL_Rect player, int map[4][4]) {
        // Calculate the tile position of the player by dividing position on tile size:
	int tileX = player.x / 32; int tileY = player.y / 32; 

	if (map[tileY][tileX] == 0) {
		std::cout << "Collision" << std::endl;
                // Do something more...
	}

}


Which works. But, the way this works isn't good enough. Because it will only detect the left-top corner of the player. E.g.:

https://i.gyazo.com/f22cef0f8e8e12253a1f248f71d4669c.png

The image above displays the player walking into (1, 1) which is a tile marked as 0 in the array. With other words, a tile the player shouldn't be able to walk on. But, the way this is registered with the function above is through the red dot in the top-left corner of the player.

Furthermore, that is not how I want the collision to happen. I want to be able to register the whole body (height and width) of the player to cause a collision. Not a single point in the top-left corner.

Any help/thoughts on how I could make this happen?
Last edited on
So, I take it you'd agree that in that image, the player is colliding with 6 tiles at one time.

The division by 32 in your code hints that the coordinate system of the tiles doesn't match the coordinate system of the player.

Further, the map has no concept of width and height.

Naturally I call into question why one would use a C based engine in a C++ program, but I've seen more inexplicable things. So be it.

The real issue is how to tease out a width and height for each cell, and stop shrinking the player's coordinate scale to fit the map, but expand the map to fit the player, including the concept of the tile's width and height.

If you don't do that, the integer math is going to drive you nuts.

So, let's say map tiles are 32 x 32 (you pick what you like).

This means the tile at 0,0 starts at 0, 0 in coordinate space, an proceeds to 31, 31. The tile at 0, 1 starts at 32, 0 and proceeds to 63, 31.

Further, the player has a width and height. From what little I can glean from the scant information on SDL, those are members of SDL_Rect. If that holds true, then it may be convenient to consider tiles the same way, as a point for the upper left corner of the tile, plus a width and height (probably fixed). This is opposed to, say, an upper left and lower right corner given by two points (which is another common means of specifying a rectangular region).

You now have tools to deal with your question. Tile 1, 1 has an upper left corner of 32, 32, with a width and height of 32, it proceeds to 63, 63.

Since I can't tell the actual player position from your post, let's say the player's upper left corner is at 62, 62 - a fair guess from your diagram. The test for that point within any tile (in this case tile 1) is rather trivial.

So, let's consider the rest. From that player point (62, 62), the player's right top corner is probably at something around ( 93, 62 ). The diagram shows it is in tile (2, 1), but the computer can't see that as we do. It must test each intersection potential for every tile.

Tile (2,1) begins at ( 64, 32 ). The for corners are UL ( 64, 32 ), UR ( 95, 32 ), LL( 64, 63 ), LR( 95, 63 ).

The player's UR is at ( 93, 62 ). The "x range" of the tile at ( 2, 1 ) is 64 to 95, and since the player's UR "x" is 93, it is between them. It's a candidate. The tile's "y range" is 32 to 63, and the player's UR is 62, so it is also between them. Since it is between both, the UR is in tile 2, 1

You can test all four corners of the player this way to determine which tiles each of the 4 corners occupies, and by an extension of logic, know what tiles the player straddles (I'm thinking about tiles ( 1, 2 ) and( 2, 2 )).

So, there's an idea. There are many variations.

I'm sure you want to continue with the division by 32, but truncation will likely bug you - you might work that out, still using the "four corners" approach I just outlined. Maybe cast that division into floats and round?

Lots of ways to do this, including a more "physics" oriented approach that gets a bit wild by comparison.



Last edited on
Thank you for the guidance @Niccolo. I've used the last day to think over my whole problem. At first, I believed it was better to just restart the tile/map concept I had going on.

But, I figured I'd just see how far this setup will take me. Because, I am now detecting collisions on all four sides of the player this way:

1
2
3
4
5
void checkTiles(const SDL_Rect player, int map[20][25]) {
		if (map[player.y / 32][player.x / 32] == 0 || map[(player.y) / 32][(player.x + player.w) / 32] == 0 || map[(player.y + player.h) / 32][(player.x) / 32] == 0 || map[(player.y + player.h) / 32][(player.x + player.w) / 32] == 0) {
			std::cout << "Collision" << std::endl;
		}
	}


Is these calculations going to be problematic you think?

This way, I can could easily just say that tile X (in this case 0) defined out from the map[20][25] tiles will cause a collision. And from that I could work out a move() function for the player I guess? Ergo, that the move() function will determine if the next movie is acceptable or not. Maybe by turning the checkTiles function into a bool instead?

Furthermore, why would using SDL2 be an issue with C++? I was recommended this library when googling for game development with C++. Not wanting to learn something such as Unreal Engine as of yet. Because I want to go through the fundementals of game development for 2D as a start, before moving onto such as game engines.
Last edited on
What works, works. I expect minor issues with integer division, but if you see that (where something may be about 1 or 2 pixels off), you can probably invent adjustments (rounding, for example, from floating point casts).

The theory is reasonable, though - you're assuming each tile is 32 x 32, it seems, and the layer can move 32 units from one tile to the next. Whatever the rendered size of a tile, that may end up being scaled, and if it looks ok, it is ok. It may not translate into a wide range of resolutions, but that's a different thing to consider as you move upwards in skill.

If the image you posted is genuine illustrative, the player is large enough to cover 3 rows. If that was merely a drawing anomaly then there's no issue to solve. If that is correct, though, you may need to consider that if a tile exists between the tiles where the UL and LL (or UR and LR) collide, then that "between" tile is also a colliding tile, I would assume.

My point about SDL2 is that it is an old style, and a bit too simple. Maybe it's fine for study, I'm not all that sure. I have to think back to the early 80's and late 70's to remember my own study of this kind of material. After decades, I just "do" things, hardly without really having to think about it.

Unreal is a bit much if you're not already seriously steeped in C++. Of course, it is built so that artist/indies can create games without even programming, but that means using the graphical scripting tools (Blueprints I think). I haven't used Unreal in a while. It aims toward higher end graphic results, which are really good, but I intend to target Android and iOS. Unreal isn't really good for Android because one must limit the consumer base to higher end Android devices (OpenGL ES 3.2, maybe 3.1 if you can squeeze it). Unity, on the other hand, has much better "light" engine support targeting most Android devices, with options to move upward to high end graphic results. My main complaint with Unity is C# scripting, which I ignore. Unity does support (barely) "native" plugins, written in C++. You have to already understand how to write C++ to be accessible from C# (and to call C# methods from within C++), but it can be done. I've done it to deploy the PhysX engine from source, so I have the entire PhysX feature set, and whatever the latest version they release which Unity does not yet include. At the moment, Unity is using the "current" (or very recent) version of PhysX, but they don't expose the parts I need (articulations) - or at least didn't. I haven't checked last month's release, nor do I bother with the betas.

Unity otherwise, however, is a really good balance, suitable for learning more modern game development. The days of using a source code engine base no longer make much sense except for really simple games (the kind that don't really grab attention in the market).

I've used various engines, many are more rendering than game engines, for a wide variety of purposes. I recognize the interest and direction of your study, and it is certainly valid. If your purpose is to advance to the point you could make a game engine, you're probably headed somewhere in the right direction. If you're really just interested in making games, however, I'm not convinced. You're not really learning what is applicable to modern game development methods. The "under the hood" and "low level" work is so detailed, so deep and wide, that no one can compete making games starting from code. In modern terms, one must start with artwork, mock ups, and an extant engine. Just keeping up with all of the rendering API's is exhausting, if the purpose is to make games.

If you're about half way, I wouldn't suggest stopping. Make it through to something. I'm not sure what the game is in your case, but my "first" on the PC was a Pac-Man clone back in the early 80's. One of my earlier works was on an 8 bit computer, popular just after the first Apple II, based on the final "death star battle" scene from the first star wars movie, which was still in theaters (though it was the $1 cinema where films that were out the previous year still ran).

When you are finished, though, I'd highly recommend that if you're focused on making games, you should consider running through the Unity tutorials to see if you are "ready for" and like the direction.
Topic archived. No new replies allowed.