ccl4/blueberryPeak/Assets/Wwise/MonoBehaviour/Runtime/AkRoomPortal.cs
AgentSchmisch 9144907a10 ANGST
2025-06-12 18:45:34 +02:00

438 lines
13 KiB
C#

#if ! (UNITY_DASHBOARD_WIDGET || UNITY_WEBPLAYER || UNITY_WII || UNITY_WIIU || UNITY_NACL || UNITY_FLASH || UNITY_BLACKBERRY) // Disable under unsupported platforms.
/*******************************************************************************
The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
Technology released in source code form as part of the game integration package.
The content of this file may not be used without valid licenses to the
AUDIOKINETIC Wwise Technology.
Note that the use of the game engine is subject to the Unity(R) Terms of
Service at https://unity3d.com/legal/terms-of-service
License Usage
Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
this file in accordance with the end user license agreement provided with the
software or, alternatively, in accordance with the terms contained
in a written agreement between you and Audiokinetic Inc.
Copyright (c) 2025 Audiokinetic Inc.
*******************************************************************************/
[UnityEngine.AddComponentMenu("Wwise/Spatial Audio/AkRoomPortal")]
[UnityEngine.RequireComponent(typeof(UnityEngine.BoxCollider))]
[UnityEngine.DisallowMultipleComponent]
/// @brief An AkRoomPortal can connect two AkRoom components together.
/// @details
public class AkRoomPortal : AkTriggerHandler
{
/// AkRoomPortals can only connect a maximum of 2 rooms.
public const int MAX_ROOMS_PER_PORTAL = 2;
public enum State
{
Closed,
Open
}
public State initialState = State.Closed;
private bool active = true;
public bool portalActive
{
get
{
return active;
}
set
{
active = value;
portalNeedsUpdate = true;
AkRoomManager.RegisterPortalUpdate(this);
}
}
public System.Collections.Generic.List<int> closePortalTriggerList = new System.Collections.Generic.List<int>();
private ulong frontRoomID { get { return IsRoomActive(frontRoom) ? frontRoom.GetID() : AkRoom.INVALID_ROOM_ID; } }
private ulong backRoomID { get { return IsRoomActive(backRoom) ? backRoom.GetID() : AkRoom.INVALID_ROOM_ID; } }
/// The front and back rooms connected by the portal.
/// The first room is on the negative side of the portal(opposite to the direction of the local Z axis)
/// The second room is on the positive side of the portal.
[UnityEngine.SerializeField]
private AkRoom[] rooms = new AkRoom[MAX_ROOMS_PER_PORTAL];
/// The list of rooms sorted by priority in front and in the back of the portal
private AkRoom.PriorityList[] roomList = { new AkRoom.PriorityList(), new AkRoom.PriorityList() };
public AkRoom GetRoom(int index) { return rooms[index]; }
public AkRoom frontRoom { get { return rooms[1]; } }
public AkRoom backRoom { get { return rooms[0]; } }
public bool isSetInWwise() { return portalSet; }
private AkTransform portalTransform;
private UnityEngine.BoxCollider portalCollider;
private bool portalSet = false;
private bool portalNeedsUpdate = false;
private UnityEngine.Vector3 previousPosition;
private UnityEngine.Vector3 previousScale;
private UnityEngine.Quaternion previousRotation;
private void SetRoomPortal()
{
if (!AkUnitySoundEngine.IsInitialized())
{
return;
}
if (!isActiveAndEnabled)
{
return;
}
if (IsValid)
{
portalTransform.Set(portalCollider.bounds.center, transform.forward, transform.up);
var extentVector = UnityEngine.Vector3.Scale(portalCollider.size, transform.lossyScale) / 2;
// in case extent is negative, get the absolute value
AkExtent extent = new AkExtent(
UnityEngine.Mathf.Abs(extentVector.x),
UnityEngine.Mathf.Abs(extentVector.y),
UnityEngine.Mathf.Abs(extentVector.z));
AkUnitySoundEngine.SetRoomPortal(GetID(), frontRoomID, backRoomID, portalTransform, extent, active, name);
portalSet = true;
portalNeedsUpdate = false;
}
else
{
UnityEngine.Debug.LogWarning(name + " Portal placement is invalid. The portal is not set in the Spatial Audio engine. The front and back Rooms of the Portal cannot be the same or have a ReverbZone-parent relationship.");
if (portalSet)
{
AkUnitySoundEngine.RemovePortal(GetID());
portalSet = false;
}
}
}
public void UpdateRoomPortal()
{
bool roomsChanged = UpdateRooms();
if (roomsChanged || !portalSet || portalNeedsUpdate)
{
SetRoomPortal();
}
}
public bool Overlaps(AkRoom room)
{
FindOverlappingRooms(roomList);
for (int i = 0; i < MAX_ROOMS_PER_PORTAL; ++i)
{
if (roomList[i].Contains(room))
{
return true;
}
}
return false;
}
public bool IsValid
{
get
{
// portal is valid if its front and back rooms are different
bool isPortalValid = frontRoomID != backRoomID;
// portal is valid if its front and back room don't have a ReverbZone-parent relationship
if (isPortalValid && frontRoom && frontRoom.IsAReverbZoneInWwise)
{
isPortalValid = backRoomID != frontRoom.ParentRoomID;
}
if (isPortalValid && backRoom && backRoom.IsAReverbZoneInWwise)
{
isPortalValid = frontRoomID != backRoom.ParentRoomID;
}
#if UNITY_EDITOR
// check all reverb zone components
if (isPortalValid)
{
AkReverbZone[] reverbZoneComponents = UnityEngine.Resources.FindObjectsOfTypeAll<AkReverbZone>();
for (uint i = 0; i < reverbZoneComponents.Length; ++i)
{
if (reverbZoneComponents[i].isActiveAndEnabled && reverbZoneComponents[i].ReverbZone)
{
ulong reverbZoneID = reverbZoneComponents[i].ReverbZone.GetID();
ulong parentRoomID = AkRoom.INVALID_ROOM_ID;
if (reverbZoneComponents[i].ParentRoom != null)
{
parentRoomID = reverbZoneComponents[i].ParentRoom.GetID();
}
isPortalValid = !(frontRoomID == reverbZoneID && backRoomID == parentRoomID);
isPortalValid = isPortalValid && !(backRoomID == reverbZoneID && frontRoomID == parentRoomID);
}
}
}
#endif
return isPortalValid;
}
}
/// Access the portal's ID
public ulong GetID() { return (ulong)GetInstanceID(); }
protected override void Awake()
{
portalCollider = GetComponent<UnityEngine.BoxCollider>();
portalCollider.isTrigger = true;
portalTransform = new AkTransform();
// set portal in it's initial state
portalActive = initialState != State.Closed;
RegisterTriggers(closePortalTriggerList, ClosePortal);
// init update condition
previousPosition = transform.position;
previousScale = transform.lossyScale;
previousRotation = transform.rotation;
base.Awake();
}
protected override void Start()
{
base.Start();
//Call the ClosePortal function if registered to the Start Trigger
if (closePortalTriggerList.Contains(START_TRIGGER_ID))
{
ClosePortal(null);
}
}
/// Opens the portal on trigger event
public override void HandleEvent(UnityEngine.GameObject in_gameObject)
{
Open();
}
/// Closes the portal on trigger event
public void ClosePortal(UnityEngine.GameObject in_gameObject)
{
Close();
}
protected override void OnDestroy()
{
base.OnDestroy();
UnregisterTriggers(closePortalTriggerList, ClosePortal);
}
public override void OnEnable()
{
AkRoomManager.RegisterPortal(this);
base.OnEnable();
}
private void OnDisable()
{
AkRoomManager.UnregisterPortal(this);
if (portalSet)
{
AkUnitySoundEngine.RemovePortal(GetID());
}
portalSet = false;
}
private void Update()
{
if (previousPosition != transform.position ||
previousScale != transform.lossyScale ||
previousRotation != transform.rotation)
{
portalNeedsUpdate = true;
AkRoomManager.RegisterPortalUpdate(this);
previousPosition = transform.position;
previousScale = transform.lossyScale;
previousRotation = transform.rotation;
}
}
private bool IsRoomActive(AkRoom in_room)
{
return in_room != null && in_room.isActiveAndEnabled;
}
public void Open()
{
portalActive = true;
}
public void Close()
{
portalActive = false;
}
public void FindOverlappingRooms(AkRoom.PriorityList[] roomList)
{
var portalCollider = gameObject.GetComponent<UnityEngine.BoxCollider>();
if (portalCollider == null)
{
return;
}
// compute halfExtents and divide the local z extent by 2
var halfExtentZ = portalCollider.size.z / 2;
// move the center backward
FillRoomList(UnityEngine.Vector3.forward * -halfExtentZ, roomList[0]);
// move the center forward
FillRoomList(UnityEngine.Vector3.forward * halfExtentZ, roomList[1]);
}
private void FillRoomList(UnityEngine.Vector3 position, AkRoom.PriorityList list)
{
list.Clear();
position = transform.TransformPoint(position);
var colliders = UnityEngine.Physics.OverlapSphere(position, 0, -1, UnityEngine.QueryTriggerInteraction.Collide);
foreach (var collider in colliders)
{
var room = collider.gameObject.GetComponent<AkRoom>();
if (room != null && !list.Contains(room))
{
list.Add(room);
}
}
}
public bool UpdateRooms()
{
FindOverlappingRooms(roomList);
bool wasUpdated = false;
for (var i = 0; i < MAX_ROOMS_PER_PORTAL; ++i)
{
var room = roomList[i].GetHighestPriorityActiveAndEnabledRoom();
if (room != rooms[i])
{
wasUpdated = true;
}
rooms[i] = room;
}
return wasUpdated;
}
#if UNITY_EDITOR
private void OnDrawGizmos()
{
if (!enabled)
{
return;
}
UnityEngine.Gizmos.matrix = transform.localToWorldMatrix;
var centreOffset = UnityEngine.Vector3.zero;
var sizeMultiplier = UnityEngine.Vector3.one;
var collider = GetComponent<UnityEngine.BoxCollider>();
if (collider)
{
centreOffset = collider.center;
sizeMultiplier = collider.size;
}
// color faces
var faceCenterPos = new UnityEngine.Vector3[6];
faceCenterPos[0] = UnityEngine.Vector3.Scale(new UnityEngine.Vector3(0.5f, 0.0f, 0.0f), sizeMultiplier);
faceCenterPos[1] = UnityEngine.Vector3.Scale(new UnityEngine.Vector3(0.0f, 0.5f, 0.0f), sizeMultiplier);
faceCenterPos[2] = UnityEngine.Vector3.Scale(new UnityEngine.Vector3(-0.5f, 0.0f, 0.0f), sizeMultiplier);
faceCenterPos[3] = UnityEngine.Vector3.Scale(new UnityEngine.Vector3(0.0f, -0.5f, 0.0f), sizeMultiplier);
faceCenterPos[4] = UnityEngine.Vector3.Scale(new UnityEngine.Vector3(0.0f, 0.0f, 0.5f), sizeMultiplier);
faceCenterPos[5] = UnityEngine.Vector3.Scale(new UnityEngine.Vector3(0.0f, 0.0f, -0.5f), sizeMultiplier);
var faceSize = new UnityEngine.Vector3[6];
faceSize[0] = new UnityEngine.Vector3(0, 1, 1);
faceSize[1] = new UnityEngine.Vector3(1, 0, 1);
faceSize[2] = faceSize[0];
faceSize[3] = faceSize[1];
faceSize[4] = new UnityEngine.Vector3(1, 1, 0);
faceSize[5] = faceSize[4];
if (IsValid)
{
UnityEngine.Gizmos.color = new UnityEngine.Color32(255, 204, 0, 100);
}
else
{
UnityEngine.Gizmos.color = new UnityEngine.Color32(255, 0, 0, 100);
}
for (var i = 0; i < 4; i++)
{
UnityEngine.Gizmos.DrawCube(faceCenterPos[i] + centreOffset, UnityEngine.Vector3.Scale(faceSize[i], sizeMultiplier));
}
if (!portalActive)
{
UnityEngine.Gizmos.DrawCube(faceCenterPos[4] + centreOffset, UnityEngine.Vector3.Scale(faceSize[4], sizeMultiplier));
UnityEngine.Gizmos.DrawCube(faceCenterPos[5] + centreOffset, UnityEngine.Vector3.Scale(faceSize[5], sizeMultiplier));
}
// draw line in the center of the portal
var CornerCenterPos = faceCenterPos;
CornerCenterPos[0].y += 0.5f * sizeMultiplier.y;
CornerCenterPos[1].x -= 0.5f * sizeMultiplier.x;
CornerCenterPos[2].y -= 0.5f * sizeMultiplier.y;
CornerCenterPos[3].x += 0.5f * sizeMultiplier.x;
UnityEngine.Gizmos.color = UnityEngine.Color.green;
for (var i = 0; i < 4; i++)
{
UnityEngine.Gizmos.DrawLine(CornerCenterPos[i] + centreOffset, CornerCenterPos[(i + 1) % 4] + centreOffset);
}
}
#endif
#region Obsolete
[System.Obsolete(AkUnitySoundEngine.Deprecation_2019_2_0)]
public void SetRoom(int in_roomIndex, AkRoom in_room)
{
UnityEngine.Debug.LogFormat("SetRoom is deprecated. Highest priority, active and enabled room will be automatically chosen. Make sure room priorities and game object placements are correct.");
}
[System.Obsolete(AkUnitySoundEngine.Deprecation_2019_2_0)]
public void SetFrontRoom(AkRoom room)
{
UnityEngine.Debug.LogFormat("SetFrontRoom is deprecated. Highest priority, active and enabled room will be automatically chosen. Make sure room priorities and game object placements are correct.");
}
[System.Obsolete(AkUnitySoundEngine.Deprecation_2019_2_0)]
public void SetBackRoom(AkRoom room)
{
UnityEngine.Debug.LogFormat("SetBackRoom is deprecated. Highest priority, active and enabled room will be automatically chosen. Make sure room priorities and game object placements are correct.");
}
[System.Obsolete(AkUnitySoundEngine.Deprecation_2019_2_0)]
public void UpdateSoundEngineRoomIDs()
{
UpdateRoomPortal();
}
[System.Obsolete(AkUnitySoundEngine.Deprecation_2019_2_0)]
public void UpdateOverlappingRooms()
{
UpdateRooms();
}
#endregion
}
#endif // #if ! (UNITY_DASHBOARD_WIDGET || UNITY_WEBPLAYER || UNITY_WII || UNITY_WIIU || UNITY_NACL || UNITY_FLASH || UNITY_BLACKBERRY) // Disable under unsupported platforms.