From 44eca08fa488bf653dd06dd10f51ea798323385e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 24 Mar 2015 17:38:35 -0700 Subject: [PATCH] PhysicsEngine doesn't need AvatarData MyAvatar now owns its CharacterController fix for bug of phantom collision obj when avatar's physics are disabled --- interface/src/Application.cpp | 7 +- interface/src/avatar/MyAvatar.cpp | 14 +- interface/src/avatar/MyAvatar.h | 11 + libraries/avatars/src/AvatarData.h | 13 - libraries/physics/src/CharacterController.cpp | 229 +++++++++++------- libraries/physics/src/CharacterController.h | 16 +- libraries/physics/src/PhysicsEngine.cpp | 43 +--- libraries/physics/src/PhysicsEngine.h | 4 +- 8 files changed, 197 insertions(+), 140 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4ff41e1b6f..418407282c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1903,8 +1903,6 @@ void Application::init() { _physicsEngine.init(&_entityEditSender); - _physicsEngine.setAvatarData(_myAvatar); - auto entityScriptingInterface = DependencyManager::get(); connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity, @@ -2191,6 +2189,7 @@ void Application::update(float deltaTime) { { PerformanceTimer perfTimer("physics"); + _myAvatar->preSimulation(); _physicsEngine.stepSimulation(); } @@ -4207,7 +4206,7 @@ void Application::checkSkeleton() { _myAvatar->setSkeletonModelURL(DEFAULT_BODY_MODEL_URL); _myAvatar->sendIdentityPacket(); } else { - _myAvatar->updateLocalAABox(); - _physicsEngine.setAvatarData(_myAvatar); + _myAvatar->updateCharacterController(); + _physicsEngine.setCharacterController(_myAvatar->getCharacterController()); } } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index ab4989a651..e0de24247e 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -82,6 +82,8 @@ MyAvatar::MyAvatar() : _scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE), _scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME), _motionBehaviors(AVATAR_MOTION_DEFAULTS), + _characterController(this), + _enablePhysics(false), _lookAtTargetAvatar(), _shouldRender(true), _billboardValid(false), @@ -954,15 +956,15 @@ glm::vec3 MyAvatar::getSkeletonPosition() const { return Avatar::getPosition(); } -void MyAvatar::updateLocalAABox() { +void MyAvatar::updateCharacterController() { + // compute localAABox const CapsuleShape& capsule = _skeletonModel.getBoundingShape(); float radius = capsule.getRadius(); float height = 2.0f * (capsule.getHalfHeight() + radius); - glm::vec3 offset = _skeletonModel.getBoundingShapeOffset(); glm::vec3 corner(-radius, -0.5f * height, -radius); - corner += offset; + corner += _skeletonModel.getBoundingShapeOffset(); glm::vec3 scale(2.0f * radius, height, 2.0f * radius); - _localAABox.setBox(corner, scale); + _characterController.setLocalBoundingBox(corner, scale); } QString MyAvatar::getScriptedMotorFrame() const { @@ -1580,6 +1582,10 @@ glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) { return palm->getPosition(); } +void MyAvatar::preSimulation() { + _characterController.setEnabled(_enablePhysics); +} + void MyAvatar::clearDriveKeys() { for (int i = 0; i < MAX_DRIVE_KEYS; ++i) { _driveKeys[i] = 0.0f; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 08c0228f1e..1b2b2f5e46 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -13,6 +13,7 @@ #define hifi_MyAvatar_h #include +#include #include "Avatar.h" @@ -122,6 +123,8 @@ public: virtual glm::vec3 getSkeletonPosition() const; void updateLocalAABox(); + CharacterController* getCharacterController() { return &_characterController; } + void updateCharacterController(); void clearJointAnimationPriorities(); @@ -145,6 +148,11 @@ public: const RecorderPointer getRecorder() const { return _recorder; } const PlayerPointer getPlayer() const { return _player; } + + void togglePhysicsEnabled() { _enablePhysics = !_enablePhysics; } + bool isPhysicsEnabled() { return _enablePhysics; } + void setPhysicsEnabled(bool enablePhysics) { _enablePhysics = enablePhysics; } + void preSimulation(); public slots: void increaseSize(); @@ -202,6 +210,9 @@ private: int _scriptedMotorFrame; quint32 _motionBehaviors; + bool _enablePhysics; + CharacterController _characterController; + QWeakPointer _lookAtTargetAvatar; glm::vec3 _targetAvatarPosition; bool _shouldRender; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 28123124a0..a2feb98798 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -300,16 +300,6 @@ public: const AABox& getLocalAABox() const { return _localAABox; } const Referential* getReferential() const { return _referential; } - void togglePhysicsEnabled() { _enablePhysics = !_enablePhysics; } - bool isPhysicsEnabled() { return _enablePhysics; } - void setPhysicsEnabled(bool enablePhysics) { _enablePhysics = enablePhysics; } - - void lockForRead() { _lock.lockForRead(); } - bool tryLockForRead() { return _lock.tryLockForRead(); } - void lockForWrite() { _lock.lockForWrite(); } - bool tryLockForWrite() { return _lock.tryLockForWrite(); } - void unlock() { _lock.unlock(); } - void setVelocity(const glm::vec3 velocity) { _velocity = velocity; } Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; } @@ -409,9 +399,6 @@ private: // privatize the copy constructor and assignment operator so they cannot be called AvatarData(const AvatarData&); AvatarData& operator= (const AvatarData&); - - QReadWriteLock _lock; - bool _enablePhysics = false; }; Q_DECLARE_METATYPE(AvatarData*) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index d0b083fc01..be10cd1f54 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -21,6 +21,12 @@ subject to the following restrictions: #include "BulletUtil.h" #include "CharacterController.h" +const uint32_t PENDING_FLAG_ADD_TO_SIMULATION = 1U << 0; +const uint32_t PENDING_FLAG_REMOVE_FROM_SIMULATION = 1U << 1; +//const uint32_t PENDING_FLAG_ENABLE = 1U << 0; +//const uint32_t PENDING_FLAG_DISABLE = 1U << 1; +const uint32_t PENDING_FLAG_UPDATE_SHAPE = 1U << 2; +const uint32_t PENDING_FLAG_JUMP = 1U << 4; // static helper method static btVector3 getNormalizedVector(const btVector3& v) { @@ -223,11 +229,10 @@ CharacterController::CharacterController(AvatarData* avatarData) { _avatarData = avatarData; // cache the "PhysicsEnabled" state of _avatarData - _avatarData->lockForRead(); - _enabled = _avatarData->isPhysicsEnabled(); - _avatarData->unlock(); + _enabled = false; - createShapeAndGhost(); + _ghostObject = NULL; + _convexShape = NULL; _addedMargin = 0.02f; _walkDirection.setValue(0.0f,0.0f,0.0f); @@ -242,6 +247,7 @@ CharacterController::CharacterController(AvatarData* avatarData) { _wasJumping = false; setMaxSlope(btRadians(45.0f)); _lastStepUp = 0.0f; + _pendingFlags = 0; } CharacterController::~CharacterController() { @@ -349,7 +355,7 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl return penetration; } -void CharacterController::stepUp( btCollisionWorld* world) { +void CharacterController::stepUp(btCollisionWorld* world) { // phase 1: up // compute start and end @@ -416,7 +422,7 @@ void CharacterController::updateTargetPositionBasedOnCollision(const btVector3& } } -void CharacterController::stepForward( btCollisionWorld* collisionWorld, const btVector3& movement) { +void CharacterController::stepForward(btCollisionWorld* collisionWorld, const btVector3& movement) { // phase 2: forward _targetPosition = _currentPosition + movement; @@ -472,7 +478,7 @@ void CharacterController::stepForward( btCollisionWorld* collisionWorld, const b _convexShape->setMargin(margin); } -void CharacterController::stepDown( btCollisionWorld* collisionWorld, btScalar dt) { +void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt) { // phase 3: down // // The "stepDown" phase first makes a normal sweep down that cancels the lift from the "stepUp" phase. @@ -558,7 +564,7 @@ void CharacterController::setVelocityForTimeInterval(const btVector3& velocity, _velocityTimeInterval += timeInterval; } -void CharacterController::reset( btCollisionWorld* collisionWorld ) { +void CharacterController::reset(btCollisionWorld* collisionWorld) { _verticalVelocity = 0.0; _verticalOffset = 0.0; _wasOnGround = false; @@ -583,7 +589,7 @@ void CharacterController::warp(const btVector3& origin) { } -void CharacterController::preStep( btCollisionWorld* collisionWorld) { +void CharacterController::preStep(btCollisionWorld* collisionWorld) { if (!_enabled) { return; } @@ -603,7 +609,7 @@ void CharacterController::preStep( btCollisionWorld* collisionWorld) { _targetPosition = _currentPosition; } -void CharacterController::playerStep( btCollisionWorld* collisionWorld, btScalar dt) { +void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar dt) { if (!_enabled || (!_useWalkDirection && _velocityTimeInterval <= 0.0)) { return; // no motion } @@ -710,106 +716,163 @@ void CharacterController::setUpInterpolate(bool value) { // (interpolate = true, and now default behavior) or happily penetrate objects above the avatar. } +/* // protected void CharacterController::createShapeAndGhost() { // get new dimensions from avatar - _avatarData->lockForRead(); - AABox box = _avatarData->getLocalAABox(); - - // create new ghost - _ghostObject = new btPairCachingGhostObject(); - _ghostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), - glmToBullet(_avatarData->getPosition()))); - _avatarData->unlock(); - - const glm::vec3& diagonal = box.getScale(); - _radius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z)); - _halfHeight = 0.5f * diagonal.y - _radius; + float x = _boxScale.x; + float z = _boxScale.z; + _radius = 0.5f * sqrtf(0.5f * (x * x + z * z)); + _halfHeight = 0.5f * _boxScale.y - _radius; float MIN_HALF_HEIGHT = 0.1f; if (_halfHeight < MIN_HALF_HEIGHT) { _halfHeight = MIN_HALF_HEIGHT; } - glm::vec3 offset = box.getCorner() + 0.5f * diagonal; - _shapeLocalOffset = offset; + // NOTE: _shapeLocalOffset is already computed - // stepHeight affects the heights of ledges that the character can ascend - // however the actual ledge height is some function of _stepHeight - // due to character shape and this CharacterController algorithm - // (the function is approximately 2*_stepHeight) - _stepHeight = 0.1f * (_radius + _halfHeight) + 0.1f; - - // create new shape - _convexShape = new btCapsuleShape(_radius, 2.0f * _halfHeight); - _ghostObject->setCollisionShape(_convexShape); - _ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); + if (_radius > 0.0f) { + // create new ghost + _ghostObject = new btPairCachingGhostObject(); + _ghostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), + glmToBullet(_avatarData->getPosition()))); + // stepHeight affects the heights of ledges that the character can ascend + // however the actual ledge height is some function of _stepHeight + // due to character shape and this CharacterController algorithm + // (the function is approximately 2*_stepHeight) + _stepHeight = 0.1f * (_radius + _halfHeight) + 0.1f; + + // create new shape + _convexShape = new btCapsuleShape(_radius, 2.0f * _halfHeight); + _ghostObject->setCollisionShape(_convexShape); + _ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); + } else { + // TODO: handle this failure case + } + _pendingFlags &= ~ PENDING_FLAG_UPDATE_SHAPE; } +*/ -bool CharacterController::needsShapeUpdate() { - // get new dimensions from avatar - _avatarData->lockForRead(); - AABox box = _avatarData->getLocalAABox(); - _avatarData->unlock(); +void CharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale) { + _boxScale = scale; - const glm::vec3& diagonal = box.getScale(); - float radius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z)); - float halfHeight = 0.5f * diagonal.y - radius; + float x = _boxScale.x; + float z = _boxScale.z; + float radius = 0.5f * sqrtf(0.5f * (x * x + z * z)); + float halfHeight = 0.5f * _boxScale.y - radius; float MIN_HALF_HEIGHT = 0.1f; if (halfHeight < MIN_HALF_HEIGHT) { halfHeight = MIN_HALF_HEIGHT; } - glm::vec3 offset = box.getCorner() + 0.5f * diagonal; - // compare dimensions (and offset) + // compare dimensions float radiusDelta = glm::abs(radius - _radius); float heightDelta = glm::abs(halfHeight - _halfHeight); if (radiusDelta < FLT_EPSILON && heightDelta < FLT_EPSILON) { // shape hasn't changed --> nothing to do - float offsetDelta = glm::distance(offset, _shapeLocalOffset); - if (offsetDelta > FLT_EPSILON) { - // if only the offset changes then we can update it --> no need to rebuild shape - _shapeLocalOffset = offset; - } - return false; + } else { + // we need to: remove, update, add + _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION + | PENDING_FLAG_UPDATE_SHAPE + | PENDING_FLAG_ADD_TO_SIMULATION; + } + + // it's ok to change offset immediately -- there are no thread safety issues here + _shapeLocalOffset = corner + 0.5f * _boxScale; +} + +bool CharacterController::needsAddition() const { + return (bool)(_pendingFlags & PENDING_FLAG_ADD_TO_SIMULATION); +} + +bool CharacterController::needsRemoval() const { + return (bool)(_pendingFlags & PENDING_FLAG_REMOVE_FROM_SIMULATION); +} + +void CharacterController::setEnabled(bool enabled) { + if (enabled != _enabled) { + if (enabled) { + _pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION; + } else { + _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION; + _pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION; + } + _enabled = enabled; + } +} + +void CharacterController::setDynamicsWorld(btDynamicsWorld* world) { + if (_dynamicsWorld != world) { + if (_dynamicsWorld) { + _dynamicsWorld->removeCollisionObject(getGhostObject()); + _dynamicsWorld->removeAction(this); + } + _dynamicsWorld = world; + if (_dynamicsWorld) { + _pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION; + _dynamicsWorld->addCollisionObject(getGhostObject(), + btBroadphaseProxy::CharacterFilter, + btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); + _dynamicsWorld->addAction(this); + reset(_dynamicsWorld); + } else { + _pendingFlags &= ~ PENDING_FLAG_REMOVE_FROM_SIMULATION; + } + } else { + _pendingFlags &= ~ (PENDING_FLAG_REMOVE_FROM_SIMULATION | PENDING_FLAG_ADD_TO_SIMULATION); } - return true; } void CharacterController::updateShape() { - // DANGER: make sure this CharacterController and its GhostShape have been removed from - // the PhysicsEngine before calling this. - - // delete shape and GhostObject - delete _ghostObject; - _ghostObject = NULL; - delete _convexShape; - _convexShape = NULL; - - createShapeAndGhost(); + if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) { + assert(!(_pendingFlags & PENDING_FLAG_REMOVE_FROM_SIMULATION)); + _pendingFlags &= ~ PENDING_FLAG_UPDATE_SHAPE; + // make sure there is NO pending removal from simulation at this point + // (don't want to delete _ghostObject out from under the simulation) + // delete shape and GhostObject + delete _ghostObject; + _ghostObject = NULL; + delete _convexShape; + _convexShape = NULL; + + // compute new dimensions from avatar's bounding box + float x = _boxScale.x; + float z = _boxScale.z; + _radius = 0.5f * sqrtf(0.5f * (x * x + z * z)); + _halfHeight = 0.5f * _boxScale.y - _radius; + float MIN_HALF_HEIGHT = 0.1f; + if (_halfHeight < MIN_HALF_HEIGHT) { + _halfHeight = MIN_HALF_HEIGHT; + } + // NOTE: _shapeLocalOffset is already computed + + if (_radius > 0.0f) { + // create new ghost + _ghostObject = new btPairCachingGhostObject(); + _ghostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), + glmToBullet(_avatarData->getPosition()))); + // stepHeight affects the heights of ledges that the character can ascend + // however the actual ledge height is some function of _stepHeight + // due to character shape and this CharacterController algorithm + // (the function is approximately 2*_stepHeight) + _stepHeight = 0.1f * (_radius + _halfHeight) + 0.1f; + + // create new shape + _convexShape = new btCapsuleShape(_radius, 2.0f * _halfHeight); + _ghostObject->setCollisionShape(_convexShape); + _ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); + } else { + // TODO: handle this failure case + } + } } void CharacterController::preSimulation(btScalar timeStep) { - bool wasEnabled = _enabled; + if (_enabled && _dynamicsWorld) { + glm::quat rotation = _avatarData->getOrientation(); + glm::vec3 position = _avatarData->getPosition() + rotation * _shapeLocalOffset; + // TODO: harvest jump event here + btVector3 walkVelocity = glmToBullet(_avatarData->getVelocity()); - // lock avatarData, get everything we need from it ASAP, then unlock - _avatarData->lockForRead(); - _enabled = _avatarData->isPhysicsEnabled(); - glm::quat rotation = _avatarData->getOrientation(); - glm::vec3 position = _avatarData->getPosition() + rotation * _shapeLocalOffset; - // TODO: Andrew to implement: harvest jump event here - btVector3 walkVelocity = glmToBullet(_avatarData->getVelocity()); - - _avatarData->unlock(); - - if (wasEnabled != _enabled) { - if (_enabled) { - // TODO: Andrew to implement: add collision shape back into world - } else { - // TODO: Andrew to implement: remove collision shape from world, - // otherwise things will continue to collide with it - } - } - - if (_enabled) { _ghostObject->setWorldTransform(btTransform(glmToBullet(rotation), glmToBullet(position))); setVelocityForTimeInterval(walkVelocity, timeStep); } @@ -817,13 +880,11 @@ void CharacterController::preSimulation(btScalar timeStep) { void CharacterController::postSimulation() { if (_enabled) { - _avatarData->lockForWrite(); const btTransform& avatarTransform = _ghostObject->getWorldTransform(); glm::quat rotation = bulletToGLM(avatarTransform.getRotation()); glm::vec3 offset = rotation * _shapeLocalOffset; _avatarData->setOrientation(rotation); _avatarData->setPosition(bulletToGLM(avatarTransform.getOrigin()) - offset); - _avatarData->unlock(); } } diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index b6109eb0ff..9803d0d6ee 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -37,13 +37,13 @@ class btPairCachingGhostObject; ///It uses a ghost object and convex sweep test to test for upcoming collisions. This is combined with discrete collision detection to recover from penetrations. ///Interaction between btKinematicCharacterController and dynamic rigid bodies needs to be explicity implemented by the user. + ATTRIBUTE_ALIGNED16(class) CharacterController : public btCharacterControllerInterface { protected: AvatarData* _avatarData = NULL; btPairCachingGhostObject* _ghostObject; - glm::vec3 _shapeLocalOffset; btConvexShape* _convexShape;//is also in _ghostObject, but it needs to be convex, so we store it here to avoid upcast btScalar _radius; @@ -83,6 +83,12 @@ protected: bool _wasJumping; bool _useWalkDirection; btScalar _velocityTimeInterval; + uint32_t _pendingFlags; + + glm::vec3 _shapeLocalOffset; + glm::vec3 _boxScale; // used to compute capsule shape + + btDynamicsWorld* _dynamicsWorld = NULL; btVector3 computeReflectionDirection(const btVector3& direction, const btVector3& normal); btVector3 parallelComponent(const btVector3& direction, const btVector3& normal); @@ -152,7 +158,13 @@ public: bool onGround() const; void setUpInterpolate(bool value); - bool needsShapeUpdate(); + bool needsRemoval() const; + bool needsAddition() const; + void setEnabled(bool enabled); + void setDynamicsWorld(btDynamicsWorld* world); + + void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale); + bool needsShapeUpdate() const; void updateShape(); void preSimulation(btScalar timeStep); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 447a3ab6f1..bcde3318ad 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -280,12 +280,12 @@ void PhysicsEngine::init(EntityEditPacketSender* packetSender) { void PhysicsEngine::stepSimulation() { lock(); // NOTE: the grand order of operations is: - // (1) relay incoming changes + // (1) pull incoming changes // (2) step simulation // (3) synchronize outgoing motion states // (4) send outgoing packets - // This is step (1). + // This is step (1) pull incoming changes relayIncomingChangesToSimulation(); const int MAX_NUM_SUBSTEPS = 4; @@ -296,10 +296,17 @@ void PhysicsEngine::stepSimulation() { // TODO: move character->preSimulation() into relayIncomingChanges if (_characterController) { + if (_characterController->needsRemoval()) { + _characterController->setDynamicsWorld(NULL); + } + _characterController->updateShape(); + if (_characterController->needsAddition()) { + _characterController->setDynamicsWorld(_dynamicsWorld); + } _characterController->preSimulation(timeStep); } - // This is step (2). + // This is step (2) step simulation int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP); _numSubsteps += (uint32_t)numSubsteps; stepNonPhysicalKinematics(usecTimestampNow()); @@ -600,34 +607,10 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio return true; } -void PhysicsEngine::setAvatarData(AvatarData *avatarData) { - if (_characterController) { - bool needsShapeUpdate = _characterController->needsShapeUpdate(); - if (needsShapeUpdate) { - lock(); - // remove old info - _dynamicsWorld->removeCollisionObject(_characterController->getGhostObject()); - _dynamicsWorld->removeAction(_characterController); - // update shape - _characterController->updateShape(); - // insert new info - _dynamicsWorld->addCollisionObject(_characterController->getGhostObject(), - btBroadphaseProxy::CharacterFilter, - btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); - _dynamicsWorld->addAction(_characterController); - _characterController->reset(_dynamicsWorld); - unlock(); - } - } else { - // initialize _characterController - assert(avatarData); // don't pass NULL argument +void PhysicsEngine::setCharacterController(CharacterController* character) { + if (!_characterController) { lock(); - _characterController = new CharacterController(avatarData); - _dynamicsWorld->addCollisionObject(_characterController->getGhostObject(), - btBroadphaseProxy::CharacterFilter, - btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); - _dynamicsWorld->addAction(_characterController); - _characterController->reset(_dynamicsWorld); + _characterController = character; unlock(); } } diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index cb637c60b9..0661b47d3a 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -17,9 +17,7 @@ #include #include #include -//#include -#include #include #include @@ -86,7 +84,7 @@ public: /// process queue of changed from external sources void relayIncomingChangesToSimulation(); - void setAvatarData(AvatarData *avatarData); + void setCharacterController(CharacterController* character); private: /// \param motionState pointer to Object's MotionState