CharacterController jump is more reliable.

This commit is contained in:
Anthony J. Thibault 2016-02-01 14:18:30 -08:00
parent 2936811484
commit 47f3ce3786
2 changed files with 61 additions and 26 deletions

View file

@ -624,6 +624,13 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
const float STATE_CHANGE_HYSTERESIS_TIMER = 0.1f; const float STATE_CHANGE_HYSTERESIS_TIMER = 0.1f;
// Skip hystersis timer for jump transitions.
if (_desiredState == RigRole::Takeoff) {
_desiredStateAge = STATE_CHANGE_HYSTERESIS_TIMER;
} else if (_state == RigRole::InAir && _desiredState != RigRole::InAir) {
_desiredStateAge = STATE_CHANGE_HYSTERESIS_TIMER;
}
if ((_desiredStateAge >= STATE_CHANGE_HYSTERESIS_TIMER) && _desiredState != _state) { if ((_desiredStateAge >= STATE_CHANGE_HYSTERESIS_TIMER) && _desiredState != _state) {
_state = _desiredState; _state = _desiredState;
_desiredStateAge = 0.0f; _desiredStateAge = 0.0f;

View file

@ -1,4 +1,4 @@
// //
// CharacterControllerInterface.cpp // CharacterControllerInterface.cpp
// libraries/physcis/src // libraries/physcis/src
// //
@ -15,11 +15,14 @@
#include "PhysicsCollisionGroups.h" #include "PhysicsCollisionGroups.h"
#include "ObjectMotionState.h" #include "ObjectMotionState.h"
#include "PhysicsLogging.h"
const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f); const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f);
const float JUMP_SPEED = 3.5f; const float JUMP_SPEED = 3.5f;
const float MAX_FALL_HEIGHT = 20.0f; const float MAX_FALL_HEIGHT = 20.0f;
#define DEBUG_STATE_CHANGE
// helper class for simple ray-traces from character // helper class for simple ray-traces from character
class ClosestNotMe : public btCollisionWorld::ClosestRayResultCallback { class ClosestNotMe : public btCollisionWorld::ClosestRayResultCallback {
public: public:
@ -220,7 +223,7 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) {
// Dynamicaly compute a follow velocity to move this body toward the _followDesiredBodyTransform. // Dynamicaly compute a follow velocity to move this body toward the _followDesiredBodyTransform.
// Rather then add this velocity to velocity the RigidBody, we explicitly teleport the RigidBody towards its goal. // Rather then add this velocity to velocity the RigidBody, we explicitly teleport the RigidBody towards its goal.
// This mirrors the computation done in MyAvatar::FollowHelper::postPhysicsUpdate(). // This mirrors the computation done in MyAvatar::FollowHelper::postPhysicsUpdate().
// These two computations must be kept in sync.
const float MINIMUM_TIME_REMAINING = 0.005f; const float MINIMUM_TIME_REMAINING = 0.005f;
const float MAX_DISPLACEMENT = 0.5f * _radius; const float MAX_DISPLACEMENT = 0.5f * _radius;
_followTimeRemaining -= dt; _followTimeRemaining -= dt;
@ -258,18 +261,21 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) {
void CharacterController::jump() { void CharacterController::jump() {
// check for case where user is holding down "jump" key... // check for case where user is holding down "jump" key...
// we'll eventually transition to "hover" // we'll eventually transition to "hover"
if (_state == State::Hover) { if (_state != State::Takeoff) {
quint64 now = usecTimestampNow(); if (_state == State::InAir) {
const quint64 JUMP_TO_HOVER_PERIOD = 75 * (USECS_PER_SECOND / 100); quint64 now = usecTimestampNow();
if (now - _jumpToHoverStart > JUMP_TO_HOVER_PERIOD) { if (!_isPushingUp) {
_isPushingUp = true; _isPushingUp = true;
setState(State::Hover); _jumpToHoverStart = now;
} }
} else { const quint64 JUMP_TO_HOVER_PERIOD = 750 * MSECS_PER_SECOND;
if (_state != State::Takeoff) { if (now - _jumpToHoverStart > JUMP_TO_HOVER_PERIOD) {
_jumpToHoverStart = usecTimestampNow(); setState(State::Hover);
}
} else {
_pendingFlags |= PENDING_FLAG_JUMP; _pendingFlags |= PENDING_FLAG_JUMP;
} }
} }
} }
@ -278,19 +284,41 @@ bool CharacterController::onGround() const {
return _floorDistance < FLOOR_PROXIMITY_THRESHOLD || _hasSupport; return _floorDistance < FLOOR_PROXIMITY_THRESHOLD || _hasSupport;
} }
void CharacterController::setState(State desiredState) { #ifdef DEBUG_STATE_CHANGE
if (desiredState == State::Hover && _state != State::Hover) { static const char* stateToStr(CharacterController::State state) {
// hover enter switch (state) {
if (_rigidBody) { case CharacterController::State::Ground:
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f)); return "Ground";
} case CharacterController::State::Takeoff:
} else if (_state == State::Hover && desiredState != State::Hover) { return "Takeoff";
// hover exit case CharacterController::State::InAir:
if (_rigidBody) { return "InAir";
_rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp); case CharacterController::State::Hover:
} return "Hover";
default:
return "Unknown";
}
}
#endif // #ifdef DEBUG_STATE_CHANGE
void CharacterController::setState(State desiredState) {
if (desiredState != _state) {
#ifdef DEBUG_STATE_CHANGE
qCDebug(physics) << "CharacterController::setState" << stateToStr(desiredState) << "<-" << stateToStr(_state);
#endif
if (desiredState == State::Hover && _state != State::Hover) {
// hover enter
if (_rigidBody) {
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
}
} else if (_state == State::Hover && desiredState != State::Hover) {
// hover exit
if (_rigidBody) {
_rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp);
}
}
_state = desiredState;
} }
_state = desiredState;
} }
void CharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale) { void CharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale) {
@ -411,6 +439,7 @@ void CharacterController::preSimulation() {
if (_enabled && _dynamicsWorld) { if (_enabled && _dynamicsWorld) {
// slam body to where it is supposed to be // slam body to where it is supposed to be
_rigidBody->setWorldTransform(_characterBodyTransform); _rigidBody->setWorldTransform(_characterBodyTransform);
btVector3 velocity = _rigidBody->getLinearVelocity();
// scan for distant floor // scan for distant floor
// rayStart is at center of bottom sphere // rayStart is at center of bottom sphere
@ -431,7 +460,7 @@ void CharacterController::preSimulation() {
} }
// TODO: use collision events rather than ray-trace test to disable jumping // TODO: use collision events rather than ray-trace test to disable jumping
const btScalar JUMP_PROXIMITY_THRESHOLD = 0.1f * _radius; const btScalar JUMP_PROXIMITY_THRESHOLD = 0.1f * _radius;
if (_state != State::Takeoff && (_floorDistance < JUMP_PROXIMITY_THRESHOLD || _hasSupport)) { if (_state != State::Takeoff && (velocity.dot(_currentUp) <= (JUMP_SPEED / 2.0f)) && ((_floorDistance < JUMP_PROXIMITY_THRESHOLD) || _hasSupport)) {
setState(State::Ground); setState(State::Ground);
} }
} else if (!_hasSupport) { } else if (!_hasSupport) {
@ -454,7 +483,6 @@ void CharacterController::preSimulation() {
setState(State::InAir); setState(State::InAir);
_takeoffToInAirStart = now + USECS_PER_SECOND * 86500.0f; _takeoffToInAirStart = now + USECS_PER_SECOND * 86500.0f;
btVector3 velocity = _rigidBody->getLinearVelocity();
velocity += _jumpSpeed * _currentUp; velocity += _jumpSpeed * _currentUp;
_rigidBody->setLinearVelocity(velocity); _rigidBody->setLinearVelocity(velocity);
} }