gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Beginners > Walking down diagonal tiles

#31540 - identitycrisisuk - Sun Dec 12, 2004 1:14 am

I've been holding off posting this until I was sure I'd given this some serious thought but I still don't think I can think up a nice solution. I think I'm okay with the actual collisions for 45 degree angle tiles, just using the offset of a position from the corner of a tile along the x and y axes can return a true or false result. I'm also pretty sure I can also reposition a point correctly when it's coming up the slope of a diagonal tile or when it would result in the point being inside the tile.

The only thing I can't really get my head around is getting a character to walk down a tile smoothly (this is a side scrolling platformer btw) and this is perhaps partially due to the way I've tried to program my character movement physically. When you're asking to go right it simply increases the x velocity and if there is no collision then it adds the velocity to the current position. Problem is, when starting to go down a slope there isn't necessarily a collision. For Example:
Code:
Start pos ->*--------*<- End pos
---------------\
                \
                 \
                  \
                   \
                    \*<- Where I'd like to be after this move
                     \
                      \

So currently my character goes down slopes in individual drops rather than walking all the way down. I'm unsure of how to detect this though, as in the above example the end pos is in a completely blank tile. Should I be doing some kind of test like:

IF the player was on the ground last frame AND hasn't just tried to jump AND end point is in the free part of a diagonal tile OR end point is above a diagonal tile THEN correct position to on the diagonal

That just looks horrible though, I have got states to make the testing for being on the ground and jumping easy but the on diagonal tile OR above diagonal test just seems a bit wrong. Haven't even considered slowing down and speeding up the character when going across these tiles so I'm sure that'll be a whole other fun task...
_________________
Code:
CanIKickIt(YES_YOU_CAN);

#31542 - sajiimori - Sun Dec 12, 2004 1:34 am

Make a "snap to the ground" function that takes a character's current position and either raises or lowers them until they're standing directly on the surface. Raise them if they're inside a solid area, or lower them otherwise. Have a flag on each character that says whether they are on the ground or not, and apply the function to all the ones that are.

Basically, you're seperating the laws of physics into 2 sets: the ones that apply to flying objects, and the ones that apply to sliding/walking ones.

#31589 - identitycrisisuk - Sun Dec 12, 2004 7:55 pm

Hmm, certainly would make the code look nicer if it was all wrapped into a snap to ground function like that. I already have a state for characters being on the ground, so I'd just have to make sure I set it to false as soon as they request to jump so they won't be snapped back to the ground.

I think I'd rather keep the raising people up separate though, so that it's done in the main collision loop while collisions with solid tiles are handled. I'd just feel like I have to be doing tests twice, checking when jumping characters land on a diagonal tile so that they can be set as being on the ground so that they can be repositioned later. Then again, it's possible it would help with a character coming down very fast so he maybe clips through a diagonal tile and ends up in a solid tile below. The solid tile test would put him on top of the solid tile and then the snap to ground would bring him to true ground level.

So was I pretty much right in either checking for being on or above a diagonal tile? I guess it's not too bad when you take away the tests that you need to get to that point.
_________________
Code:
CanIKickIt(YES_YOU_CAN);

#31594 - sajiimori - Sun Dec 12, 2004 9:29 pm

Quote:
I already have a state for characters being on the ground, so I'd just have to make sure I set it to false as soon as they request to jump so they won't be snapped back to the ground.
Don't forget to clear it when they walk off a ledge. ;)

Hmm... just to exercise on a weekend morning:
Code:

int heightAtGroundBelow(Point pixel, Map* m)
{
  Point tile = pixelToTile(pixel);
  while(tile.y < m->height() && m->getTile(tile).isEmpty())
    ++tile.y;
  return tileBottom(tile) -
    m->getTile(tile).heightAt(tileOffset(pixel.x));
}

// Edit: fixed a bug where a rectangle wider than 2 tiles
// might not notice a pillar between its sides.
int heightAtGroundBelow(Rect r, Map* m)
{
  int result = INT_MAX;
  int end = roundUp(r.right, TILE_WIDTH);

  for(Point p(r.left, r.bottom); p.x < end; p.x += TILE_WIDTH)
    result = min(result, heightAtGroundBelow(p, m));

  return result;
}

int heightAtGroundBelow(Actor* a, Map* m)
{
  return heightAtGroundBelow(a->collisionRect(), m);
}

// This is the only function that has side effects or
// accesses globals.  It is meant to only perform the side
// effect and leave the rest of the work to pure functions.
void snapToGroundBelow(Actor* a)
{
  a->setY(heightAtGroundBelow(a, gMap()));
}

#31605 - identitycrisisuk - Sun Dec 12, 2004 11:39 pm

Weekend morning? Wow, you must be a lot of hours behind me, west coast of america?

Hopefully the walking off a ledge thing will sort itself out, all I've got for checking if in the air at the moment is to check if the pixel underneath the bottom position of the character results in a collision. This should mean that in the next frame it will be set to in the air and if I only check one tile lower for snapping the position it won't find anything to collide with (as long as I make my levels sensibly, it would go wrong if I decided to have a diagonal tile in the middle of a flat piece of ground for no reason).

The only think I'm thinking might be slightly problematic now is the transition from one tile to the next going up a slope. I think I may have to set the y axis velocity too or at the top of a diagonal tile the system will think the player wants to move into the tile directly to the left/right of the tile it is on. This will either be solid, meaning the player will stop or free meaning it'll fall through the floor. Still, sensible though as I'll really need to know when something is on a diagonal tile so I can add a state for that, might even link it into an animation that looks more like walking up or down a hill/stairs. I'm trying to recreate a movement system similar to the GBA Castlevania games and even they don't change the animation when going up stairs, might be quite cool.

Thanks for the code, I'm not at the stage where I have a full rectangle for the character yet but will probably work with that eventually. It confused me a bit with the function overloading but it makes sense now :)
_________________
Code:
CanIKickIt(YES_YOU_CAN);

#31608 - sajiimori - Mon Dec 13, 2004 12:26 am

Quote:
Wow, you must be a lot of hours behind me, west coast of america?
Yup.
Quote:
Hopefully the walking off a ledge thing will sort itself out, all I've got for checking if in the air at the moment is to check if the pixel underneath the bottom position of the character results in a collision.
Then you don't need to maintain a flag for being on the ground (except for caching purposes but beware of early optimization).

Anyway, the whole point was to seperate ground physics from free-flying physics, and if you aren't going to do that then very little of what I said is relevant.
Quote:
I think I may have to set the y axis velocity too or at the top of a diagonal tile the system will think the player wants to move into the tile directly to the left/right of the tile it is on.
That's what snapping upwards is for.
Quote:
This will either be solid, meaning the player will stop or free meaning it'll fall through the floor.
I would just make them solid, to keep things simple.