The context
I was thinking of using a versor + velocity field to implement the "moving" part of a 2D game object. For example, if the player should move right I just set the versor to be: [1, 0] and the velocity to be some variable. Then when the player movement needs to be updated we just multiply the versor to the variable and we get the vector to be summed to the current vector position.
For example if the position p
is [12, 45]
in the 2D space, the versor vs
is [1, 0]
and the velocity v
is 4
we can easily apply the algorithm above:
new position = p + (vs * v)
which leads to:
new position = [12, 45] + ([1, 0] * 4)
new position = [12, 45] + [4, 0]
new position = [16, 45]
The velocity/speed is a separate field because a versor (of length always = 1) better explain diagonal cases, like we see below.
When the player position is handled by the pressing of WASD keys I'd like to be able to code something like this:
on press W -> add versor [0, +1] to current versor and normalize
on press S -> add versor [0, -1] to current versor and normalize
on press A -> add versor [-1, 0] to current versor and normalize
on press D -> add versor [+1, 0] to current versor and normalize
on release W -> remove versor [0, +1]
on release S -> remove versor [0, -1]
on release A -> remove versor [-1, 0]
on release D -> remove versor [+1, 0]
Adding versors (everything is good)
The cool thing about this is that when both W and D are pressed the player moves diagonally to the top right because we first add the W versor and normalize:
vs = [0, 0]
vs += [0, +1] // W versor
// vs is now [0, +1] which is already normalized
and then we add the D versor:
// vs is now [0, +1]
vs += [+1, 0] // D versor
// vs is now [1, 1] which is not normalized
vs /= magnitude(vs)
// vs is now [0.71, 0.71]
Substracting versors (the problem)
Now the problem is when the user later release the W key for example. We currently have the W and D key pressed (which means the player is moving of [0.71, 0.71] (towards the top right corner) at every update. But if we remove the W versor, the calculus goes as:
// vs is now [0.71, 0.71]
vs -= [0, +1]
// vs is now [0.71, -0.29]
vs /= magnitude(vs)
// vs is now [0.9258, -0.3781]
The versor should be the remaining D versor, instead, ([1, 0]). I understand that this problem is related to the fact that we are normalizing at every operation, otherwise we would have:
vs = [0, 0]
vs += [0, +1] // W versor
vs += [+1, 0] // D versor
// vs is now [+1, +1]
vs -= [+1, 0] // D versor
// vs is now [0, +1]
but if we don't normalize and for some reason two D events are sent, we end up with:
vs = [0, 0]
vs += [0, +1] // W versor
vs += [+1, 0] // D versor
vs += [+1, 0] // D versor
// vs is now [+1, +2]
vs -= [+1, 0] // D versor
// vs is now [+1, +1]
which is not what we want. How can I correctly calculate the player position with versors then?