VR4RoboticArm2/VR4RoboticArm/Library/PackageCache/com.meta.xr.sdk.interaction/Runtime/Sample/Scripts/AudioPhysics.cs
IonutMocanu d7aba243a2 Main
2025-09-08 11:04:02 +03:00

204 lines
7.2 KiB
C#

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* Licensed under the Oculus SDK License Agreement (the "License");
* you may not use the Oculus SDK except in compliance with the License,
* which is provided at the time of installation or download, or which
* otherwise accompanies this software in either electronic or hard copy form.
*
* You may obtain a copy of the License at
*
* https://developer.oculus.com/licenses/oculussdk/
*
* Unless required by applicable law or agreed to in writing, the Oculus SDK
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using UnityEngine.Assertions;
using UnityEngine;
using Oculus.Interaction;
namespace Oculus.Interaction
{
public class AudioPhysics : MonoBehaviour
{
[Tooltip("Add a reference to the rigidbody on this gameobject.")]
[SerializeField]
private Rigidbody _rigidbody;
[Tooltip("Reference an audio trigger instance for soft and hard collisions.")]
[SerializeField]
private ImpactAudio _impactAudioEvents;
[Tooltip("Collisions below this value will play a soft audio event, and collisions above will play a hard audio event.")]
[Range(0.0f, 8.0f)]
[SerializeField]
private float _velocitySplit = 1.0f;
[Tooltip("Collisions below this value will be ignored and will not play audio.")]
[Range(0.0f, 2.0f)]
[SerializeField]
private float _minimumVelocity = 0;
[Tooltip("The shortest amount of time in seconds between collisions. Used to cull multiple fast collision events.")]
[Range(0.0f, 2.0f)]
[SerializeField]
private float _timeBetweenCollisions = 0.2f;
[Tooltip("By default (false), when two physics objects collide with physics audio components, we only play the one with the higher velocity." +
"Setting this to true will allow both impacts to play.")]
[SerializeField]
private bool _allowMultipleCollisions = false;
private float _timeAtLastCollision = 0f;
protected bool _started = false;
private CollisionEvents _collisionEvents;
protected virtual void Start()
{
this.BeginStart(ref _started);
this.AssertField(_impactAudioEvents.SoftCollisionSound, nameof(_impactAudioEvents.SoftCollisionSound));
this.AssertField(_impactAudioEvents.HardCollisionSound, nameof(_impactAudioEvents.HardCollisionSound));
this.AssertField(_rigidbody, nameof(_rigidbody));
_collisionEvents = _rigidbody.gameObject.AddComponent<CollisionEvents>();
this.EndStart(ref _started);
}
protected virtual void OnEnable()
{
if (_started)
{
_collisionEvents.WhenCollisionEnter += HandleCollisionEnter;
}
}
protected virtual void OnDisable()
{
if (_started)
{
_collisionEvents.WhenCollisionEnter -= HandleCollisionEnter;
}
}
protected virtual void OnDestroy()
{
if (_collisionEvents != null)
{
Destroy(_collisionEvents);
}
}
private void HandleCollisionEnter(Collision collision)
{
TryPlayCollisionAudio(collision, _rigidbody);
}
private void TryPlayCollisionAudio(Collision collision, Rigidbody rigidbody)
{
// capture the velocity of the impact. TODO lets see if there is another way to get this data that might be better
float collisionMagnitude = collision.relativeVelocity.sqrMagnitude;
// make sure the gameobject we collided with is valid
if (collision.collider.gameObject == null)
{
return;
}
// cull all the collisions we want to ignore
// ignore any physics impacts that happen too close together
float deltaTime = Time.time - _timeAtLastCollision;
if (_timeBetweenCollisions > deltaTime)
{
return;
}
// only play a single sound when two physics objects collide
if (_allowMultipleCollisions == false)
{
// check the object we collided with if it has an audio physics component
if (collision.collider.gameObject.TryGetComponent(out AudioPhysics otherAudioPhysicsObj))
{
if (GetObjectVelocity(otherAudioPhysicsObj) > GetObjectVelocity(this))
{
return;
}
}
}
// update time variable for impacts too close together
_timeAtLastCollision = Time.time;
// play the audio
PlayCollisionAudio(_impactAudioEvents, collisionMagnitude);
}
private void PlayCollisionAudio(ImpactAudio impactAudio, float magnitude)
{
// early out if there is no physics audio available
if (impactAudio.HardCollisionSound == null || impactAudio.SoftCollisionSound == null)
{
return;
}
// cull audio by minimum velocity value
if (magnitude > _minimumVelocity)
{
// play the hard or soft sound determined by the slider
if (magnitude > _velocitySplit && impactAudio.HardCollisionSound != null)
{
PlaySoundOnAudioTrigger(impactAudio.HardCollisionSound);
}
else
{
PlaySoundOnAudioTrigger(impactAudio.SoftCollisionSound);
}
}
}
private static float GetObjectVelocity(AudioPhysics target)
{
#pragma warning disable CS0618 // Type or member is obsolete
return target._rigidbody.velocity.sqrMagnitude;
#pragma warning restore CS0618 // Type or member is obsolete
}
private void PlaySoundOnAudioTrigger(AudioTrigger audioTrigger)
{
if (audioTrigger != null)
{
audioTrigger.PlayAudio();
}
}
public class CollisionEvents : MonoBehaviour
{
public event Action<Collision> WhenCollisionEnter = delegate { };
private void OnCollisionEnter(Collision collision)
{
WhenCollisionEnter.Invoke(collision);
}
}
}
[Serializable]
public struct ImpactAudio
{
[Tooltip("Hard collision sound will play when impact velocity is above the velocity split value.")]
[SerializeField]
private AudioTrigger _hardCollisionSound;
[Tooltip("Soft collision sound will play when impact velocity is below the velocity split value.")]
[SerializeField]
private AudioTrigger _softCollisionSound;
public AudioTrigger HardCollisionSound => _hardCollisionSound;
public AudioTrigger SoftCollisionSound => _softCollisionSound;
}
}