26
\$\begingroup\$

I would hope that we have all played Zelda: A Link to the Past, please correct me if I'm wrong, but I want to emulate that kind of 2D, top-down character movement with a touch of correction. It has been done in other games, but I feel this reference would be the easiest to relate to. More specifically the kind of movement and correction I'm talking about is:

  • Floating movement not restricted to tile based movement like Pokemon and other games where one tap of the movement pad moves you one square in that cardinal direction. This floating movement should be able to achieve diagonal motion.
  • If you're walking West and you come to a wall that is diagonal in a North East/South West fashion, you are corrected into a South West movement even if you continue holding left (West) on the controller. This should work for both diagonals correcting in both directions.
  • If you're a few pixels off from walking squarely into a door or hallway, you are corrected into walking through the hall or down the hallway, i.e. bumping into the corner causes you to be pushed into the hall/door.

I've hunted for efficient ways to achieve this and have had no luck. To be clear I'm talking about the human character's movement, not an NPC's movement. Are their resources available on this kind of movement? Equations or algorithms explained on a wiki or something?

I'm using the XNA Framework, is there anything in it to help with this?

\$\endgroup\$

4 Answers 4

22
\$\begingroup\$

Well, the first bullet point is easy. You simply store and manipulate the character's position in world or pixel coordinates instead of tile-based coordinates. If you were having an issue with this, it might be due to a a confusing choice of representation for your world and tile space, so perhaps you should post more details about it / ask a separate, specific question.

For the second point, the most direct approach would be to take the player's (normalized) movement vector and add it to the wall's normal vector, then renormalize. The sign of the components of the resulting vector will indicate how the wall relates to the player's motion while the vector itself indicates which direction the player may now move.

For the third point, assuming you have collision rectangles for both the wall and the player, you should be able to determine how much of the player's collision rectangle contacts with the wall's collision rectangle. If, for example, the player is moving to the right and hits a vertical wall, you compare the Y axis extents of the collision rectangles -- if if the player's extent exceeds the wall's extent by some threshold, say 75% of the player's Y axis extent, then you "cheat" the player towards the door.

I've made a fair number of assumptions here in how your object model looks in your code and what techniques you've chosen -- largely due to the generality of your question. I've tried to suggest approaches that are simple (although perhaps not optimal) for the same reason. If you can provide more specific information, either in this question or in a new one, I can try to provide more details or a better idea.

\$\endgroup\$
6
  • \$\begingroup\$ Yeah, floating the character around wasn't a problem. Just making sure people saw that it was a requirement. You did give me the key answer: Tiles having vectors! I can't believe I didn't think of that. Thank you. \$\endgroup\$ Jan 12, 2011 at 14:31
  • \$\begingroup\$ In zelda, there was only one-angle they could be at, so there was no need for calculating normal-vectors, it was just a special case in the code. \$\endgroup\$ May 27, 2011 at 21:40
  • \$\begingroup\$ I don't understand how you give a tile a vector. What would that look like? \$\endgroup\$
    – test
    Oct 12, 2014 at 6:19
  • \$\begingroup\$ A tile already presumably has data like its graphic, whether or not it's passable, etc. this is just another field. For example: struct Tile { vector2 normal; ... } The value of the normal should come with the data that defines the tile \$\endgroup\$
    – user1430
    Oct 12, 2014 at 16:17
  • \$\begingroup\$ @JoshPetrie Revisting this. Wouldn't a tile that can be collided with in multiple directions need to have multiple vectors? I'm not sure I understand how a tile could have a single vector. \$\endgroup\$
    – test
    Oct 8, 2015 at 22:51
4
\$\begingroup\$

As a possible answer for the second point is to project the player's movement vector along the wall vector using a dot product (a.b * normalized(b)). You then get a vector that tells you how far to move the player in the direction of the wall, and if you move the player by that vector, you get a 'slide' along the wall. Worked well for me in a previous game project.

\$\endgroup\$
3
\$\begingroup\$

Great answer for Josh, but I'll add a few suggestions: - For more info on sliding against walls, check out my question - from this answer I managed to get it working really nicely. - If I'm not mistaken, when walking up the screen Link will ease to align to the closest whole horizontal grid square. This way when you get to the doors you're more likely to be properly lined up (might be wrong). - To make it easy to get through doors, make sure the collision box of your character is way smaller than the width of the door.

\$\endgroup\$
1
  • \$\begingroup\$ Or have the collision box be a circle perhaps? \$\endgroup\$ Jan 13, 2011 at 20:03
2
\$\begingroup\$

For correction of entering doors, you could make the collision object for the door slightly larger than the image of the door. This would result in the same effect proposed by Josh, but without having to calculate the proximity to the wall's collision rectangle.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .