What I do is this:
I make the camera be a physical sphere, with collision, mass, velocity, etc. The only difference from a typical object is that the camera will NOT affect other objects when colliding. This is implemented such, that when the camera hits something else, I create a contact joint between the camera and the "static world" rather than between the camera and the other object.
The camera has a "desired position" that's 3 meters behind and 1 meter above the character's head (this is tuneable).
Each frame, I calculate the velocity I would need to get to the desired position in some time (this is tuneable). I call that "desired velocity".
I then calculate the amount of force I need to apply to the camera to get it to the desired velocity in this time step. I limit the force to a maximum camera acceleration force (this is tuneable), and apply this force to the camera ball.
The camera has some inertial and velocity dampening ("air drag") just like every other object in my world.
Then, when time comes to draw, I place the camera in the center of the ball, and point it at the center of the player character, with the world up being up (I have no roll control).
It is possible for the player to, say, walk through a swinging gate, and the gate swings back, hits the camera, and propels it like a baseball out of the court. To deal with this, I do a few things:
I don't allow the character itself to push the camera around (with collision).
I limit the maximum velocity of the camera to some multiple times maximum player run speed (say, 1.5 -- this is tuneable).
If the camera has been more than X meters away from the player for more than Y second (both are tuneable), I cut the camera to a snap position I explain below.
If the camera cannot see the character (a single ray test, although you could use more) for more than Z seconds (this is tuneable), I cut the camera to the same cut position.
The cut position is determined by placing the camera 1 cm behind the player look-at position (center of torso). I then shoot a ray from there, back towards the ideal position. I move the camera as far along the ray as I can without collision.
This all ends up working reasonably well, although a very intricate attic-crawling game probably would make the camera seem naff; it works better for RPG and open-space platformer type gameplay.
Some games will just fade out anything that's between the player and the camera, and let the camera extend into walls and stuff. That works pretty well, too, but means you need better controls in your renderer for what gets drawn how.
Also, the sphere of my camera ball has the same radius as my camera near plane distance, which means that the camera won't clip through geometry, which is a nice bonus.
|