2
\$\begingroup\$

I am trying to wrap my head around some concepts in a side project I'm working on. I'm struggling with how I can calculate a vector based on my character movement logic. Here are the relevant details of my character movement:

  1. The character's hit box for collisions (and map position validity) is defined as a rectangle: x,y,w,h
  2. A character can move in 8 directions, let's keep this simple to ignore strafing, call this direction:

    • Left(x-1), Right(x+1), Up(y-1), Down(y+1)
    • UpLeft(x-1,y-1), UpRight(x+1,y-1),DownLeft (x-1,y+1), DownRight(x+1,y+1)
  3. The character can be in two moving states, again keeping numbers simple:

    • Walking 1 x offsets
    • Running 2 x offsets
  4. When a character is moved the following logic happens:

    • Create their proposed new hit box by adding an offset to their x & y coordinates based on their direction, call this proposedHitBox
    • Check if the proposedHitBox is a valid position on the map, if so, then update the character's position to the location defined on the proposedHitBox
    • If the proposedHitBox is not a valid location on the map it should try to glance the character. This is where I'm having trouble.

Given all this, how do I essentially, calculate a vector of their proposed motion?

Example:

  1. Character is at 10,10.
  2. Character starts running.
  3. Input is DownLeft.
  4. Proposed location is 8,12 (x-(1x2),y+(1x2)).
  5. Proposed location is valid.
  6. Update character position to 8,12.
  7. What calculation defines my vector? How does magnitude come from this? Is that generally stored as Z in a 2D game? So I'd use a Vector3 to store it? How does velocity come into this?

I'd assume my vector is a 45deg angle from current to proposed...?

Edit

Here is a picture of what the walls can look like in the game. The red box being the hit box as discussed above. The character is bound inside the blue polygon (which represents outer walls). Black being inner walls. The way I was doing glancing was overlaying 4x4 tiles across this entire map and then for each tile that the character should glance on I would choose an incoming direction (i.e. DownLeft) and then redirect them to a different direction (i.e. Down) which should make the proposed hit box in a valid position. This is however very tedious as I have to create glances for multiple directions for every tile. I'm looking for hopefully a better way.

Walls

I was reading that you could add vectors to each tile but I'm not sure how this works because on some tiles a incoming direction does not always have the same out direction.

\$\endgroup\$
  • 1
    \$\begingroup\$ The vector of their proposed motion is, in the example, (8,12) - (10,10) which is ( -2, 2 ). Normalise this to get the direction. Use Pythagoras' theorem to get the magnitude. \$\endgroup\$ – Ben Oct 12 '14 at 7:35
5
\$\begingroup\$

You're on the right track. I would start by determining the player's direction based on the keyboard state:

direction = Vector(0, 0)
if up pressed:
    direction = direction + Vector(0, -1)
if down pressed:
    direction = direction + Vector(0, 1)
if left pressed:
    direction = direction + Vector(-1, 0)
if right pressed:
    direction = direction + Vector(1, 0)

Then, multiply by the player's speed to get the velocity vector (or motion vector, as you say):

if running:
    speed = 2
else:
    speed = 1
velocity = speed * direction

So, the proposed location is

proposed location = current location + velocity

As you say, if the proposed location is valid, it becomes the current location. If not, the easiest thing to do is to not move the player at all. But you probably want the player to slide against walls...

Sliding

If your walls are axis-aligned, we can just add two cases, one for sliding horizontally and one for sliding vertically:

if (proposed x, proposed y) is a valid location:
    location = (proposed x, proposed y)
if (proposed x, current y) is a valid location:
    location = (proposed x, current y)
if (current x, proposed y) is a valid location:
    location = (current x, proposed y)

If your walls are not axis-aligned, sliding becomes somewhat more complex. We first need to determine which wall the player is facing. Now, we can think of the velocity vector as having two components: one which points into the wall, and one which moves sideways along the wall. We need to remove the component which points into the wall, so that we're left with a "sideways" motion vector.

The velocity component which points into the wall is the velocity vector's projection onto the wall's normal vector. We can compute this as

(v dot n / magnitude(n)^2) n

where v is the velocity vector and n is the wall's normal vector. If n is already normalized, this simplifies to

(v dot n) n

Now, subtract this from the original velocity to get the "sideways" component of velocity, which we can add to our location without running into the current wall. We should still check that this new proposed location is valid before accepting it, in case we run into a different wall.

Demo

I put together a JSFiddle to demonstrate. The logic for sliding against walls is in updatePosition.

\$\endgroup\$
  • 4
    \$\begingroup\$ Note that in above code the player walks diagonally about 41% faster (the length of Vector(0, 1) is 1, but the length of Vector(1, 1) is sqrt(2)). This may or may not be important in your game. The solution to this problem is to normalize the vector. \$\endgroup\$ – milleniumbug Oct 12 '14 at 11:45
  • 1
    \$\begingroup\$ Thank-you for the answer, it makes sense and has helped me understand it. I would like to know what you mean about the walls. I've edited my post to include details as to what my walls look like and what I've been trying to do with glancing currently. @milleniumbug In my game strafing is a problem. I had been attempting to solve this by just choosing different offsets when the character moves diagonally. One thing I had been noticing about these floating point offsets of position is that sometimes my character is drawn blurry. I've been rounding the drawn location for this. \$\endgroup\$ – test Oct 12 '14 at 16:41
  • 1
    \$\begingroup\$ @test, thanks for adding those details. gamedev.stackexchange.com/questions/4059/… shows a common approach to sliding against walls. If you'd like to see real code, I put together a JSFiddle and added a link in my answer. I'll also work on expanding my answer with more details about sliding. \$\endgroup\$ – Daniel Lubarov Oct 13 '14 at 3:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.