Updated character controller with a state enumeration

Also, adjusted checkForSupport logic such that very slanted walls are not considered support.
This commit is contained in:
Anthony J. Thibault 2016-01-29 11:57:14 -08:00
parent e9fd439ffd
commit 61c55ebf6c
8 changed files with 62 additions and 58 deletions

View file

@ -1510,7 +1510,8 @@ void MyAvatar::updatePosition(float deltaTime) {
// rotate velocity into camera frame
glm::quat rotation = getHead()->getCameraOrientation();
glm::vec3 localVelocity = glm::inverse(rotation) * _targetVelocity;
glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isHovering());
bool isHovering = _characterController.getState() == CharacterController::State::Hover;
glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isHovering);
newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity);
// rotate back into world-frame
@ -1579,10 +1580,6 @@ bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float
return false;
}
bool MyAvatar::isHovering() const {
return _characterController.isHovering();
}
void MyAvatar::increaseSize() {
if ((1.0f + SCALING_RATIO) * _targetScale < MAX_AVATAR_SCALE) {
_targetScale *= (1.0f + SCALING_RATIO);

View file

@ -239,8 +239,6 @@ public:
glm::quat getCustomListenOrientation() { return _customListenOrientation; }
void setCustomListenOrientation(glm::quat customListenOrientation) { _customListenOrientation = customListenOrientation; }
bool isHovering() const;
public slots:
void increaseSize();
void decreaseSize();

View file

@ -67,7 +67,7 @@ void MyCharacterController::updateShapeIfNecessary() {
_rigidBody->setAngularFactor(0.0f);
_rigidBody->setWorldTransform(btTransform(glmToBullet(_avatar->getOrientation()),
glmToBullet(_avatar->getPosition())));
if (_isHovering) {
if (_state == State::Hover) {
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
} else {
_rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp);

View file

@ -72,6 +72,18 @@ void SkeletonModel::initJointStates() {
emit skeletonLoaded();
}
Rig::CharacterControllerState convertCharacterControllerState(CharacterController::State state) {
switch (state) {
default:
case CharacterController::State::Ground:
return Rig::CharacterControllerState::Ground;
case CharacterController::State::InAir:
return Rig::CharacterControllerState::InAir;
case CharacterController::State::Hover:
return Rig::CharacterControllerState::Hover;
};
}
// Called within Model::simulate call, below.
void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
Head* head = _owningAvatar->getHead();
@ -133,13 +145,7 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
_rig->updateFromHandParameters(handParams, deltaTime);
Rig::CharacterControllerState ccState = Rig::CharacterControllerState::Ground;
if (myAvatar->getCharacterController()->isHovering()) {
ccState = Rig::CharacterControllerState::Hover;
} else if (myAvatar->getCharacterController()->isJumping()) {
ccState = Rig::CharacterControllerState::Jump;
}
Rig::CharacterControllerState ccState = convertCharacterControllerState(myAvatar->getCharacterController()->getState());
_rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation(), ccState);
// evaluate AnimGraph animation and update jointStates.

View file

@ -577,11 +577,11 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_desiredStateAge = 0.0f;
}
_desiredState = RigRole::Hover;
} else if (ccState == CharacterControllerState::Jump) {
if (_desiredState != RigRole::Jump) {
} else if (ccState == CharacterControllerState::InAir) {
if (_desiredState != RigRole::InAir) {
_desiredStateAge = 0.0f;
}
_desiredState = RigRole::Jump;
_desiredState = RigRole::InAir;
} else {
float moveThresh;
if (_state != RigRole::Move) {
@ -719,7 +719,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isNotFlying", false);
_animVars.set("isInAir", false);
_animVars.set("isNotInAir", true);
} else if (_state == RigRole::Jump) {
} else if (_state == RigRole::InAir) {
// jumping in-air
_animVars.set("isMovingForward", false);
_animVars.set("isMovingBackward", false);

View file

@ -75,7 +75,7 @@ public:
enum class CharacterControllerState {
Ground = 0,
Jump,
InAir,
Hover
};
@ -278,7 +278,7 @@ public:
Turn,
Move,
Hover,
Jump
InAir
};
RigRole _state { RigRole::Idle };
RigRole _desiredState { RigRole::Idle };

View file

@ -1,4 +1,4 @@
//
//
// CharacterControllerInterface.cpp
// libraries/physcis/src
//
@ -51,10 +51,7 @@ CharacterController::CharacterController() {
_followDesiredBodyTransform.setIdentity();
_followTimeRemaining = 0.0f;
_jumpSpeed = JUMP_SPEED;
_isOnGround = false;
_isJumping = false;
_isFalling = false;
_isHovering = true;
_state = State::Hover;
_isPushingUp = false;
_jumpToHoverStart = 0;
_followTime = 0.0f;
@ -107,6 +104,8 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) {
}
}
static const float COS_PI_OVER_THREE = cosf(PI / 3.0f);
bool CharacterController::checkForSupport(btCollisionWorld* collisionWorld) const {
int numManifolds = collisionWorld->getDispatcher()->getNumManifolds();
for (int i = 0; i < numManifolds; i++) {
@ -119,8 +118,10 @@ bool CharacterController::checkForSupport(btCollisionWorld* collisionWorld) cons
btManifoldPoint& pt = contactManifold->getContactPoint(j);
// check to see if contact point is touching the bottom sphere of the capsule.
// and the contact normal is not slanted too much.
float contactPointY = (obA == _rigidBody) ? pt.m_localPointA.getY() : pt.m_localPointB.getY();
if (contactPointY < -_halfHeight) {
btVector3 normal = (obA == _rigidBody) ? pt.m_normalWorldOnB : -pt.m_normalWorldOnB;
if (contactPointY < -_halfHeight && normal.dot(_currentUp) > COS_PI_OVER_THREE) {
return true;
}
}
@ -165,7 +166,7 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) {
}
const btScalar MIN_SPEED = 0.001f;
if (_isHovering) {
if (_state == State::Hover) {
if (desiredSpeed < MIN_SPEED) {
if (actualSpeed < MIN_SPEED) {
_rigidBody->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f));
@ -255,9 +256,9 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) {
void CharacterController::jump() {
// check for case where user is holding down "jump" key...
// we'll eventually tansition to "hover"
if (!_isJumping) {
if (!_isHovering) {
// we'll eventually transition to "hover"
if (_state != State::InAir) {
if (_state != State::Hover) {
_jumpToHoverStart = usecTimestampNow();
_pendingFlags |= PENDING_FLAG_JUMP;
}
@ -266,7 +267,7 @@ void CharacterController::jump() {
const quint64 JUMP_TO_HOVER_PERIOD = 75 * (USECS_PER_SECOND / 100);
if (now - _jumpToHoverStart > JUMP_TO_HOVER_PERIOD) {
_isPushingUp = true;
setHovering(true);
setState(State::Hover);
}
}
}
@ -276,19 +277,19 @@ bool CharacterController::onGround() const {
return _floorDistance < FLOOR_PROXIMITY_THRESHOLD || _hasSupport;
}
void CharacterController::setHovering(bool hover) {
if (hover != _isHovering) {
_isHovering = hover;
_isJumping = false;
void CharacterController::setState(State desiredState) {
if (desiredState == State::Hover && _state != State::Hover) {
// hover enter
if (_rigidBody) {
if (hover) {
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
} else {
_rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp);
}
_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;
}
void CharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale) {
@ -335,9 +336,8 @@ void CharacterController::setEnabled(bool enabled) {
_pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION;
}
_pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION;
_isOnGround = false;
}
setHovering(true);
setState(State::Hover);
_enabled = enabled;
}
}
@ -345,7 +345,7 @@ void CharacterController::setEnabled(bool enabled) {
void CharacterController::updateUpAxis(const glm::quat& rotation) {
btVector3 oldUp = _currentUp;
_currentUp = quatRotate(glmToBullet(rotation), LOCAL_UP_AXIS);
if (!_isHovering) {
if (_state != State::Hover) {
const btScalar MIN_UP_ERROR = 0.01f;
if (oldUp.distance(_currentUp) > MIN_UP_ERROR) {
_rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp);
@ -425,23 +425,23 @@ void CharacterController::preSimulation() {
if (rayCallback.hasHit()) {
_floorDistance = rayLength * rayCallback.m_closestHitFraction - _radius;
const btScalar MIN_HOVER_HEIGHT = 3.0f;
if (_isHovering && _floorDistance < MIN_HOVER_HEIGHT && !_isPushingUp) {
setHovering(false);
if (_state == State::Hover && _floorDistance < MIN_HOVER_HEIGHT && !_isPushingUp) {
setState(State::InAir);
}
// TODO: use collision events rather than ray-trace test to disable jumping
const btScalar JUMP_PROXIMITY_THRESHOLD = 0.1f * _radius;
if (_floorDistance < JUMP_PROXIMITY_THRESHOLD) {
_isJumping = false;
if (_floorDistance < JUMP_PROXIMITY_THRESHOLD || _hasSupport) {
setState(State::Ground);
}
} else if (!_hasSupport) {
_floorDistance = FLT_MAX;
setHovering(true);
setState(State::Hover);
}
if (_pendingFlags & PENDING_FLAG_JUMP) {
_pendingFlags &= ~ PENDING_FLAG_JUMP;
if (onGround()) {
_isJumping = true;
setState(State::InAir);
btVector3 velocity = _rigidBody->getLinearVelocity();
velocity += _jumpSpeed * _currentUp;
_rigidBody->setLinearVelocity(velocity);

View file

@ -75,9 +75,13 @@ public:
glm::vec3 getLinearVelocity() const;
bool isJumping() const { return _isJumping; }
bool isHovering() const { return _isHovering; }
void setHovering(bool enabled);
enum class State {
Ground = 0,
InAir,
Hover
};
State getState() const { return _state; }
void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale);
@ -87,6 +91,8 @@ public:
bool getRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation);
protected:
void setState(State state);
void updateUpAxis(const glm::quat& rotation);
bool checkForSupport(btCollisionWorld* collisionWorld) const;
@ -117,10 +123,7 @@ protected:
btQuaternion _followAngularDisplacement;
bool _enabled;
bool _isOnGround;
bool _isJumping;
bool _isFalling;
bool _isHovering;
State _state;
bool _isPushingUp;
btDynamicsWorld* _dynamicsWorld { nullptr };