Jump to content
  • Advertisement
Hashbrown

Gameplay How do I apply direction to a velocity vector and then to the character position?

Recommended Posts

Posted (edited)

I'm making basic fps controls. I managed to apply acceleration to a velocity vector and of course velocity to position. Everything works perfectly and the character accelerates and decelerates in 3D space. But I can't seem to figure out how to apply direction to the character. I'm trying to move the camera (character) towards the direction I'm looking at. I'm very sure the fwd, right, and up unit vectors are fine.

By the time I get to adding my velocity to the position: 

  // Acceleration already calculated and it's increasing and decreasing velocity every frame.
  transform.position.x += this.velocity.x * Game.Time.step;
  transform.position.y += this.velocity.y * Game.Time.step;
  transform.position.z += this.velocity.z * Game.Time.step;

I can't do something like this this: 

  // No good.
  transform.position.x += this.velocity.x * transform.forward.x * Game.Time.step;
  transform.position.y += this.velocity.y * transform.forward.y * Game.Time.step;
  transform.position.z += this.velocity.z * transform.forward.z * Game.Time.step;

because it won't work. I'm able to walk forward, but not to the right (nor left).

Btw, before adding acceleration to the mix, I would do something like this:

// Used to do this, but no acceleration. Only moves as soon as I press a key.
if (Game.Input.Key.upArrow.down)    Game.camera.transform.moveZ(-speed);
if (Game.Input.Key.downArrow.down)  Game.camera.transform.moveZ( speed);
if (Game.Input.Key.rightArrow.down) Game.camera.transform.moveX( speed);
if (Game.Input.Key.leftArrow.down)  Game.camera.transform.moveX(-speed);

...and the moveZ  function would look something like this: 

// Move X works the same obviously, just replace forward with right.
moveZ(speed) {
    this.position.x += speed * this.forward.x;
    this.position.y += speed * this.forward.y;
    this.position.z += speed * this.forward.z;
}

 But of course this clearly doesn't accelerate the character, but my camera would move towards the direction I was looking at. I'm sure this is a very basic question with an answer I should already know :S

Oh by any chance you want to take a look at the acceleration function I wrote, you can see it at this pastebin. Granted, I'm sure there's way simpler ways of doing it. 

Edited by Hashbrown

Share this post


Link to post
Share on other sites
Advertisement
Posted (edited)
1 hour ago, Hashbrown said:

I'm trying to move the camera (character) towards the direction I'm looking at.

I am assuming that transform.forward = direction camera is looking at. 

I am also assuming you are using vectors for rotations and not quaternions, and rotation is normalized, and that this.velocity = acceleration.

Then moving to the right should be:

 transform.position += this.velocity * transform.right * Game.Time.step;

 

Edited by Scouting Ninja

Share this post


Link to post
Share on other sites
Posted (edited)
1 hour ago, Scouting Ninja said:

I am assuming that transform.forward = direction camera is looking at. 

I am also assuming you are using vectors for rotations and not quaternions, and rotation is normalized, and that this.velocity = acceleration.

Then moving to the right should be:


 transform.position += this.velocity * transform.right * Game.Time.step;

 

Hey there Ninja, thanks for the quick response. I'm using vectors instead of quaternions and rotations are definitely normalized. The forward, right and up unit vectors are working with another implementation. The problem was actually that this was never going to work for me: 

// Only for moving forward and backward, doesn't work though.
transform.position.x += this.velocity.x * transform.forward.x * Game.Time.step;
transform.position.y += this.velocity.y * transform.forward.y * Game.Time.step;
transform.position.z += this.velocity.z * transform.forward.z * Game.Time.step;

I actually had to consider that I'm only using x and z in my velocity vector, and I should add the z to all xyz properties of the position vector. Same for velocity.x. I feel foolish for not noticing this, but it's working beautifully now. Visualizing everything in my head as arrows helped out too 😛 Here's the right implementation:

