0
\$\begingroup\$

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?

\$\endgroup\$
  • \$\begingroup\$ What do versors plus speed (you've mislabeled it velocity in your example; velocity includes direction, speed does not) actually offer you? Looks like extra math (less efficiency) and complication over just using a velocity vector for no gain. \$\endgroup\$ – Sean Middleditch Oct 12 '13 at 17:25
  • \$\begingroup\$ @SeanMiddleditch, You are right, I meant speed. I need to be able to modify the speed at every update if I need to (and I need it to simulate friction). With vectors I would always have to calculate the length/magnitude of the vector and adjust it to be of the length of the speed I want (which seems less efficient if you ask me). Either way if you have a cleaner solution with a single vector (without an external component) I'm fine with it. \$\endgroup\$ – Shoe Oct 12 '13 at 17:30
  • \$\begingroup\$ In the end it doesn't change a thing. Normalizing to 1 or normalizing to the length/speed you want doesn't change anything of the problem above. \$\endgroup\$ – Shoe Oct 12 '13 at 17:31
  • \$\begingroup\$ So... your underlying question has nothing to do with versors at all but with the application of movement controls? \$\endgroup\$ – Sean Middleditch Oct 12 '13 at 17:34
  • \$\begingroup\$ @SeanMiddleditch, the problem I'm facing is with versors. The problem lies on the fact that the versor is normalized by definition and I can't apply and unapply "forces" to it like shown above (at least I don't know why), which is what I need for controls. \$\endgroup\$ – Shoe Oct 12 '13 at 17:40
3
\$\begingroup\$

Don't try to remove force from your movement when a key is released. Apply movement acceleration/force every frame, not just on key events. Clamp velocity's magnitude and use damping (plus maybe surface friction) to cause the character to quickly slow to a halt when the key is released.

This applies whether you're using versors, vectors, or some other representation. You're currently combining your movement controls with current object state and losing information in the process (which is why subtracting the original inputs doesn't work). You'll also run into problems with trying to apply counter force when letting go of a key once you have more complex scene interactions: your character will maybe hit a wall and stop moving, so applying a counter force to the original input will cause the character to start moving in the opposite direction.

\$\endgroup\$
  • \$\begingroup\$ I think I understand what you are saying, but I can't quite see how you would implement it otherwise. Can you make pseudo-code example (leaving the whole friction part out)? \$\endgroup\$ – Shoe Oct 12 '13 at 18:53

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.