Skip to main content
GameDev.net gamedev.net
🔒 Locked

Basic FPS Physics

Started by dave Jun 25, 2010 at 5:25 AM 5 replies 2.6k views
Original Post
dave
dave
I've been mulling over this for a while now and i cant seem to get my head around it. Confusion has arisen over how you elegantly combine physics against the world and the controlling of the FPS player. I have a physics object of which the physics manager can hold many. The physics object has a m_Velocity 3D vector that is used to determine the next position of the physics object.

- At the start of the frame the game input code removes the velocity it added to the physics object from the last frame and adds on the new velocity based on what keys are down for the current frame. The reason for the removal is so the velocity doesn't accumulate over the course of many frames as keys are held down.

- After the game input is ticked the physics manager is ticked.

- The physics manager applies gravity to the physics object. It just adds a downwards velocity of -9.81 * framedelta to the physics object velocity. This allows the gravity to accelerate it down.

- The physics manager then checks for whether the physics object hits the ground. Since i am only doing this for the player, i just cast a ray, find the height off the ground and adjust.

- Next the physics manager checks whether the physics object is colliding with any of the walls etc. I cast more rays for this and adjust the movement vector to be parallel with the wall at the reduced speed.

- Finally, once the physics objects velocity has been fine tuned by the various stages, i apply the change in position.

Now the problem that has arisen is that because the wall intersection code stops the physics object (it does this be overwriting the velocity based on the collision), when the game input code gets ticked next frame it removes it's last frame of input (to prevent accumulation remember) causing the object to move in the opposite direction to the last frames controller direction.

Have i overcomplicated this? In terms of code it is pretty simply implemented but i cant think of an elegant solution to combining the affects of forces with the impulses of the controller.

Any ideas what i have done wrong or where to go from here?

Thanks alot.
dave
dave
Hmm, probably best moved to the Maths & Physics forum.

Thanks,
Ashaman73
Ashaman73
I need to look up my code, but I can't access it at the moment. From what I remember you should try to damp unwished velocities instead of removing them. When you remove your velocity try something like this:
vec3 last_velocity = ...vec3 normalized_last_velocity = normalize(last_velocity);// determine current "speed" in direction of the last velocityfloat speed = dot(normalized_last_velocity,current_velocity);// limit speed to last velocityspeed = min(speed, length(last_velocity) );// determine damp factorfloat damp = detmerineDampFactor( time); // [0..1], i.e. 0.8f// neutralize last velocitycurrent_velocity -= normalized_last_velocity * speed * damp;
Ashaman73
Ashaman73
Ok, I've looked up my code, here it is (based on bullet physics):
			// delta time			BtFloat deltaTime = BtFloat(m_stepSize) * 0.001f;			// update rotation around y-axis (=control.y)			BtFloat turning = _object.m_controlVector.getX() - controlForce.getX()*deltaTime;			turning = BsMath::modulus(turning,360.0f);			_object.m_controlVector.setX( turning);			// update bullet rotation			bulletOrientation.setRotation (btQuaternion (btVector3(0.0, 1.0, 0.0), turning*BD_MATH_PI/180.0f));			// get current speed			btVector3 linearVelocity	= body->getLinearVelocity();			btScalar speed 				= linearVelocity.length();			// on ground			BtBool onGround				= lambdaD<= (hitDistance+ON_GROUND_DISTACE);//			BtBool infrontOfWall		= lambdaF<= (hitDistance+0.01f);			// move at all and on ground(lambda&lt1) ?			if (controlForce.getY()==0.0f && controlForce.getZ()==0.0f && onGround)			{							// Dampen 				linearVelocity *= btScalar(0.2);				body->setLinearVelocity (linearVelocity);			} 			else 			{//todo: get max velocity from kinetic props ? (transfered)								if (speed < maxVelocity)				{					// new velocity					btVector3 newVelocity		= right * controlForce.getY()*deltaTime + forward * controlForce.getZ()*deltaTime;					btVector3 direction			= newVelocity;					direction.normalize();					btVector3 moveVelocity		= direction * dot(direction,linearVelocity);// * (infrontOfWall ? 0.3f : 1.0f);					btVector3 sideVelocity		= linearVelocity-moveVelocity;					btScalar sideDampValue		= onGround ? 0.3f : 1.0f;					btVector3 velocity =	moveVelocity + sideVelocity * sideDampValue + newVelocity;					body->setLinearVelocity (velocity);				}			}
dave
dave
So im still looking at this problem. Getting the correct reaction with the wall (causing the slide) is fine, that was always working. I fully understand how to have the forces acting on a body move it. Thats all working fine too, gravity for example is fine.

The question i have is, how should the input from the keyboard affect the body? Should it add a force to it that is resolved along with gravity to produce the final velocity? Should it modify the velocity of the object directly? If it should? What do i do when i release the forward key for example? How do i un-affect the velocity if i dont know what it was when i was affecting it.

Thanks again!
Ashaman73
Ashaman73
I needed a few years of tweaking until I was happy with the way to control the player by direct keyboard input based on a physics engine.

Quote:
Original post by Dave
The question i have is, how should the input from the keyboard affect the body?

I started with appling forces, but this never worked for me. As you can see in my code fragment I'm using velocity instead of forces.

Quote:
Original post by Dave
Should it add a force to it that is resolved along with gravity to produce the final velocity? Should it modify the velocity of the object directly?

Applying forces worked for vehicles, planes etc. but not for humanoids. Human like beings are not really accelerating or sliding, except fast running or on ice. So, try to modify the velocity directly.

Quote:
Original post by Dave
If it should? What do i do when i release the forward key for example?
How do i un-affect the velocity if i dont know what it was when i was affecting it.

When you release the key, don't apply a counter velocity which is as strong as the one in the last frame. This often results in jittering, wall bumping etc. Take the current velocity and damp it. To simulate a human being, I damp the current velocity only, if he stands on the ground (a simple raycast from the body center to the feet + X works quite fine). A simple current_velo *= damp_factor is enough to get a fast stop. A human being does not slide, so fast stopping feels more naturally. This will automatically prevent a human being of sliding down a ramp, because the velocity resulting from gravity will be damped too. But this is a desired effect, isn't it ?

I think that you want to apply forces (falling down, being shoot by a shotgun etc) and control the player directly. I think that this does not work in a generic way. So you can't have a simple apply X forces consisting of direct control and external effects. A lot of tweaking and faking is necessary, because a human being or some other creature doesn't behave like a rigid body. To get it handled right you need to switch between different control states. One example is to apply only direct control if the player has his feets on the ground. If you want to apply a shotgun effect, you need to turn off direct control for a few seconds.

Maybe there's a better way, but I didn't found it sofar :-)

dave
dave
Hi,

Thats basically how i ended up doing it.

Thanks for the help,

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.