Topdown RPG slopes?

Started by
17 comments, last by KellerHood 12 years, 9 months ago
A Link to the past had basic tilemap collision, but it also had slopes, as shown in the picture.

link-to-the-past.jpg

I am making a topdown rpg, similar to that.
My current code for checking simple, square tiles, is as follows:


void collide(ENTITY* e, int** tilemap, int map_width, int map_height)
{

/*
x1,y1____x2,y1
| |
| |
| |
x1,y2____x2,y2
*/

int i, x1, x2, y1, y2;


i = e->h > TILE_SIZE ? TILE_SIZE : e->h;

for (;;)
{
/*horizontal movement*/

x1 = (e->x + e->dirx) / TILE_SIZE;
x2 = (e->x + e->dirx + e->w /*- 1*/) / TILE_SIZE;

y1 = (e->y) / TILE_SIZE;
y2 = (e->y + i - 1) / TILE_SIZE;

if (x1 >= 0 && x2 < map_width && y1 >= 0 && y2 < map_height)
{
if (e->dirx > 0)
{
/* Trying to move right */

if ((tilemap[y1][x2] != T_BLANK) || (tilemap[y2][x2]!= T_BLANK))
{
if ((tilemap[y1][x2] == T_BLOCK) || (tilemap[y2][x2] == T_BLOCK))
{
/* Place the player as close to the solid tile as possible */

e->x = x2 * TILE_SIZE;

e->x -= e->w + 1;

e->dirx = 0;
}
if ((tilemap[y1][x2] == T_SLOPE_DR) || (tilemap[y2][x2] == T_SLOPE_DR))
{
/*?*/
}
if ((tilemap[y1][x2] == T_SLOPE_UR) || (tilemap[y2][x2] == T_SLOPE_UR))
{
/*?*/
}
}
}

else if (e->dirx < 0)
{
/* Trying to move left */

if ((tilemap[y1][x1] != T_BLANK) || (tilemap[y2][x1]!=T_BLANK))
{
if((tilemap[y1][x1] == T_BLOCK) || (tilemap[y2][x1] == T_BLOCK))
{
/* Place the player as close to the solid tile as possible */

e->x = (x1 + 1) * TILE_SIZE;

e->dirx = 0;
}
if ((tilemap[y1][x1] == T_SLOPE_DL) || (tilemap[y2][x1] == T_SLOPE_DL))
{
/*?*/
}
if ((tilemap[y1][x1] == T_SLOPE_UL) || (tilemap[y2][x1] == T_SLOPE_UL))
{
/*?*/
}
}
}
}

if (i == e->h)
{
break;
}

i += TILE_SIZE;

if (i > e->h)
{
i = e->h;
}
}

/* Now test the vertical movement */

i = e->w > TILE_SIZE ? TILE_SIZE : e->w;

for (;;)
{

/*vertical movement*/
x1 = (e->x) / TILE_SIZE;
x2 = (e->x + i) / TILE_SIZE;

y1 = (e->y + e->diry) / TILE_SIZE;
y2 = (e->y + e->diry + e->h) / TILE_SIZE;

if (x1 >= 0 && x2 < map_width && y1 >= 0 && y2 < map_height)
{
if (e->diry > 0)
{
/* Trying to move down */

if ((tilemap[y2][x1] != T_BLANK) || (tilemap[y2][x2]!=T_BLANK))
{
if (((tilemap[y2][x1] == T_BLOCK) || (tilemap[y2][x2] == T_BLOCK)))
{
/* Place the player as close to the solid tile as possible */

e->y = y2 * TILE_SIZE;
e->y -= e->h;

e->diry = 0;
}
if ((tilemap[y2][x1] == T_SLOPE_DR) || (tilemap[y2][x2] == T_SLOPE_DR))
{
if (e->dirx == 0)
e->dirx=-e->diry;
}
if ((tilemap[y2][x1] == T_SLOPE_DL) || (tilemap[y2][x2] == T_SLOPE_DL))
{
if (e->dirx == 0)
e->dirx=e->diry;
}

}
}

else if (e->diry < 0)
{
/* Trying to move up */

if ((tilemap[y1][x1] != T_BLANK) || (tilemap[y1][x2]!=T_BLANK))
{
if ((tilemap[y1][x1] == T_BLOCK) || (tilemap[y1][x2] == T_BLOCK))
{
/* Place the player as close to the solid tile as possible */

e->y = (y1 + 1) * TILE_SIZE;

e->diry = 0;
}
if ((tilemap[y1][x1] == T_SLOPE_UR) || (tilemap[y1][x2] == T_SLOPE_UR))
{
/*?*/
}
if ((tilemap[y1][x1] == T_SLOPE_UL) || (tilemap[y1][x2] == T_SLOPE_UL))
{
/*?*/
}
}
}
}

if (i == e->w)
{
break;
}

i += TILE_SIZE;

if (i > e->w)
{
i = e->w;
}
}

/* Now apply the movement */

e->x += e->dirx;
e->y += e->diry;

if (e->x < 0)
{
e->x = 0;
}

else if (e->x + e->w >= map_width * 32)
{
e->x = map_width * 32 - e->w - 1;
}
}



