mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 16:53:16 +02:00
Avatar collision sounds.
collisionsSoundURL can be set in preferences: Currently defaults to https://s3.amazonaws.com/hifi-public/sounds/Collisions-hitsandslaps/airhockey_hit1.wav. Can be empty, which means no sound, rather than restoring default. MyAvatar.collisionSoundURL can read/written in scripts. Preloads when set, so that it won't have to fetch on first collision. Plays at start of collision only, with volume proportional to "velocity change"^2.
This commit is contained in:
parent
8dcd91fdab
commit
98f165f2ae
6 changed files with 107 additions and 0 deletions
|
@ -2202,6 +2202,7 @@ void Application::init() {
|
||||||
|
|
||||||
// Make sure any new sounds are loaded as soon as know about them.
|
// Make sure any new sounds are loaded as soon as know about them.
|
||||||
connect(tree, &EntityTree::newCollisionSoundURL, DependencyManager::get<SoundCache>().data(), &SoundCache::getSound);
|
connect(tree, &EntityTree::newCollisionSoundURL, DependencyManager::get<SoundCache>().data(), &SoundCache::getSound);
|
||||||
|
connect(_myAvatar, &MyAvatar::newCollisionSoundURL, DependencyManager::get<SoundCache>().data(), &SoundCache::getSound);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::closeMirrorView() {
|
void Application::closeMirrorView() {
|
||||||
|
|
|
@ -257,6 +257,31 @@ void AvatarManager::handleOutgoingChanges(VectorOfMotionStates& motionStates) {
|
||||||
|
|
||||||
void AvatarManager::handleCollisionEvents(CollisionEvents& collisionEvents) {
|
void AvatarManager::handleCollisionEvents(CollisionEvents& collisionEvents) {
|
||||||
// TODO: expose avatar collision events to JS
|
// TODO: expose avatar collision events to JS
|
||||||
|
for (Collision collision : collisionEvents) {
|
||||||
|
if (collision.idA.isNull() || collision.idB.isNull()) {
|
||||||
|
MyAvatar* myAvatar = getMyAvatar();
|
||||||
|
const QString& collisionSoundURL = myAvatar->getCollisionSoundURL();
|
||||||
|
if (!collisionSoundURL.isEmpty()) {
|
||||||
|
const float velocityChange = glm::length(collision.velocityChange);
|
||||||
|
const float MIN_AVATAR_COLLISION_ACCELERATION = 0.01;
|
||||||
|
const bool isSound = (collision.type == CONTACT_EVENT_TYPE_START) && (velocityChange > MIN_AVATAR_COLLISION_ACCELERATION);
|
||||||
|
|
||||||
|
if (!isSound) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// 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 = 0.5f;
|
||||||
|
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;
|
||||||
|
|
||||||
|
AudioInjector::playSound(collisionSoundURL, energyFactorOfFull, AVATAR_STRETCH_FACTOR, myAvatar->getPosition());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarManager::updateAvatarPhysicsShape(const QUuid& id) {
|
void AvatarManager::updateAvatarPhysicsShape(const QUuid& id) {
|
||||||
|
|
|
@ -70,6 +70,7 @@ float DEFAULT_SCRIPTED_MOTOR_TIMESCALE = 1.0e6f;
|
||||||
const int SCRIPTED_MOTOR_CAMERA_FRAME = 0;
|
const int SCRIPTED_MOTOR_CAMERA_FRAME = 0;
|
||||||
const int SCRIPTED_MOTOR_AVATAR_FRAME = 1;
|
const int SCRIPTED_MOTOR_AVATAR_FRAME = 1;
|
||||||
const int SCRIPTED_MOTOR_WORLD_FRAME = 2;
|
const int SCRIPTED_MOTOR_WORLD_FRAME = 2;
|
||||||
|
const QString& DEFAULT_AVATAR_COLLISION_SOUND_URL = "https://s3.amazonaws.com/hifi-public/sounds/Collisions-hitsandslaps/airhockey_hit1.wav";
|
||||||
|
|
||||||
const float MyAvatar::ZOOM_MIN = 0.5f;
|
const float MyAvatar::ZOOM_MIN = 0.5f;
|
||||||
const float MyAvatar::ZOOM_MAX = 10.0f;
|
const float MyAvatar::ZOOM_MAX = 10.0f;
|
||||||
|
@ -90,6 +91,7 @@ MyAvatar::MyAvatar() :
|
||||||
_scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE),
|
_scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE),
|
||||||
_scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME),
|
_scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME),
|
||||||
_motionBehaviors(AVATAR_MOTION_DEFAULTS),
|
_motionBehaviors(AVATAR_MOTION_DEFAULTS),
|
||||||
|
_collisionSoundURL(""),
|
||||||
_characterController(this),
|
_characterController(this),
|
||||||
_lookAtTargetAvatar(),
|
_lookAtTargetAvatar(),
|
||||||
_shouldRender(true),
|
_shouldRender(true),
|
||||||
|
@ -664,6 +666,7 @@ void MyAvatar::saveData() {
|
||||||
settings.endArray();
|
settings.endArray();
|
||||||
|
|
||||||
settings.setValue("displayName", _displayName);
|
settings.setValue("displayName", _displayName);
|
||||||
|
settings.setValue("collisionSoundURL", _collisionSoundURL);
|
||||||
|
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
|
@ -789,6 +792,7 @@ void MyAvatar::loadData() {
|
||||||
settings.endArray();
|
settings.endArray();
|
||||||
|
|
||||||
setDisplayName(settings.value("displayName").toString());
|
setDisplayName(settings.value("displayName").toString());
|
||||||
|
setCollisionSoundURL(settings.value("collisionSoundURL", DEFAULT_AVATAR_COLLISION_SOUND_URL).toString());
|
||||||
|
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
|
@ -1183,6 +1187,13 @@ void MyAvatar::clearScriptableSettings() {
|
||||||
_scriptedMotorTimescale = DEFAULT_SCRIPTED_MOTOR_TIMESCALE;
|
_scriptedMotorTimescale = DEFAULT_SCRIPTED_MOTOR_TIMESCALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MyAvatar::setCollisionSoundURL(const QString& url) {
|
||||||
|
if (!url.isEmpty() && (url != _collisionSoundURL)) {
|
||||||
|
emit newCollisionSoundURL(QUrl(url));
|
||||||
|
}
|
||||||
|
_collisionSoundURL = url;
|
||||||
|
}
|
||||||
|
|
||||||
void MyAvatar::attach(const QString& modelURL, const QString& jointName, const glm::vec3& translation,
|
void MyAvatar::attach(const QString& modelURL, const QString& jointName, const glm::vec3& translation,
|
||||||
const glm::quat& rotation, float scale, bool allowDuplicates, bool useSaved) {
|
const glm::quat& rotation, float scale, bool allowDuplicates, bool useSaved) {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
|
|
|
@ -25,6 +25,7 @@ class MyAvatar : public Avatar {
|
||||||
Q_PROPERTY(glm::vec3 motorVelocity READ getScriptedMotorVelocity WRITE setScriptedMotorVelocity)
|
Q_PROPERTY(glm::vec3 motorVelocity READ getScriptedMotorVelocity WRITE setScriptedMotorVelocity)
|
||||||
Q_PROPERTY(float motorTimescale READ getScriptedMotorTimescale WRITE setScriptedMotorTimescale)
|
Q_PROPERTY(float motorTimescale READ getScriptedMotorTimescale WRITE setScriptedMotorTimescale)
|
||||||
Q_PROPERTY(QString motorReferenceFrame READ getScriptedMotorFrame WRITE setScriptedMotorFrame)
|
Q_PROPERTY(QString motorReferenceFrame READ getScriptedMotorFrame WRITE setScriptedMotorFrame)
|
||||||
|
Q_PROPERTY(QString collisionSoundURL READ getCollisionSoundURL WRITE setCollisionSoundURL)
|
||||||
//TODO: make gravity feature work Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setGravity)
|
//TODO: make gravity feature work Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setGravity)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -150,6 +151,9 @@ public:
|
||||||
void setScriptedMotorTimescale(float timescale);
|
void setScriptedMotorTimescale(float timescale);
|
||||||
void setScriptedMotorFrame(QString frame);
|
void setScriptedMotorFrame(QString frame);
|
||||||
|
|
||||||
|
const QString& getCollisionSoundURL() {return _collisionSoundURL; }
|
||||||
|
void setCollisionSoundURL(const QString& url);
|
||||||
|
|
||||||
void clearScriptableSettings();
|
void clearScriptableSettings();
|
||||||
|
|
||||||
virtual void attach(const QString& modelURL, const QString& jointName = QString(),
|
virtual void attach(const QString& modelURL, const QString& jointName = QString(),
|
||||||
|
@ -204,6 +208,7 @@ public slots:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void transformChanged();
|
void transformChanged();
|
||||||
|
void newCollisionSoundURL(const QUrl& url);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -233,6 +238,7 @@ private:
|
||||||
float _scriptedMotorTimescale; // timescale for avatar to achieve its target velocity
|
float _scriptedMotorTimescale; // timescale for avatar to achieve its target velocity
|
||||||
int _scriptedMotorFrame;
|
int _scriptedMotorFrame;
|
||||||
quint32 _motionBehaviors;
|
quint32 _motionBehaviors;
|
||||||
|
QString _collisionSoundURL;
|
||||||
|
|
||||||
DynamicCharacterController _characterController;
|
DynamicCharacterController _characterController;
|
||||||
|
|
||||||
|
|
|
@ -127,6 +127,8 @@ void PreferencesDialog::loadPreferences() {
|
||||||
_displayNameString = myAvatar->getDisplayName();
|
_displayNameString = myAvatar->getDisplayName();
|
||||||
ui.displayNameEdit->setText(_displayNameString);
|
ui.displayNameEdit->setText(_displayNameString);
|
||||||
|
|
||||||
|
ui.collisionSoundURLEdit->setText(myAvatar->getCollisionSoundURL());
|
||||||
|
|
||||||
ui.sendDataCheckBox->setChecked(!menuInstance->isOptionChecked(MenuOption::DisableActivityLogger));
|
ui.sendDataCheckBox->setChecked(!menuInstance->isOptionChecked(MenuOption::DisableActivityLogger));
|
||||||
|
|
||||||
ui.snapshotLocationEdit->setText(Snapshot::snapshotsLocation.get());
|
ui.snapshotLocationEdit->setText(Snapshot::snapshotsLocation.get());
|
||||||
|
@ -204,6 +206,8 @@ void PreferencesDialog::savePreferences() {
|
||||||
myAvatar->sendIdentityPacket();
|
myAvatar->sendIdentityPacket();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
myAvatar->setCollisionSoundURL(ui.collisionSoundURLEdit->text());
|
||||||
|
|
||||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableActivityLogger)
|
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableActivityLogger)
|
||||||
!= ui.sendDataCheckBox->isChecked()) {
|
!= ui.sendDataCheckBox->isChecked()) {
|
||||||
Menu::getInstance()->triggerOption(MenuOption::DisableActivityLogger);
|
Menu::getInstance()->triggerOption(MenuOption::DisableActivityLogger);
|
||||||
|
|
|
@ -189,6 +189,66 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_5csu">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>7</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>7</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="avatarCollisionSoundURLLabel">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Arial</family>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string><html><head/><body><p>Avatar collision sound URL <span style=" color:#909090;">(optional)</span></p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>collisionSoundURLEdit</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_17csu">
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>5</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="collisionSoundURLEdit">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Arial</family>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="layoutDirection">
|
||||||
|
<enum>Qt::LeftToRight</enum>
|
||||||
|
</property>
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>Enter the URL of a sound to play when you bump into something</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_appearance">
|
<layout class="QVBoxLayout" name="verticalLayout_appearance">
|
||||||
|
|
Loading…
Reference in a new issue