using System; using System.Linq; using UnityEngine; using Wwise.Wooduan.Components; using Wwise.Wooduan.Core; using Wwise.Wooduan.Tools; public enum PortalType { Door, Window, Entrance, All } public partial class AkRoomPortal : AkSpace, IAkSpatialAudioObject, ICullableAudioObject { public PortalType portalType = PortalType.Window; public bool isOpened; public AkSpatialAudioRoom frontRoom; public AkSpatialAudioRoom backRoom; [Tooltip("If door or windows has multiple members, it will open when any member is open.")] public int groupSize = 1; private int _currentOpenedMembers; internal bool IsPendingRoom { get; private set; } protected override void OnEnable() { IsCulled = SpatialAudioManager.CullByEmitter; base.OnEnable(); } private ulong GetRoomID(AkSpatialAudioRoom room) { if (!room) return AkRoom.INVALID_ROOM_ID; if (!room.IsRegisteredInWwise) { IsPendingRoom = true; Debug.LogError("Portal " + name + " inits earlier than room " + room.name); return AkRoom.INVALID_ROOM_ID; } return room.GetID(); } private void FillOutdoorRooms() { if (!frontRoom) frontRoom = AkOutdoor.GetInstance(); if (!backRoom) backRoom = AkOutdoor.GetInstance(); } internal void TogglePortal(bool opened) { if (opened) { if (_currentOpenedMembers < groupSize) _currentOpenedMembers++; else return; } if (!opened) { if (_currentOpenedMembers > 0) _currentOpenedMembers--; else return; if (_currentOpenedMembers != 0) return; } isOpened = opened; SetPortal(); } internal override bool IsPositionWithinSpace(Vector3 position) { return GetDistanceToPosition(position) < 1f; } internal override void Refresh(bool active) { if (active && SpatialAudioManager.RoomEnabled) RegisterInWwise(); else UnregisterInWwise(); } #region LifeCycle protected override void Init() { switch (portalType) { case PortalType.Entrance: isOpened = true; break; case PortalType.Window: isOpened = SpatialAudioManager.CullByEmitter; break; case PortalType.Door: isOpened = false; break; } if (frontRoom) frontRoom.RegisterPortal(this); if (backRoom) backRoom.RegisterPortal(this); } protected override void Dispose() { if (frontRoom) frontRoom.UnregisterPortal(this); if (backRoom) backRoom.UnregisterPortal(this); } #endregion LifeCycle public void UpdateRooms() { // compute halfExtents and divide the local z extent by 2 var halfExtentZ = Collider.size.z / 2; var positionBack = transform.TransformPoint(Vector3.forward * -halfExtentZ); backRoom = SpatialAudioManager.FindRoomAtPosition(positionBack); var positionFront = transform.TransformPoint(Vector3.forward * halfExtentZ); frontRoom = SpatialAudioManager.FindRoomAtPosition(positionFront); } private AKRESULT SetPortal() { if (IsCulled) return AKRESULT.AK_Cancelled; if (!frontRoom) frontRoom = AkOutdoor.GetInstance(); if (!backRoom) backRoom = AkOutdoor.GetInstance(); var frontRoomID = GetRoomID(frontRoom); var backRoomID = GetRoomID(backRoom); if (frontRoomID == AkRoom.INVALID_ROOM_ID || backRoomID == AkRoom.INVALID_ROOM_ID) { Debug.LogError($"AkRoomPortal {name} has invalid front or back room!"); AkOutdoor.PendingPortals.Add(this); return AKRESULT.AK_Cancelled; } if (frontRoomID == backRoomID) { Debug.LogError($"AkRoomPortal {name} has identical front and back room {frontRoom.name}!"); return AKRESULT.AK_Fail; } var portalTransform = new AkTransform(); portalTransform.Set(Collider.bounds.center, transform.forward, transform.up); var extentVector = UnityEngine.Vector3.Scale(Collider.size, transform.localScale) / 2; var extent = new AkExtent(Mathf.Abs(extentVector.x), Mathf.Abs(extentVector.y), Mathf.Abs(extentVector.z)); var result = AkSoundEngine.SetRoomPortal(GetID(), frontRoomID, backRoomID, portalTransform, extent, isOpened, name); AkWooduanHelper.DebugToConsole( result == AKRESULT.AK_Success ? AudioLogVerbosity.Notification : AudioLogVerbosity.Error, AudioObjectType.Portal, AudioTriggerSource.AkRoomPortal, AudioAction.Activate, name, gameObject); return result; } public override bool IsValid() { return frontRoom != backRoom && Collider; } #region IAkSpatialAudioObject public bool IsRegisteredInWwise { get; set; } public void RegisterInWwise() { if (AkSoundEngine.IsInitialized() && !IsRegisteredInWwise) IsRegisteredInWwise = SetPortal() == AKRESULT.AK_Success; if (IsRegisteredInWwise) IsPendingRoom = false; } public void UnregisterInWwise() { if (!AkSoundEngine.IsInitialized() || !IsRegisteredInWwise) return; IsRegisteredInWwise = AkSoundEngine.RemovePortal(GetID()) != AKRESULT.AK_Success; if (!IsRegisteredInWwise) { AkWooduanHelper.DebugToConsole(AudioLogVerbosity.Notification, AudioObjectType.Portal, AudioTriggerSource.AkRoomPortal, AudioAction.Deactivate, name, gameObject); } } #endregion IAkSpatialAudioObject #region ICullableAudioObject public int RoomsUsing { get => _roomsUsing; set { if (_roomsUsing == 0 && value > 0) OnReveal(); else if (_roomsUsing > 0 && value == 0) OnCull(); _roomsUsing = value; } } private int _roomsUsing = 0; public bool IsCulled { get; set; } public void TryCull(Vector3 listenerPosition) { } public void OnCull() { if (IsCulled) return; IsCulled = true; Refresh(false); } public void OnReveal() { if (!IsCulled) return; IsCulled = false; Refresh(true); } #endregion ICullableAudioObject #if UNITY_EDITOR public void AutoRename() { UpdateRooms(); if (!frontRoom && backRoom) transform.Rotate(Vector3.up, 180); UpdateRooms(); var buildingName = transform.parent.parent.name; var frontRoomName = frontRoom ? frontRoom.name.Split('_').Last() : "Outdoor"; var backRoomName = backRoom ? backRoom.name.Split('_').Last() : "Outdoor"; var newName = $"AkPortal_{buildingName}_{portalType}_{frontRoomName}-{backRoomName}"; gameObject.name = newName; } public void Rotate() { var originalScale = transform.localScale; transform.localScale = new Vector3(originalScale.z, originalScale.y, originalScale.x); transform.Rotate(Vector3.up, 90); } #endif }