I'm either not searching correctly or there is really not a lot of material on character movement in 3D games. I'm mostly interested in how people usually implement character movement in games like FPS and action games, where usually the WASD keys are used to move backward and forward and for strafing, with the mouse used for turning. I'd like to learn what methods are generally used, and what makes the movement handling feel right.
For example, I tried to implement movement handling using some 'walking' force to move my character, by integrating the equations of motion. Needless to say, this felt more like handling a spaceship, rather than a human. Others probably use just some velocity to steer the characters, maybe coupled with a deceleration when no buttons are pressed. I tried something similar in following code, but it still feels kinda clunky.
if(move_comps_[*entity]->mv_direction != glm::ivec3(0))
{
glm::vec3 mv_dir(0.0);
mv_dir += (float)move_comps_[*entity]- > mv_direction.z
* transform_comps_[*entity]->forwardVec();
mv_dir += (float)move_comps_[*entity]->mv_direction.x
* transform_comps_[*entity]->rightVec();
mv_dir = glm::normalize(mv_dir);
glm::vec3& velocity = move_comps_[*entity]->velocity_;
velocity += dt * move_comps_[*entity]->acceleration_ * mv_dir;
if(glm::dot(velocity, velocity) > sqr(move_comps_[*entity]->max_velocity_))
{
velocity = move_comps_[*entity]->max_velocity_ * mv_dir;
}
transform_comps_[*entity]->pos_ += dt * velocity + 0.5f
* move_comps_[*entity]->acceleration_ * sqr(dt) * mv_dir;
}
else if(glm::length(move_comps_[*entity]->velocity_) > 0.0)
{
glm::vec3& velocity = move_comps_[*entity]->velocity_;
glm::vec3 mv_dir = glm::normalize(velocity);
velocity -= dt * move_comps_[*entity]->acceleration_ * mv_dir;
if(glm::dot(velocity, velocity) < 0.01f)
{
velocity = glm::vec3(0.0);
}
else
{
transform_comps_[*entity]->pos_ += dt * velocity + 0.5f
* move_comps_[*entity]->acceleration_ * sqr(dt) * mv_dir;
}
}
Here in essence, I use an integer vector which can hold (-1, 0, 1) in each dimension. When a walk_forward_start
event is fired, for example, this z component is increased by 1 and decreased when the player releases the button. This vector is used to find out in which direction to move the player. I also added a simple deceleration mechanism. As I said, this still doesn't feel right, and is certainly not really smooth. What could I do to improve it?
Others have gone as far as implementing advanced techniques such as inverse kinematics, too. I wouldn't go that far, but how far do you have to go to make a movement system feel good?
Essentially, beyond the sauce, I want to know what makes pushing forward, strafing, turning and stopping feel smooth and what are some standard methods to achieve this. Do you use some impulse/force based method? Do you use a linear velocity method?
Note: This may seem like a subjective question and it might be up to some point, but I think there must be some general consensus or else there would be a big variations on how these controls are handled by games.