transform.position.x += this.velocity.z * transform.forward.x * Game.Time.step;
transform.position.y += this.velocity.z * transform.forward.y * Game.Time.step;
transform.position.z += this.velocity.z * transform.forward.z * Game.Time.step;

transform.position.x += this.velocity.x * transform.right.x * Game.Time.step;
transform.position.y += this.velocity.x * transform.right.y * Game.Time.step;
transform.position.z += this.velocity.x * transform.right.z * Game.Time.step;

 

Edited by Hashbrown

Share this post


Link to post
Share on other sites
Quote

How do I apply direction to a velocity vector and then to the character position?

I think the answer you are looking for is, you don't. Velocity has a direction already (providing it has magnitude), you just add the velocity to the position each (preferably FIXED) tick.

Anything to do with direction is done beforehand when you decide how to affect the velocity as a result of the player input / look direction.

Share this post


Link to post
Share on other sites

Just to expand on this, a typical simple example:

  1. Player input : pressed forward
  2. Apply impulse in the forward direction (determined by yaw, and atan2), with magnitude scaled to determine the player speed. Impulse is simply added to velocity.
  3. Physics tick : Player position += velocity.
  4. Friction : velocity *= 0.99
Things become simpler once you fix your timestep.

Share this post


Link to post
Share on other sites
6 minutes ago, lawnjelly said:

Anything to do with direction is done beforehand when you decide how to affect the velocity as a result of the player input / look direction.

So even though my controls are working, I might have it all wrong, at least intuitively I had it wrong? At the moment I have it like this:

transform.position.x += this.velocity.z * transform.forward.x * Game.Time.step;
transform.position.y += this.velocity.z * transform.forward.y * Game.Time.step;
transform.position.z += this.velocity.z * transform.forward.z * Game.Time.step;

transform.position.x += this.velocity.x * transform.right.x * Game.Time.step;
transform.position.y += this.velocity.x * transform.right.y * Game.Time.step;
transform.position.z += this.velocity.x * transform.right.z * Game.Time.step;

I should always apply direction to the position vector first, and then apply velocity to the position afterwards is what you're saying? Sorry about asking so much, just want to make sure I get it :)

Share this post


Link to post
Share on other sites
23 minutes ago, Hashbrown said:

So even though my controls are working, I might have it all wrong, at least intuitively I had it wrong? At the moment I have it like this:


transform.position.x += this.velocity.z * transform.forward.x * Game.Time.step;
transform.position.y += this.velocity.z * transform.forward.y * Game.Time.step;
transform.position.z += this.velocity.z * transform.forward.z * Game.Time.step;

transform.position.x += this.velocity.x * transform.right.x * Game.Time.step;
transform.position.y += this.velocity.x * transform.right.y * Game.Time.step;
transform.position.z += this.velocity.x * transform.right.z * Game.Time.step;

I should always apply direction to the position vector first, and then apply velocity to the position afterwards is what you're saying? Sorry about asking so much, just want to make sure I get it :)

No.  The velocity vector tells you what the direction of movement is.  If you want to turn the character to another direction, then you rotate the velocity vector.  So for example if you want to turn 30 degrees to the right, then you rotate the velocity vector by 30 degrees to the right. 

After you're doing with the velocity vector, including adding any accelerations and so on, then you apply it to the position.  NewPos = OldPos + Velocity * dt

To rotate the velocity just use whatever you have... a matrix, quaternion, or whatever you use. 

Share this post


Link to post
Share on other sites

Your terminology seems a bit dodgy I think. Applying direction? What does that even mean, it could mean different things in different scenarios. You can apply an impulse, or a force, to change a velocity.

You can apply an offset to change a position directly, and that is used in some games, but I am guessing you are trying to use the physics approach of having game events change objects velocities, and then the velocities in turn change the objects positions. Even in these games, sometimes you will 'teleport' an object to a position and override the velocity in some situations.