What this does is it takes the coordinates his four corners, and checks to see if there is a tile in front of the coordinates, based on his current speed vector (dirx and diry), and if that is true, then he will basically be 'snapped' to the grid. This is quite robust. The areas with no code and commented with a ? are when he 'collides' (or will collide) with some kind of slope tile, either Down-left, Down-right, Up-left, or Up-right.
I already know whether or not he will be in the bounding box of the slope, but how do I check whether he will collide with the hypotenuse? And how would I go about response, sliding him down the slope like in LTTP? They are only 45 degree slopes, but in 4 directions. Keep in mind this is only C, and the tiles are not data structures with coordinates, just a single number representing what type of tile it is. I had an idea to make his speed in the other direction equivalent to his speed in the direction he's going, to make him move diagonally whenever he came within the bounding box of the slope, but this technique had many problems. I need something more robust, but nothing too complicated.
Advertisement
Filthy trick: don't try to make slopes.

Consider this hypothetical approach: There are tiles that are painted to look like vertical surfaces. There are tiles which are marked obstructed to prevent you from "climbing" them. Then there are tiles which are marked passable, and painted to look like ramps, stairs, etc.

Now you get the visual effect of 2.5D terrain without writing a single line of code. It's all down to art and level design.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]


Filthy trick: don't try to make slopes.

Consider this hypothetical approach: There are tiles that are painted to look like vertical surfaces. There are tiles which are marked obstructed to prevent you from "climbing" them. Then there are tiles which are marked passable, and painted to look like ramps, stairs, etc.

Now you get the visual effect of 2.5D terrain without writing a single line of code. It's all down to art and level design.


No, I understand that trick and have been using it for other projects. But I want to know how to do strictly 2-dimensional slopes in a top-down environment.
Like in this image on the corners of the room:
0.jpg
Just to clarify: By "slopes" you mean walls that run diagonally on a 2D surface? It's a bit confusing since the first image seems to contain ACTUAL slopes,as well as diagonal walls.

Can't you replace the bounding boxes of the diagonal walls with polygons or (if they are always on the outer part of the level) even just line segments?
Yeah, i think he means going in the diagonal direction
"It doesn't matter how slow you go - as long as you don't stop"

"Declare variables, not war"

"There are only 10 types of people: those who understand binary and those who don't"

No, I understand that trick and have been using it for other projects. But I want to know how to do strictly 2-dimensional slopes in a top-down environment.
Like in this image on the corners of the room:
0.jpg





Your terminology is extremely confusing.

What you see in that room is not what I would call a "slope." There is no elevation change. All you are seeing is a rendering/artwork trick.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]


Just to clarify: By "slopes" you mean walls that run diagonally on a 2D surface? It's a bit confusing since the first image seems to contain ACTUAL slopes,as well as diagonal walls.

Can't you replace the bounding boxes of the diagonal walls with polygons or (if they are always on the outer part of the level) even just line segments?


I mean 2d walls going diagonally. Where in that image do you see anything else? The game contains vertical slopes, but not the image...
My game doesn't do a bounding box check, it does a grid-based check. Dividing the player's coordinates by the tile size, and checking the data grid if the player's location is passable (0 on the grid).
And in that game, they weren't a graphical trick either. The player would actually slide along them diagonally.
[s]Ok, to clarify things up. What re you meaning? the corners? or the grass, that is in diagonal lines? or another thing?

please try to be more clear[/s]
[s]
[/s]
[s]
[/s]
ok, the walls cutting half a grid square.. now it's clear.

If you have a squre you can find the Hypotenuse, and have a square cut in half....

But it must have another way of doing this....
"It doesn't matter how slow you go - as long as you don't stop"

"Declare variables, not war"

"There are only 10 types of people: those who understand binary and those who don't"

Ok, to clarify things up. What re you meaning? the corners? or the grass, that is in diagonal lines? or another thing?

please try to be more clear


I fail to see what isn't clear about this. It really isn't easy to explain in words, so I'm gonna fire up GIMP.
This is what I mean when I say 'slopes':
[attachment=4467:Slopes.png]

If Link comes into contact with a 'slope', and continues moving:
[attachment=4468:Start.png]
[attachment=4469:end.png]

He will slide along it, like in the above picture.
This is what I want. However, my code checks if he is coming into contact with the slope's bounding box. I want to know how to check if he has collided with the hypotenuse, and how to slide him along the slope like in LTTP. The tiles aren't objects, but numbers in a grid of data known in my code as tilemap[][].
Ah, you're talking about diagonal walls.


That's easy: you mark which corner is clear (only four possibilities: top left, top right, bottom left, bottom right). Based on that, you know the slope of the diagonal itself (it will be either +1 or -1) and the side of the diagonal (above or below) that should be passable. Then you write a total of five collision check cases:

  • No corners are clear, i.e. the block is solid - use your existing code
  • Top left corner is clear
  • Top right corner is clear
  • Bottom left corner is clear
  • Bottom right corner is clear

For the solid block case, do as you already do. For diagonals, you just do an intersection between the line that defines the diagonal, and the player's bounding box. If they hit, move the player back "out" of the wall and slide them along it. If they don't overlap, allow the player to move freely.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

This topic is closed to new replies.

Advertisement