mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 11:45:36 +02:00
improved management of collisionless avatar state
This commit is contained in:
parent
95a4bb9ef4
commit
fe401c7488
3 changed files with 68 additions and 65 deletions
|
@ -163,12 +163,14 @@ MyAvatar::MyAvatar(QThread* thread, RigPointer rig) :
|
|||
if (recordingInterface->getPlayFromCurrentLocation()) {
|
||||
setRecordingBasis();
|
||||
}
|
||||
_previousCollisionGroup = _characterController.getCollisionGroup();
|
||||
_characterController.setCollisionGroup(BULLET_COLLISION_GROUP_COLLISIONLESS);
|
||||
_previousCollisionGroup = _characterController.computeCollisionGroup();
|
||||
_characterController.setCollisionless(true);
|
||||
} else {
|
||||
clearRecordingBasis();
|
||||
useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName);
|
||||
_characterController.setCollisionGroup(_previousCollisionGroup);
|
||||
if (_previousCollisionGroup != BULLET_COLLISION_GROUP_COLLISIONLESS) {
|
||||
_characterController.setCollisionless(false);
|
||||
}
|
||||
}
|
||||
|
||||
auto audioIO = DependencyManager::get<AudioClient>();
|
||||
|
@ -550,12 +552,12 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
EntityTreePointer entityTree = entityTreeRenderer ? entityTreeRenderer->getTree() : nullptr;
|
||||
if (entityTree) {
|
||||
bool flyingAllowed = true;
|
||||
bool ghostingAllowed = true;
|
||||
bool collisionlessAllowed = true;
|
||||
entityTree->withWriteLock([&] {
|
||||
std::shared_ptr<ZoneEntityItem> zone = entityTreeRenderer->myAvatarZone();
|
||||
if (zone) {
|
||||
flyingAllowed = zone->getFlyingAllowed();
|
||||
ghostingAllowed = zone->getGhostingAllowed();
|
||||
collisionlessAllowed = zone->getGhostingAllowed();
|
||||
}
|
||||
auto now = usecTimestampNow();
|
||||
EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender();
|
||||
|
@ -586,9 +588,7 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
}
|
||||
});
|
||||
_characterController.setFlyingAllowed(flyingAllowed);
|
||||
if (!ghostingAllowed && _characterController.getCollisionGroup() == BULLET_COLLISION_GROUP_COLLISIONLESS) {
|
||||
_characterController.setCollisionGroup(BULLET_COLLISION_GROUP_MY_AVATAR);
|
||||
}
|
||||
_characterController.setCollisionlessAllowed(collisionlessAllowed);
|
||||
}
|
||||
|
||||
updateAvatarEntities();
|
||||
|
@ -1448,7 +1448,7 @@ void MyAvatar::updateMotors() {
|
|||
glm::quat motorRotation;
|
||||
if (_motionBehaviors & AVATAR_MOTION_ACTION_MOTOR_ENABLED) {
|
||||
if (_characterController.getState() == CharacterController::State::Hover ||
|
||||
_characterController.getCollisionGroup() == BULLET_COLLISION_GROUP_COLLISIONLESS) {
|
||||
_characterController.computeCollisionGroup() == BULLET_COLLISION_GROUP_COLLISIONLESS) {
|
||||
motorRotation = getMyHead()->getCameraOrientation();
|
||||
} else {
|
||||
// non-hovering = walking: follow camera twist about vertical but not lift
|
||||
|
@ -1884,7 +1884,7 @@ void MyAvatar::updateActionMotor(float deltaTime) {
|
|||
glm::vec3 direction = forward + right;
|
||||
CharacterController::State state = _characterController.getState();
|
||||
if (state == CharacterController::State::Hover ||
|
||||
_characterController.getCollisionGroup() == BULLET_COLLISION_GROUP_COLLISIONLESS) {
|
||||
_characterController.computeCollisionGroup() == BULLET_COLLISION_GROUP_COLLISIONLESS) {
|
||||
// we can fly --> support vertical motion
|
||||
glm::vec3 up = (getDriveKey(TRANSLATE_Y)) * IDENTITY_UP;
|
||||
direction += up;
|
||||
|
@ -2207,20 +2207,13 @@ void MyAvatar::setCollisionsEnabled(bool enabled) {
|
|||
return;
|
||||
}
|
||||
|
||||
bool ghostingAllowed = true;
|
||||
auto entityTreeRenderer = qApp->getEntities();
|
||||
if (entityTreeRenderer) {
|
||||
std::shared_ptr<ZoneEntityItem> zone = entityTreeRenderer->myAvatarZone();
|
||||
if (zone) {
|
||||
ghostingAllowed = zone->getGhostingAllowed();
|
||||
}
|
||||
}
|
||||
int16_t group = (enabled || !ghostingAllowed) ? BULLET_COLLISION_GROUP_MY_AVATAR : BULLET_COLLISION_GROUP_COLLISIONLESS;
|
||||
_characterController.setCollisionGroup(group);
|
||||
_characterController.setCollisionless(!enabled);
|
||||
}
|
||||
|
||||
bool MyAvatar::getCollisionsEnabled() {
|
||||
return _characterController.getCollisionGroup() != BULLET_COLLISION_GROUP_COLLISIONLESS;
|
||||
// may return 'false' even though the collisionless option was requested
|
||||
// because the zone may disallow collisionless avatars
|
||||
return _characterController.computeCollisionGroup() != BULLET_COLLISION_GROUP_COLLISIONLESS;
|
||||
}
|
||||
|
||||
void MyAvatar::setCharacterControllerEnabled(bool enabled) {
|
||||
|
|
|
@ -111,11 +111,12 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) {
|
|||
}
|
||||
_dynamicsWorld = nullptr;
|
||||
}
|
||||
int16_t collisionGroup = computeCollisionGroup();
|
||||
if (world && _rigidBody) {
|
||||
// add to new world
|
||||
_dynamicsWorld = world;
|
||||
_pendingFlags &= ~PENDING_FLAG_JUMP;
|
||||
_dynamicsWorld->addRigidBody(_rigidBody, _collisionGroup, BULLET_COLLISION_MASK_MY_AVATAR);
|
||||
_dynamicsWorld->addRigidBody(_rigidBody, collisionGroup, BULLET_COLLISION_MASK_MY_AVATAR);
|
||||
_dynamicsWorld->addAction(this);
|
||||
// restore gravity settings because adding an object to the world overwrites its gravity setting
|
||||
_rigidBody->setGravity(_gravity * _currentUp);
|
||||
|
@ -123,7 +124,7 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) {
|
|||
assert(shape && shape->getShapeType() == CONVEX_HULL_SHAPE_PROXYTYPE);
|
||||
_ghost.setCharacterShape(static_cast<btConvexHullShape*>(shape));
|
||||
}
|
||||
_ghost.setCollisionGroupAndMask(_collisionGroup, BULLET_COLLISION_MASK_MY_AVATAR & (~ _collisionGroup));
|
||||
_ghost.setCollisionGroupAndMask(collisionGroup, BULLET_COLLISION_MASK_MY_AVATAR & (~ collisionGroup));
|
||||
_ghost.setCollisionWorld(_dynamicsWorld);
|
||||
_ghost.setRadiusAndHalfHeight(_radius, _halfHeight);
|
||||
_ghost.setWorldTransform(_rigidBody->getWorldTransform());
|
||||
|
@ -331,20 +332,20 @@ void CharacterController::setState(State desiredState) {
|
|||
#ifdef DEBUG_STATE_CHANGE
|
||||
qCDebug(physics) << "CharacterController::setState" << stateToStr(desiredState) << "from" << stateToStr(_state) << "," << reason;
|
||||
#endif
|
||||
if (_rigidBody) {
|
||||
if (desiredState == State::Hover && _state != State::Hover) {
|
||||
// hover enter
|
||||
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
|
||||
} else if (_state == State::Hover && desiredState != State::Hover) {
|
||||
// hover exit
|
||||
if (_collisionGroup == BULLET_COLLISION_GROUP_COLLISIONLESS) {
|
||||
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
|
||||
} else {
|
||||
_rigidBody->setGravity(_gravity * _currentUp);
|
||||
}
|
||||
}
|
||||
}
|
||||
_state = desiredState;
|
||||
updateGravity();
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterController::updateGravity() {
|
||||
int16_t collisionGroup = computeCollisionGroup();
|
||||
if (_state == State::Hover || collisionGroup == BULLET_COLLISION_GROUP_COLLISIONLESS) {
|
||||
_gravity = 0.0f;
|
||||
} else {
|
||||
_gravity = DEFAULT_CHARACTER_GRAVITY;
|
||||
}
|
||||
if (_rigidBody) {
|
||||
_rigidBody->setGravity(_gravity * _currentUp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,11 +380,18 @@ void CharacterController::setLocalBoundingBox(const glm::vec3& minCorner, const
|
|||
_shapeLocalOffset = minCorner + 0.5f * scale;
|
||||
}
|
||||
|
||||
void CharacterController::setCollisionGroup(int16_t group) {
|
||||
if (_collisionGroup != group) {
|
||||
_collisionGroup = group;
|
||||
void CharacterController::setCollisionless(bool collisionless) {
|
||||
if (collisionless != _collisionless) {
|
||||
_collisionless = collisionless;
|
||||
_pendingFlags |= PENDING_FLAG_UPDATE_COLLISION_GROUP;
|
||||
_ghost.setCollisionGroupAndMask(_collisionGroup, BULLET_COLLISION_MASK_MY_AVATAR & (~ _collisionGroup));
|
||||
}
|
||||
}
|
||||
|
||||
int16_t CharacterController::computeCollisionGroup() const {
|
||||
if (_collisionless) {
|
||||
return _collisionlessAllowed ? BULLET_COLLISION_GROUP_COLLISIONLESS : BULLET_COLLISION_GROUP_MY_AVATAR;
|
||||
} else {
|
||||
return BULLET_COLLISION_GROUP_MY_AVATAR;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -392,18 +400,11 @@ void CharacterController::handleChangedCollisionGroup() {
|
|||
// ATM the easiest way to update collision groups is to remove/re-add the RigidBody
|
||||
if (_dynamicsWorld) {
|
||||
_dynamicsWorld->removeRigidBody(_rigidBody);
|
||||
_dynamicsWorld->addRigidBody(_rigidBody, _collisionGroup, BULLET_COLLISION_MASK_MY_AVATAR);
|
||||
int16_t collisionGroup = computeCollisionGroup();
|
||||
_dynamicsWorld->addRigidBody(_rigidBody, collisionGroup, BULLET_COLLISION_MASK_MY_AVATAR);
|
||||
}
|
||||
_pendingFlags &= ~PENDING_FLAG_UPDATE_COLLISION_GROUP;
|
||||
|
||||
if (_collisionGroup == BULLET_COLLISION_GROUP_COLLISIONLESS) {
|
||||
_gravity = 0.0f;
|
||||
} else if (_state != State::Hover) {
|
||||
_gravity = (_collisionGroup == BULLET_COLLISION_GROUP_COLLISIONLESS) ? 0.0f : DEFAULT_CHARACTER_GRAVITY;
|
||||
}
|
||||
if (_rigidBody) {
|
||||
_rigidBody->setGravity(_gravity * _currentUp);
|
||||
}
|
||||
updateGravity();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -491,7 +492,8 @@ void CharacterController::applyMotor(int index, btScalar dt, btVector3& worldVel
|
|||
btScalar angle = motor.rotation.getAngle();
|
||||
btVector3 velocity = worldVelocity.rotate(axis, -angle);
|
||||
|
||||
if (_collisionGroup == BULLET_COLLISION_GROUP_COLLISIONLESS ||
|
||||
int16_t collisionGroup = computeCollisionGroup();
|
||||
if (collisionGroup == BULLET_COLLISION_GROUP_COLLISIONLESS ||
|
||||
_state == State::Hover || motor.hTimescale == motor.vTimescale) {
|
||||
// modify velocity
|
||||
btScalar tau = dt / motor.hTimescale;
|
||||
|
@ -630,7 +632,8 @@ void CharacterController::updateState() {
|
|||
btVector3 rayStart = _position;
|
||||
|
||||
btScalar rayLength = _radius;
|
||||
if (_collisionGroup == BULLET_COLLISION_GROUP_MY_AVATAR) {
|
||||
int16_t collisionGroup = computeCollisionGroup();
|
||||
if (collisionGroup == BULLET_COLLISION_GROUP_MY_AVATAR) {
|
||||
rayLength += MAX_FALL_HEIGHT;
|
||||
} else {
|
||||
rayLength += MIN_HOVER_HEIGHT;
|
||||
|
@ -667,7 +670,7 @@ void CharacterController::updateState() {
|
|||
|
||||
// disable normal state transitions while collisionless
|
||||
const btScalar MAX_WALKING_SPEED = 2.65f;
|
||||
if (_collisionGroup == BULLET_COLLISION_GROUP_MY_AVATAR) {
|
||||
if (collisionGroup == BULLET_COLLISION_GROUP_MY_AVATAR) {
|
||||
switch (_state) {
|
||||
case State::Ground:
|
||||
if (!rayHasHit && !_hasSupport) {
|
||||
|
@ -719,14 +722,15 @@ void CharacterController::updateState() {
|
|||
}
|
||||
} else {
|
||||
// when collisionless: only switch between State::Ground and State::Hover
|
||||
// and bypass state debugging
|
||||
if (rayHasHit) {
|
||||
if (velocity.length() > (MAX_WALKING_SPEED)) {
|
||||
SET_STATE(State::Hover, "collisionless in air");
|
||||
_state = State::Hover;
|
||||
} else {
|
||||
SET_STATE(State::Ground, "collisionless above ground");
|
||||
_state = State::Ground;
|
||||
}
|
||||
} else {
|
||||
SET_STATE(State::Hover, "collisionless in air");
|
||||
_state = State::Hover;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -762,14 +766,17 @@ bool CharacterController::getRigidBodyLocation(glm::vec3& avatarRigidBodyPositio
|
|||
}
|
||||
|
||||
void CharacterController::setFlyingAllowed(bool value) {
|
||||
if (_flyingAllowed != value) {
|
||||
if (value != _flyingAllowed) {
|
||||
_flyingAllowed = value;
|
||||
|
||||
if (!_flyingAllowed && _state == State::Hover) {
|
||||
// disable normal state transitions while collisionless
|
||||
if (_collisionGroup == BULLET_COLLISION_GROUP_MY_AVATAR) {
|
||||
SET_STATE(State::InAir, "flying not allowed");
|
||||
}
|
||||
SET_STATE(State::InAir, "flying not allowed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterController::setCollisionlessAllowed(bool value) {
|
||||
if (value != _collisionlessAllowed) {
|
||||
_collisionlessAllowed = value;
|
||||
_pendingFlags |= PENDING_FLAG_UPDATE_COLLISION_GROUP;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,13 +113,14 @@ public:
|
|||
|
||||
bool isEnabledAndReady() const { return _dynamicsWorld; }
|
||||
|
||||
void setCollisionGroup(int16_t group);
|
||||
int16_t getCollisionGroup() const { return _collisionGroup; }
|
||||
void setCollisionless(bool collisionless);
|
||||
int16_t computeCollisionGroup() const;
|
||||
void handleChangedCollisionGroup();
|
||||
|
||||
bool getRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation);
|
||||
|
||||
void setFlyingAllowed(bool value);
|
||||
void setCollisionlessAllowed(bool value);
|
||||
|
||||
|
||||
protected:
|
||||
|
@ -129,6 +130,7 @@ protected:
|
|||
void setState(State state);
|
||||
#endif
|
||||
|
||||
void updateGravity();
|
||||
void updateUpAxis(const glm::quat& rotation);
|
||||
bool checkForSupport(btCollisionWorld* collisionWorld);
|
||||
|
||||
|
@ -198,7 +200,8 @@ protected:
|
|||
uint32_t _previousFlags { 0 };
|
||||
|
||||
bool _flyingAllowed { true };
|
||||
int16_t _collisionGroup { BULLET_COLLISION_GROUP_MY_AVATAR };
|
||||
bool _collisionlessAllowed { true };
|
||||
bool _collisionless { false };
|
||||
};
|
||||
|
||||
#endif // hifi_CharacterController_h
|
||||
|
|
Loading…
Reference in a new issue