bool AvatarActionHold::getAvatarRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation) { auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); MyCharacterController* controller = myAvatar ? myAvatar->getCharacterController() : nullptr; if (!controller) { qDebug() << "AvatarActionHold::getAvatarRigidBodyLocation failed to get character controller"; return false; } controller->getRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation); return true; }
void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents) { bool playedCollisionSound { false }; for (Collision collision : collisionEvents) { // TODO: The plan is to handle MOTIONSTATE_TYPE_AVATAR, and then MOTIONSTATE_TYPE_MYAVATAR. As it is, other // people's avatars will have an id that doesn't match any entities, and one's own avatar will have // an id of null. Thus this code handles any collision in which one of the participating objects is // my avatar. (Other user machines will make a similar analysis and inject sound for their collisions.) if (collision.idA.isNull() || collision.idB.isNull()) { auto myAvatar = getMyAvatar(); myAvatar->collisionWithEntity(collision); if (!playedCollisionSound) { playedCollisionSound = true; auto collisionSound = myAvatar->getCollisionSound(); if (collisionSound) { const auto characterController = myAvatar->getCharacterController(); const float avatarVelocityChange = (characterController ? glm::length(characterController->getVelocityChange()) : 0.0f); const float velocityChange = glm::length(collision.velocityChange) + avatarVelocityChange; const float MIN_AVATAR_COLLISION_ACCELERATION = 2.4f; // walking speed const bool isSound = (collision.type == CONTACT_EVENT_TYPE_START) && (velocityChange > MIN_AVATAR_COLLISION_ACCELERATION); if (!isSound) { return; // No sense iterating for others. We only have one avatar. } // Your avatar sound is personal to you, so let's say the "mass" part of the kinetic energy is already accounted for. const float energy = velocityChange * velocityChange; const float COLLISION_ENERGY_AT_FULL_VOLUME = 10.0f; const float energyFactorOfFull = fmin(1.0f, energy / COLLISION_ENERGY_AT_FULL_VOLUME); // For general entity collisionSoundURL, playSound supports changing the pitch for the sound based on the size of the object, // but most avatars are roughly the same size, so let's not be so fancy yet. const float AVATAR_STRETCH_FACTOR = 1.0f; _collisionInjectors.remove_if([](const AudioInjectorPointer& injector) { return !injector; }); static const int MAX_INJECTOR_COUNT = 3; if (_collisionInjectors.size() < MAX_INJECTOR_COUNT) { AudioInjectorOptions options; options.stereo = collisionSound->isStereo(); options.position = myAvatar->getWorldPosition(); options.volume = energyFactorOfFull; options.pitch = 1.0f / AVATAR_STRETCH_FACTOR; auto injector = DependencyManager::get<AudioInjectorManager>()->playSound(collisionSound, options, true); _collisionInjectors.emplace_back(injector); } } } } } }