mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-29 20:23:04 +02:00
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:
parent
e9fd439ffd
commit
61c55ebf6c
8 changed files with 62 additions and 58 deletions
|
@ -1510,7 +1510,8 @@ void MyAvatar::updatePosition(float deltaTime) {
|
||||||
// rotate velocity into camera frame
|
// rotate velocity into camera frame
|
||||||
glm::quat rotation = getHead()->getCameraOrientation();
|
glm::quat rotation = getHead()->getCameraOrientation();
|
||||||
glm::vec3 localVelocity = glm::inverse(rotation) * _targetVelocity;
|
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);
|
newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity);
|
||||||
|
|
||||||
// rotate back into world-frame
|
// rotate back into world-frame
|
||||||
|
@ -1579,10 +1580,6 @@ bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MyAvatar::isHovering() const {
|
|
||||||
return _characterController.isHovering();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyAvatar::increaseSize() {
|
void MyAvatar::increaseSize() {
|
||||||
if ((1.0f + SCALING_RATIO) * _targetScale < MAX_AVATAR_SCALE) {
|
if ((1.0f + SCALING_RATIO) * _targetScale < MAX_AVATAR_SCALE) {
|
||||||
_targetScale *= (1.0f + SCALING_RATIO);
|
_targetScale *= (1.0f + SCALING_RATIO);
|
||||||
|
|
|
@ -239,8 +239,6 @@ public:
|
||||||
glm::quat getCustomListenOrientation() { return _customListenOrientation; }
|
glm::quat getCustomListenOrientation() { return _customListenOrientation; }
|
||||||
void setCustomListenOrientation(glm::quat customListenOrientation) { _customListenOrientation = customListenOrientation; }
|
void setCustomListenOrientation(glm::quat customListenOrientation) { _customListenOrientation = customListenOrientation; }
|
||||||
|
|
||||||
bool isHovering() const;
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void increaseSize();
|
void increaseSize();
|
||||||
void decreaseSize();
|
void decreaseSize();
|
||||||
|
|
|
@ -67,7 +67,7 @@ void MyCharacterController::updateShapeIfNecessary() {
|
||||||
_rigidBody->setAngularFactor(0.0f);
|
_rigidBody->setAngularFactor(0.0f);
|
||||||
_rigidBody->setWorldTransform(btTransform(glmToBullet(_avatar->getOrientation()),
|
_rigidBody->setWorldTransform(btTransform(glmToBullet(_avatar->getOrientation()),
|
||||||
glmToBullet(_avatar->getPosition())));
|
glmToBullet(_avatar->getPosition())));
|
||||||
if (_isHovering) {
|
if (_state == State::Hover) {
|
||||||
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
|
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
|
||||||
} else {
|
} else {
|
||||||
_rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp);
|
_rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp);
|
||||||
|
|
|
@ -72,6 +72,18 @@ void SkeletonModel::initJointStates() {
|
||||||
emit skeletonLoaded();
|
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.
|
// Called within Model::simulate call, below.
|
||||||
void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
||||||
Head* head = _owningAvatar->getHead();
|
Head* head = _owningAvatar->getHead();
|
||||||
|
@ -133,13 +145,7 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
||||||
|
|
||||||
_rig->updateFromHandParameters(handParams, deltaTime);
|
_rig->updateFromHandParameters(handParams, deltaTime);
|
||||||
|
|
||||||
Rig::CharacterControllerState ccState = Rig::CharacterControllerState::Ground;
|
Rig::CharacterControllerState ccState = convertCharacterControllerState(myAvatar->getCharacterController()->getState());
|
||||||
if (myAvatar->getCharacterController()->isHovering()) {
|
|
||||||
ccState = Rig::CharacterControllerState::Hover;
|
|
||||||
} else if (myAvatar->getCharacterController()->isJumping()) {
|
|
||||||
ccState = Rig::CharacterControllerState::Jump;
|
|
||||||
}
|
|
||||||
|
|
||||||
_rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation(), ccState);
|
_rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation(), ccState);
|
||||||
|
|
||||||
// evaluate AnimGraph animation and update jointStates.
|
// evaluate AnimGraph animation and update jointStates.
|
||||||
|
|
|
@ -577,11 +577,11 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
|
||||||
_desiredStateAge = 0.0f;
|
_desiredStateAge = 0.0f;
|
||||||
}
|
}
|
||||||
_desiredState = RigRole::Hover;
|
_desiredState = RigRole::Hover;
|
||||||
} else if (ccState == CharacterControllerState::Jump) {
|
} else if (ccState == CharacterControllerState::InAir) {
|
||||||
if (_desiredState != RigRole::Jump) {
|
if (_desiredState != RigRole::InAir) {
|
||||||
_desiredStateAge = 0.0f;
|
_desiredStateAge = 0.0f;
|
||||||
}
|
}
|
||||||
_desiredState = RigRole::Jump;
|
_desiredState = RigRole::InAir;
|
||||||
} else {
|
} else {
|
||||||
float moveThresh;
|
float moveThresh;
|
||||||
if (_state != RigRole::Move) {
|
if (_state != RigRole::Move) {
|
||||||
|
@ -719,7 +719,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
|
||||||
_animVars.set("isNotFlying", false);
|
_animVars.set("isNotFlying", false);
|
||||||
_animVars.set("isInAir", false);
|
_animVars.set("isInAir", false);
|
||||||
_animVars.set("isNotInAir", true);
|
_animVars.set("isNotInAir", true);
|
||||||
} else if (_state == RigRole::Jump) {
|
} else if (_state == RigRole::InAir) {
|
||||||
// jumping in-air
|
// jumping in-air
|
||||||
_animVars.set("isMovingForward", false);
|
_animVars.set("isMovingForward", false);
|
||||||
_animVars.set("isMovingBackward", false);
|
_animVars.set("isMovingBackward", false);
|
||||||
|
|
|
@ -75,7 +75,7 @@ public:
|
||||||
|
|
||||||
enum class CharacterControllerState {
|
enum class CharacterControllerState {
|
||||||
Ground = 0,
|
Ground = 0,
|
||||||
Jump,
|
InAir,
|
||||||
Hover
|
Hover
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -278,7 +278,7 @@ public:
|
||||||
Turn,
|
Turn,
|
||||||
Move,
|
Move,
|
||||||
Hover,
|
Hover,
|
||||||
Jump
|
InAir
|
||||||
};
|
};
|
||||||
RigRole _state { RigRole::Idle };
|
RigRole _state { RigRole::Idle };
|
||||||
RigRole _desiredState { RigRole::Idle };
|
RigRole _desiredState { RigRole::Idle };
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//
|
//
|
||||||
// CharacterControllerInterface.cpp
|
// CharacterControllerInterface.cpp
|
||||||
// libraries/physcis/src
|
// libraries/physcis/src
|
||||||
//
|
//
|
||||||
|
@ -51,10 +51,7 @@ CharacterController::CharacterController() {
|
||||||
_followDesiredBodyTransform.setIdentity();
|
_followDesiredBodyTransform.setIdentity();
|
||||||
_followTimeRemaining = 0.0f;
|
_followTimeRemaining = 0.0f;
|
||||||
_jumpSpeed = JUMP_SPEED;
|
_jumpSpeed = JUMP_SPEED;
|
||||||
_isOnGround = false;
|
_state = State::Hover;
|
||||||
_isJumping = false;
|
|
||||||
_isFalling = false;
|
|
||||||
_isHovering = true;
|
|
||||||
_isPushingUp = false;
|
_isPushingUp = false;
|
||||||
_jumpToHoverStart = 0;
|
_jumpToHoverStart = 0;
|
||||||
_followTime = 0.0f;
|
_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 {
|
bool CharacterController::checkForSupport(btCollisionWorld* collisionWorld) const {
|
||||||
int numManifolds = collisionWorld->getDispatcher()->getNumManifolds();
|
int numManifolds = collisionWorld->getDispatcher()->getNumManifolds();
|
||||||
for (int i = 0; i < numManifolds; i++) {
|
for (int i = 0; i < numManifolds; i++) {
|
||||||
|
@ -119,8 +118,10 @@ bool CharacterController::checkForSupport(btCollisionWorld* collisionWorld) cons
|
||||||
btManifoldPoint& pt = contactManifold->getContactPoint(j);
|
btManifoldPoint& pt = contactManifold->getContactPoint(j);
|
||||||
|
|
||||||
// check to see if contact point is touching the bottom sphere of the capsule.
|
// 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();
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,7 +166,7 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const btScalar MIN_SPEED = 0.001f;
|
const btScalar MIN_SPEED = 0.001f;
|
||||||
if (_isHovering) {
|
if (_state == State::Hover) {
|
||||||
if (desiredSpeed < MIN_SPEED) {
|
if (desiredSpeed < MIN_SPEED) {
|
||||||
if (actualSpeed < MIN_SPEED) {
|
if (actualSpeed < MIN_SPEED) {
|
||||||
_rigidBody->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f));
|
_rigidBody->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f));
|
||||||
|
@ -255,9 +256,9 @@ 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 tansition to "hover"
|
// we'll eventually transition to "hover"
|
||||||
if (!_isJumping) {
|
if (_state != State::InAir) {
|
||||||
if (!_isHovering) {
|
if (_state != State::Hover) {
|
||||||
_jumpToHoverStart = usecTimestampNow();
|
_jumpToHoverStart = usecTimestampNow();
|
||||||
_pendingFlags |= PENDING_FLAG_JUMP;
|
_pendingFlags |= PENDING_FLAG_JUMP;
|
||||||
}
|
}
|
||||||
|
@ -266,7 +267,7 @@ void CharacterController::jump() {
|
||||||
const quint64 JUMP_TO_HOVER_PERIOD = 75 * (USECS_PER_SECOND / 100);
|
const quint64 JUMP_TO_HOVER_PERIOD = 75 * (USECS_PER_SECOND / 100);
|
||||||
if (now - _jumpToHoverStart > JUMP_TO_HOVER_PERIOD) {
|
if (now - _jumpToHoverStart > JUMP_TO_HOVER_PERIOD) {
|
||||||
_isPushingUp = true;
|
_isPushingUp = true;
|
||||||
setHovering(true);
|
setState(State::Hover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -276,19 +277,19 @@ bool CharacterController::onGround() const {
|
||||||
return _floorDistance < FLOOR_PROXIMITY_THRESHOLD || _hasSupport;
|
return _floorDistance < FLOOR_PROXIMITY_THRESHOLD || _hasSupport;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::setHovering(bool hover) {
|
void CharacterController::setState(State desiredState) {
|
||||||
if (hover != _isHovering) {
|
if (desiredState == State::Hover && _state != State::Hover) {
|
||||||
_isHovering = hover;
|
// hover enter
|
||||||
_isJumping = false;
|
|
||||||
|
|
||||||
if (_rigidBody) {
|
if (_rigidBody) {
|
||||||
if (hover) {
|
|
||||||
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
|
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
|
||||||
} else {
|
}
|
||||||
|
} else if (_state == State::Hover && desiredState != State::Hover) {
|
||||||
|
// hover exit
|
||||||
|
if (_rigidBody) {
|
||||||
_rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp);
|
_rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
_state = desiredState;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale) {
|
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_REMOVE_FROM_SIMULATION;
|
||||||
}
|
}
|
||||||
_pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION;
|
_pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION;
|
||||||
_isOnGround = false;
|
|
||||||
}
|
}
|
||||||
setHovering(true);
|
setState(State::Hover);
|
||||||
_enabled = enabled;
|
_enabled = enabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -345,7 +345,7 @@ void CharacterController::setEnabled(bool enabled) {
|
||||||
void CharacterController::updateUpAxis(const glm::quat& rotation) {
|
void CharacterController::updateUpAxis(const glm::quat& rotation) {
|
||||||
btVector3 oldUp = _currentUp;
|
btVector3 oldUp = _currentUp;
|
||||||
_currentUp = quatRotate(glmToBullet(rotation), LOCAL_UP_AXIS);
|
_currentUp = quatRotate(glmToBullet(rotation), LOCAL_UP_AXIS);
|
||||||
if (!_isHovering) {
|
if (_state != State::Hover) {
|
||||||
const btScalar MIN_UP_ERROR = 0.01f;
|
const btScalar MIN_UP_ERROR = 0.01f;
|
||||||
if (oldUp.distance(_currentUp) > MIN_UP_ERROR) {
|
if (oldUp.distance(_currentUp) > MIN_UP_ERROR) {
|
||||||
_rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp);
|
_rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp);
|
||||||
|
@ -425,23 +425,23 @@ void CharacterController::preSimulation() {
|
||||||
if (rayCallback.hasHit()) {
|
if (rayCallback.hasHit()) {
|
||||||
_floorDistance = rayLength * rayCallback.m_closestHitFraction - _radius;
|
_floorDistance = rayLength * rayCallback.m_closestHitFraction - _radius;
|
||||||
const btScalar MIN_HOVER_HEIGHT = 3.0f;
|
const btScalar MIN_HOVER_HEIGHT = 3.0f;
|
||||||
if (_isHovering && _floorDistance < MIN_HOVER_HEIGHT && !_isPushingUp) {
|
if (_state == State::Hover && _floorDistance < MIN_HOVER_HEIGHT && !_isPushingUp) {
|
||||||
setHovering(false);
|
setState(State::InAir);
|
||||||
}
|
}
|
||||||
// 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 (_floorDistance < JUMP_PROXIMITY_THRESHOLD) {
|
if (_floorDistance < JUMP_PROXIMITY_THRESHOLD || _hasSupport) {
|
||||||
_isJumping = false;
|
setState(State::Ground);
|
||||||
}
|
}
|
||||||
} else if (!_hasSupport) {
|
} else if (!_hasSupport) {
|
||||||
_floorDistance = FLT_MAX;
|
_floorDistance = FLT_MAX;
|
||||||
setHovering(true);
|
setState(State::Hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_pendingFlags & PENDING_FLAG_JUMP) {
|
if (_pendingFlags & PENDING_FLAG_JUMP) {
|
||||||
_pendingFlags &= ~ PENDING_FLAG_JUMP;
|
_pendingFlags &= ~ PENDING_FLAG_JUMP;
|
||||||
if (onGround()) {
|
if (onGround()) {
|
||||||
_isJumping = true;
|
setState(State::InAir);
|
||||||
btVector3 velocity = _rigidBody->getLinearVelocity();
|
btVector3 velocity = _rigidBody->getLinearVelocity();
|
||||||
velocity += _jumpSpeed * _currentUp;
|
velocity += _jumpSpeed * _currentUp;
|
||||||
_rigidBody->setLinearVelocity(velocity);
|
_rigidBody->setLinearVelocity(velocity);
|
||||||
|
|
|
@ -75,9 +75,13 @@ public:
|
||||||
|
|
||||||
glm::vec3 getLinearVelocity() const;
|
glm::vec3 getLinearVelocity() const;
|
||||||
|
|
||||||
bool isJumping() const { return _isJumping; }
|
enum class State {
|
||||||
bool isHovering() const { return _isHovering; }
|
Ground = 0,
|
||||||
void setHovering(bool enabled);
|
InAir,
|
||||||
|
Hover
|
||||||
|
};
|
||||||
|
|
||||||
|
State getState() const { return _state; }
|
||||||
|
|
||||||
void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale);
|
void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale);
|
||||||
|
|
||||||
|
@ -87,6 +91,8 @@ public:
|
||||||
bool getRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation);
|
bool getRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void setState(State state);
|
||||||
|
|
||||||
void updateUpAxis(const glm::quat& rotation);
|
void updateUpAxis(const glm::quat& rotation);
|
||||||
bool checkForSupport(btCollisionWorld* collisionWorld) const;
|
bool checkForSupport(btCollisionWorld* collisionWorld) const;
|
||||||
|
|
||||||
|
@ -117,10 +123,7 @@ protected:
|
||||||
btQuaternion _followAngularDisplacement;
|
btQuaternion _followAngularDisplacement;
|
||||||
|
|
||||||
bool _enabled;
|
bool _enabled;
|
||||||
bool _isOnGround;
|
State _state;
|
||||||
bool _isJumping;
|
|
||||||
bool _isFalling;
|
|
||||||
bool _isHovering;
|
|
||||||
bool _isPushingUp;
|
bool _isPushingUp;
|
||||||
|
|
||||||
btDynamicsWorld* _dynamicsWorld { nullptr };
|
btDynamicsWorld* _dynamicsWorld { nullptr };
|
||||||
|
|
Loading…
Reference in a new issue