Tuesday, July 4, 2017

2d - Beginner: How do I calculate a vector?


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.



Answer



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.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...