예제 #1
0
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;
}
예제 #2
0
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);
                    }
                }
            }
        }
    }
}