Rotating vector around z-axis

In my FPS, I’m storing player-velocity relative to the player’s orientation. However, I’m having trouble rotating the player’s velocity vector to “persist” in the direction they were moving when they turn. So far, I’ve only managed to reach results where there is no rotation at all and/or velocity is rotated to an angle perpendicular with what it should be.
This is my current attempt at solving this: (where self._hRot is the angle in degrees the player is rotating on any given frame and self.upVec is just essentially Vec3(0,0,1))

turn = Quat()
turn.set_from_axis_angle(angle_deg = self._hRot, axis = self.upVec)
turn.normalize()
self.velocity = Vec3(turn.xform(self.velocity))

Does anyone know how to rotate the xy-component of the vector while preserving the magnitude?

Hmm… A rotation matrix should do it, I would imagine.

Something like this: (Untested.)

matrix = Mat3.rotateMat(angleToRotateBy, axis)
newVector = matrix * oldVector

But… Why are you storing your velocity relative to the player’s orientation…? It seems that it would be much simpler to store it relative to the world, in which case direction of motion would be inherently preserved…

(For what it’s worth, that’s what I do, and I find that it works quite well.)

I tried using the following:

mat = Mat4.rotate_mat(self._hRot, playerEnt.upVec)
self.velocity = Vec3(mat.xform_vec_general(self.velocity))

Unfortunately I ended up with the same problems I was facing before where turning alternates between having no effect and turning the velocity to a random direction. Maybe it’s because I’m doing this in small increments across multiple frames?

I tried using matrix * self.velocity however unfortunately neither Mat3 nor Mat4 support that operand with Vec3.

As for why I store velocity player-relative, I don’t fully remember all of my reasons but my main one was so it was easier to update velocity by simply checking if any of the wasd keys were down and then adding velocity in the corresponding directions, before moving through only one line of code:

if self.velocity.length(): self.np.set_pos(self.np, self.velocity * deltaTime)

I suppose while it’s not a trivial amount of effort, I’ll try and rewrite my player class to have world-relative velocity.

Hmm… I’m not sure of why that’s not working, I’m afraid! :/

Ahh, I see!

While I can understand the attraction, I think that you’ll find that you have far less trouble with world-relative velocity.

I mean, you can do pretty much the same thing with world-relative velocity: just get your character’s forward- and right- vectors from their orientation, and then add (or subtract) those as appropriate.

Something like this:

# First, get the character's orientation as a quaternion
#
# (Relative to the world. Of course, ff your character is
#   already a child of "render", then you can omit it, I daresay.
#  Conversely, if you have a different root-node for your
#  world, substitute that in place of "render" below)
orientation = self.np.getQuat(render)

# Then, from that, get the character's forward- and right- vectors
forwardVector = orientation.getForward()
rightVector = orientation.getRight()

# And finally, apply those vectors as appropriate to key-presses:
if forwardKeyIsPressed:
    self.worldRelativeVelocity += forwardVector * self.acceleration * deltaTime
if backwardKeyIsPressed:
    self.worldRelativeVelocity -= forwardVector * self.acceleration * deltaTime
if rightKeyIsPressed:
    self.worldRelativeVelocity += rightVector * self.acceleration * deltaTime
if leftKeyIsPressed:
    self.worldRelativeVelocity -= rightVector * self.acceleration * deltaTime

Movement with world-relative velocity is also just one line of code–just remove the self-relativity parameter, and instead include the addition of the character’s current position:

self.np.setPos(self.np.getPos() + self.velocty * deltaTime)

(If called for–if your particular scene-structure calls for it–you might add relativity to “render” within your calls to “setPos” and “getPos” there–but I’d suggest trying without, first.)

1 Like

It took a bit, but I’ve done it! Thanks to NodePath.get_relative_vector(), I was able to actually retrofit my previous movement calculations by creating a new vector, transforming that to world space, and then adding that to the player velocity.

Now all I have to do is some fine-tuning on friction and such to deal with the opposite of my initial problem; Now players have too much trouble changing their direction of movement.

1 Like

Well, I’m glad that you found a solution in the end! ^^;