2025-06-03 02:42:28 -04:00
#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 .
2026-03-14 03:13:10 -04:00
Copyright ( c ) 2025 Audiokinetic Inc .
2025-06-03 02:42:28 -04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
[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 ;
2026-03-14 03:13:10 -04:00
portalNeedsUpdate = true ;
2025-06-03 02:42:28 -04:00
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 ] ;
2026-03-14 03:13:10 -04:00
[UnityEngine.Tooltip("Set to true to set this portal as static: a portal that will not move during gameplay. A non-static portal will check the state of its transform each frame and update the portal in Wwise if there is a change.")]
/// Set to true to set this portal as static: a portal that will not move during gameplay. A non-static portal will check the state of its transform each frame and update the portal in Wwise if there is a change.
public bool isStatic = false ;
2025-06-03 02:42:28 -04:00
/// 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 ] ; } }
2026-03-14 03:13:10 -04:00
public bool isSetInWwise ( ) { return portalSet ; }
2025-06-03 02:42:28 -04:00
private AkTransform portalTransform ;
private UnityEngine . BoxCollider portalCollider ;
private bool portalSet = false ;
2026-03-14 03:13:10 -04:00
private bool portalNeedsUpdate = false ;
2025-06-03 02:42:28 -04:00
private void SetRoomPortal ( )
{
2026-03-14 03:13:10 -04:00
if ( ! AkUnitySoundEngine . IsInitialized ( ) )
2025-06-03 02:42:28 -04:00
{
return ;
}
2026-03-14 03:13:10 -04:00
if ( ! isActiveAndEnabled )
2025-06-03 02:42:28 -04:00
{
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 ) ) ;
2026-03-14 03:13:10 -04:00
AkUnitySoundEngine . SetRoomPortal ( GetID ( ) , frontRoomID , backRoomID , portalTransform , extent , active , name ) ;
2025-06-03 02:42:28 -04:00
portalSet = true ;
2026-03-14 03:13:10 -04:00
portalNeedsUpdate = false ;
2025-06-03 02:42:28 -04:00
}
else
{
2026-03-14 03:13:10 -04:00
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." ) ;
2025-06-03 02:42:28 -04:00
if ( portalSet )
{
2026-03-14 03:13:10 -04:00
AkUnitySoundEngine . RemovePortal ( GetID ( ) ) ;
portalSet = false ;
2025-06-03 02:42:28 -04:00
}
}
}
public void UpdateRoomPortal ( )
{
2026-03-14 03:13:10 -04:00
bool roomsChanged = UpdateRooms ( ) ;
if ( roomsChanged | | ! portalSet | | portalNeedsUpdate )
{
SetRoomPortal ( ) ;
}
2025-06-03 02:42:28 -04:00
}
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 ;
}
2026-03-14 03:13:10 -04:00
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 ;
}
}
2025-06-03 02:42:28 -04:00
/// 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
2026-03-14 03:13:10 -04:00
transform . hasChanged = false ;
2025-06-03 02:42:28 -04:00
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 )
{
2026-03-14 03:13:10 -04:00
AkUnitySoundEngine . RemovePortal ( GetID ( ) ) ;
2025-06-03 02:42:28 -04:00
}
portalSet = false ;
}
private void Update ( )
{
2026-03-14 03:13:10 -04:00
// don't update if is static
if ( isStatic ) return ;
if ( transform . hasChanged )
2025-06-03 02:42:28 -04:00
{
2026-03-14 03:13:10 -04:00
portalNeedsUpdate = true ;
2025-06-03 02:42:28 -04:00
AkRoomManager . RegisterPortalUpdate ( this ) ;
2026-03-14 03:13:10 -04:00
transform . hasChanged = false ;
2025-06-03 02:42:28 -04:00
}
}
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 ) ;
}
}
}
2026-03-14 03:13:10 -04:00
public bool UpdateRooms ( )
2025-06-03 02:42:28 -04:00
{
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 ;
}
2026-03-14 03:13:10 -04:00
return wasUpdated ;
2025-06-03 02:42:28 -04:00
}
#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 ] ;
2026-03-14 03:13:10 -04:00
if ( IsValid )
{
UnityEngine . Gizmos . color = new UnityEngine . Color32 ( 255 , 204 , 0 , 100 ) ;
}
else
{
UnityEngine . Gizmos . color = new UnityEngine . Color32 ( 255 , 0 , 0 , 100 ) ;
}
2025-06-03 02:42:28 -04:00
for ( var i = 0 ; i < 4 ; i + + )
{
UnityEngine . Gizmos . DrawCube ( faceCenterPos [ i ] + centreOffset , UnityEngine . Vector3 . Scale ( faceSize [ i ] , sizeMultiplier ) ) ;
}
if ( ! portalActive )
2026-03-14 03:13:10 -04:00
{
2025-06-03 02:42:28 -04:00
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 ;
2026-03-14 03:13:10 -04:00
UnityEngine . Gizmos . color = UnityEngine . Color . green ;
2025-06-03 02:42:28 -04:00
for ( var i = 0 ; i < 4 ; i + + )
{
UnityEngine . Gizmos . DrawLine ( CornerCenterPos [ i ] + centreOffset , CornerCenterPos [ ( i + 1 ) % 4 ] + centreOffset ) ;
}
}
#endif
#region Obsolete
2026-03-14 03:13:10 -04:00
[System.Obsolete(AkUnitySoundEngine.Deprecation_2019_2_0)]
2025-06-03 02:42:28 -04:00
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." ) ;
}
2026-03-14 03:13:10 -04:00
[System.Obsolete(AkUnitySoundEngine.Deprecation_2019_2_0)]
2025-06-03 02:42:28 -04:00
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." ) ;
}
2026-03-14 03:13:10 -04:00
[System.Obsolete(AkUnitySoundEngine.Deprecation_2019_2_0)]
2025-06-03 02:42:28 -04:00
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." ) ;
}
2026-03-14 03:13:10 -04:00
[System.Obsolete(AkUnitySoundEngine.Deprecation_2019_2_0)]
2025-06-03 02:42:28 -04:00
public void UpdateSoundEngineRoomIDs ( )
{
UpdateRoomPortal ( ) ;
}
2026-03-14 03:13:10 -04:00
[System.Obsolete(AkUnitySoundEngine.Deprecation_2019_2_0)]
2025-06-03 02:42:28 -04:00
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.