Trying to translate, you should be applying your 'player direction' (where you want them to move) as an impulse, or force, to the velocity of a 'physics object'. All of these are vector3 by the way.

In a really simple physics simulation you might have a physics object:

class PhObject
{
  void Iterate()
  {
    // move the position each tick by the distance in each axes defined by the velocity
   	m_ptPosition += m_ptVelocity; 
    
    // apply some friction, so the object slows down, unless it is e.g. in space
    m_ptVelocity *= 0.99f;
  }
  
	// simple functions to make the object move  
	void ApplyImpulse(const Vector3 &impulse) {m_ptVelocity += impulse;}
	void Teleport(const Vector3 &ptPos) {m_ptPosition = ptPos; m_ptVelocity.Zero();}

  // retrieve position of object (this would more likely be an interpolating function for rendering)
  void GetPosition(Vector3 &ptPos) {ptPos = m_ptPosition;}
  
private:
  Vector3 m_ptPosition;
  Vector3 m_ptVelocity;
};

Providing you get this down, you want to find out how to decide what impulse to apply due to keyboard input each game tick.

void MyInputTick()
{
	Vector2 move(0, 0);

	if (PressingForward()) move.y += 1;
	if (PressingBackward()) move.y -= 1;
	if (PressingLeft()) move.x -= 1;
	if (PressingRight()) move.x += 1;

	float yaw = GetInputYaw(); // from mouse somehow
	
	// rotate move vector by yaw radians (so that forward points in the look direction)
	move.Rotate(yaw);

	move *= PLAYER_MOVE_SPEED; // actually the impulse magnitude, but it will determine the speed

	// apply the impulse to the player physics object, so that on the physics tick the player will move!
	PlayerPhObject.ApplyImpulse(move);
}

Obviously this isn't debugged, it's just conceptual. It is ESSENTIAL that you read and understand the 'fix your timestep' article before doing this or you will just get more confused.

The big take home here is that the player input and the impulse is a totally separate issue to stepping the physics. Anything could need to apply an impulse or force to a physics object, not just a player pressing keys. It could be an AI monster, a motor, a missile etc etc.

 

Share this post


Link to post
Share on other sites
Posted (edited)
53 minutes ago, lawnjelly said:

Apply impulse in the forward direction (determined by yaw, and atan2), with magnitude scaled to determine the player speed. Impulse is simply added to velocity.

12 minutes ago, 0r0d said:

NewPos = OldPos + Velocity * dt

My own way of doing this is taking the direction vector and multiplying it with the magnitude of the velocity. This was why I assumed the velocity was the result of acceleration.

So if direction = Right(1,0,0) and velocity was say 45 degrees(20,0,20) then I can use Pythagorean theorem to find the magnitude: Root((A*A)+(B*B)) So the root of 800 = 28.284 units of speed at 45 degrees.

Edit: I mean (20,0,20) = 28.284 units of speed at 45 degrees.

Then (1,0,0) * 28.284f = (28.284f ,0 ,0) moving right at the speed of 28.284 units.

Edited by Scouting Ninja

Share this post


Link to post
Share on other sites
18 minutes ago, Scouting Ninja said:

My own way of doing this is taking the direction vector and multiplying it with the magnitude of the velocity. This was why I assumed the velocity was the result of acceleration.

So if direction = Right(1,0,0) and velocity was say 45 degrees(20,0,20) then I can use Pythagorean theorem to find the magnitude: Root((A*A)+(B*B)) So the root of 800 = 28.284 units of speed at 45 degrees.

Edit: I mean (20,0,20) = 28.284 units of speed at 45 degrees.

Then (1,0,0) * 28.284f = (28.284f ,0 ,0) moving right at the speed of 28.284 units.

If I understand this right, you can do this, but at that point it is no longer in any sense 'physics', you are just moving the object position directly, there is no momentum. That kind of approach can work though and even works better in certain types of games. :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!