I actually implemented it last night - similiar to what you are saying Raft. However you've reminded me I have to handle head collision. Here is all the collision code - it essentially checks for a jump offset during its gravity calculation and accounts for the height of the jump. Depending on the current animation frame I increment or decrement the height offset. So its the gravity calculation itself that causes the avatar to rise and fall because of the offset.
Also I added a smoothing factor to the Y axis transition where I don't allow anything greater than 7 in either direction. I did this because if the avatar steps off a small rise the camera jolts to follow the drastic change on the Y plane. Also, the avatar shouldnt transition on the Y axis instantaneously, that's not gravity! Seems to work nicely. I also terminate the jump animation if a plane is encountered. As an aside - the reason for the "blocking" boolean is because if the user releases the forward motion during a jump the animation wants to switch to "stand". I need to complete the jump. As soon as the avatar lands I release the boolean and the animation switches. Works nicely.
public void moveForward(Object3D terrain) {
SimpleVector vnew = _main.getZAxis();
vnew.scalarMul(speed);
SimpleVector vcoll = _main.checkForCollisionEllipsoid(vnew, _ellipsoid, 5);
boolean bNoHit = (vcoll.x == vnew.x && vcoll.z == vnew.z && vcoll.y == vnew.y);
vnew = vcoll;
vnew.y = 0;
_main.translate(checkGroundDynamics(vnew, terrain));
}
private SimpleVector checkGroundDynamics(SimpleVector vnew, Object3D terrain){
SimpleVector vret = null;
try{
SimpleVector vdist = new SimpleVector(0, 1, 0);
float fdist = terrain.calcMinDistance(_main.getTransformedCenter(), vdist);
if (fdist != Object3D.COLLISION_NONE) {
fdist -= 10;
vdist.scalarMul(fdist - 4);
float jump_offset = getJumpOffset();
float fdiff = (_height_offset + jump_offset) + vdist.y;
// end any jump if a surface was discovered - typically jumping
// to a higher plane will cause this....
if(fdiff == 0 && _blocking_animation)
_blocking_animation = false;
// simulate gravity and smooth the jarring movement upward as well.
// this may cause some minor clipping on slopes but its too jarring without it
// making jumps hard to control.
if(fdiff > SMOOTH_FACTOR_Y)
fdiff = SMOOTH_FACTOR_Y;
if(fdiff < (SMOOTH_FACTOR_Y * -1f))
fdiff = SMOOTH_FACTOR_Y * -1f;
vnew.y = fdiff;
}
vret = new SimpleVector(vnew);
}catch(Exception e){
System.err.println("CreatureComposite::checkGroundDynamics() " + e.getMessage());
e.printStackTrace();
}
return vret;
}
private float getJumpOffset(){
SimpleVector vret = null;
try{
if((_ai.name.equals(ANIM_JUMP1) || _ai.name.equals(ANIM_JUMP2)) && _blocking_animation){
float fdelta = 0f;
if(_ai.frame < _ai.duration/2f){
_ai.jump_offset -= _ai.jump_rate;
}else{
_ai.jump_offset += _ai.jump_rate;
}
}
}catch(Exception e){
System.err.println("CreatureComposite::checkJumpDynamics() " + e.getMessage());
e.printStackTrace();
}
return _ai.jump_offset;
}