Skip to main content
GameDev.net gamedev.net
🔒 Locked

Best solution for walking on slopes?

Started by solarstrings Aug 26, 2009 at 2:24 PM 6 replies 1.8k views
Original Post
solarstrings
solarstrings
Hi guys, and ladies! I'm working on a 2D platformer game and been coding on it back and forth, but need to shape things up a bit better, especially my slope code. Download here: http://aliengame.xieke.com/Downloads/New_Project_0.3.0.rar This used to be my metroid clone project, which now is heading in the direction of becoming it's own game with unique graphics, since I found a talented gfx artist.

My current slope function (pseudo code):

Tiles are 32x32 in size.

At the moment I'm using arrays to define slopes:

//a simple 45 degree slope to the right
//Each number represents how many pixels to move the player up on the y axis.


int Slope_Right[32] = {
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,

};

then in the code I compute how many pixels into the tile I am by:

//get the current tile the player is standing on.
player_x_calc = ( (player->worldx)/32)*32;

//worldx - player_x_calc, which gives how many pixels the player is in on the tile.
player->WhereOnTilex = player->worldx - player_x_calc;

//get players tile x & y position
tilex = player->worldx/32;
tiley = player->worldy/32;

    //get the current tile
    tile = SR387_Map[tile_y][tile_x][1];

    //check the current tile against a slope index, if we found that player SLOPE RIGHT
    if(SlopeIndex[test_tile] == SLOPE_RIGHT)

    {
        //set the new player y position to the current tile, and move him/her up the
        //pixels pre defined in the slop array.
	player->worldy = (tiley*32) - Slope_Right[player->WhereOnTilex];
    }
My question is: Is there a more efficent way to do this on? I have found very little examples on the internet about slope walking, I did find som more advanced algebra on the issue, but not a "down-to-earth" example, So I came up with this solution.
zoner7
zoner7
I was more reading this to gain an understanding of how slope-based collisions work, but I can say that
player_x_calc = ( (player->worldx)/32)*32;
performs a redundant operation...

player_x_calc = ( (player->worldx)/32)*32) = player->worldx.

32/32 = 1

Not that this will help you, but it does make the code look cleaner
shadowcomplex
shadowcomplex
First off, this part can be simplified:
int Slope_Right[32] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,};player->worldy = (tiley*32) - Slope_Right[player->WhereOnTilex];

To:
player->worldy = (tiley*32) - player->WhereOnTilex + 1;


However, using a tile system for the 2d platformer has some big disadvantages; handling slopes is one of them (especially when you want free angles.)

A very easy solution is to construct your environment out of line segments (you'll probably need a tool to do this) at which point slopes become arbitrary. Essentially, you can move your character along the normalized vector of the line the character is on. Easy, breezy, and allows for angles of any degree.

Further benefits from this system are: decreased memory footprint, simple line to line collision (which can be optimized to be very fast), the need to only check for actor-environment collision when not 'attached' to a line, it's very easily expanded to handle junction points for stairs/ladders, and finally, I've also implemented dynamic terrain using this system (subdiving lines) :)

In short, I've used the tile system, but it is just so constrictive compared to the system I've described above :)

More or less though, what you are doing is pretty normal in a tile based system.
cache_hit
cache_hit
Quote:
Original post by shadowcomplex
the need to only check for actor-environment collision when not 'attached' to a line


Wouldn't you still need to always check it? What if you run into an impassable wall that you have to jump over?
shadowcomplex
shadowcomplex
Quote:
Original post by cache_hit
Quote:
Original post by shadowcomplex
the need to only check for actor-environment collision when not 'attached' to a line


Wouldn't you still need to always check it? What if you run into an impassable wall that you have to jump over?


No, in said system, the lines know what they are connected to. When you reach the end of a line, you try to transition to the next line (the vertical wall in this case) -- either you transfer and calculate how much momentum you have left to complete the discrete move onto the new line, or you aren't allowed to move onto the new line and you are stopped (and in this system each actor can have a max angle slope they can move onto).

Or of course, the line can have no connection, in which case you begin freefall, and collision checking kicks back in :)

You still need to do actor-actor collision every frame though. But I've used this system on the DS, and being able to disregard actor-environment collision during the attached phase, allowed me to get 4 times as many actors into the scene without killing the poor Arm9/7 :D

Edit: Also, you need to think of this system containing seperate lines at each junction -- not per se, one long horizontal line at the bottom with two vertical walls, but instead 3 horizontal lines at the bottom, each properly "connected" to the appropriate vertical walls :)
XTAL256
XTAL256
Quote:
Original post by zoner7
player_x_calc = ( (player->worldx)/32)*32;
performs a redundant operation...

Not if worldx is an int (which i assume it is). In which case, the above code will find the closest multiple of 32. In other words, it will snap the position to a 32x32 grid.

@OP: Does WhereOnTilex need to be a member of your player class or can it just be a local (temporary) variable?
Also, as others have pointed out, you are storing consecutive integers in an array which is indexed by those numbers - 1. Is there any reason for this, i.e. are you planning on modifying the values in that array and the values in the code are just the initial values?

On a similar note, i am also trying to figure out slope collisions, but on a pixel-based map rather than a tile map, quite a bit harder i should think. I posted about it earlier.
[Window Detective] - Windows UI spy utility for programmers
solarstrings
solarstrings
Quote:

Also, as others have pointed out, you are storing consecutive integers in an array which is indexed by those numbers - 1. Is there any reason for this, i.e. are you planning on modifying the values in that array and the values in the code are just the initial values?


The numbers in the array represents 32 pixels.

so if the player is standing in the middle of the tile, 16 pixels in to it, I simply check with the array how many pixel to move the player up.

The array is static for a 45 degree slope.

So If I want a 22.5 degree slope, I define 2 new arrays with numbers 1-16 & 17-32 in the arrays:

int Flat_Slope_Right_Part1[32] = {
1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,16,16
};

int Flat_Slope_Right_Part2[32] = {
17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29,30,30,31,31,32,32
};

This way I can build custom slopes with any shape.
XTAL256
XTAL256
Yes, but it is still just a linear mapping of x to y so it can be done with a simple formula:
player->worldy = (tiley*32) - (player->WhereOnTilex * slopeRatio);

Where slopeRatio is the ratio of y/x. So if you have a 22.5 degree slope then the ratio would be 1/2. The only reason to use an array is if the slope could possibly be non-linear (as is the case in my game), but you could just approximate it to a line and still get reasonable collision detection accuracy.
[Window Detective] - Windows UI spy utility for programmers

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.