Kaynağa Gözat

添加一版简单的音效支持

大爷 1 yıl önce
ebeveyn
işleme
5683547b6f

+ 12 - 0
Unity/Assets/AssetBundleCollectorSetting.asset

@@ -148,3 +148,15 @@ MonoBehaviour:
       PackRuleName: PackDirectory
       FilterRuleName: CollectPrefab
       AssetTags: 
+  - GroupName: Sound
+    GroupDesc: "\u97F3\u6548"
+    AssetTags: 
+    ActiveRuleName: EnableGroup
+    Collectors:
+    - CollectPath: Assets/Res/Sounds
+      CollectorGUID: 86eee80c3ed841b46b7be6fdab5e8e69
+      CollectorType: 0
+      AddressRuleName: AddressByGroupAndFileName
+      PackRuleName: PackSeparately
+      FilterRuleName: CollectAll
+      AssetTags: 

+ 2 - 1
Unity/Assets/Scenes/Init.unity

@@ -849,7 +849,7 @@ AudioSource:
   Priority: 128
   DopplerLevel: 1
   MinDistance: 1
-  MaxDistance: 500
+  MaxDistance: 200
   Pan2D: 0
   rolloffMode: 0
   BypassEffects: 0
@@ -937,6 +937,7 @@ MonoBehaviour:
   m_Name: 
   m_EditorClassIdentifier: 
   Source: {fileID: 1270058933}
+  Listener: {fileID: 1984349701}
 --- !u!850595691 &1972482029
 LightingSettings:
   m_ObjectHideFlags: 0

+ 1 - 1
Unity/Assets/Scripts/Codes/Hotfix/Client/Login/EnterMapHelper.cs

@@ -24,7 +24,7 @@ namespace ET.Client
                     return;
                 }
 
-                SceneChangeHelper.SceneChangeTo(clientScene, mapinfo.MapName, g2CEnterMap.MapInstanceId).Coroutine();
+                SceneChangeHelper.SceneChangeTo(clientScene, mapinfo, g2CEnterMap.MapInstanceId).Coroutine();
                 // 等待场景切换完成
                 await clientScene.GetComponent<ObjectWait>().Wait<Wait_SceneChangeFinish>();
                 //告诉战斗服 i am ready

+ 3 - 3
Unity/Assets/Scripts/Codes/Hotfix/Client/Scene/SceneChangeHelper.cs

@@ -3,14 +3,14 @@
     public static class SceneChangeHelper
     {
         // 场景切换协程
-        public static async ETTask SceneChangeTo(Scene clientScene, string sceneName, long sceneInstanceId)
+        public static async ETTask SceneChangeTo(Scene clientScene, MapConfig map, long sceneInstanceId)
         {
             CurrentScenesComponent currentScenesComponent = clientScene.GetComponent<CurrentScenesComponent>();
             currentScenesComponent.Scene?.Dispose(); // 删除之前的CurrentScene,创建新的
-            SceneFactory.CreateCurrentScene(sceneInstanceId, clientScene.Zone, sceneName, currentScenesComponent);
+            SceneFactory.CreateCurrentScene(sceneInstanceId, clientScene.Zone, map.MapName, currentScenesComponent);
          
             // 可以订阅这个事件中创建Loading界面
-            EventSystem.Instance.Publish(clientScene, new EventType.SceneChangeStart());
+            EventSystem.Instance.Publish(clientScene, new EventType.SceneChangeStart() { mapId = map.Id});
 
             await ETTask.CompletedTask;
         }

+ 8 - 5
Unity/Assets/Scripts/Codes/Hotfix/Client/battle/BattleMgr.cs

@@ -1,9 +1,9 @@
 using CommonAI.Zone;
 using CommonAI.ZoneClient;
-using CommonLang;
 using CommonLang.Geometry;
 using ET.Client;
 using ET.EventType;
+using Sirenix.Utilities;
 using System;
 using System.IO;
 using XmdsCommon.Message;
@@ -15,7 +15,6 @@ namespace ET
     {
         public ZoneLayer Layer;
 
-        private bool isInited = false;
         private readonly MemoryStream writeBuffer = new MemoryStream(2048);
         private EventDispatcher<ZoneEvent> zoneEventHandler;
         private EventDispatcher<ObjectEvent> objectEventHandler;
@@ -35,13 +34,10 @@ namespace ET
             Layer.ObjectLeave += LayerEvent_ObjectLeave;
             Layer.MessageReceived += LayerEvent_MessageReceived;
             Layer.DecorationChanged += LayerEvent_DecorationChanged;
-            isInited = true;
         }
 
         public void Update(int timeMS)
         {
-            if (!isInited) return;
-
             //TODO: Send ping
             Layer.BeginUpdate(timeMS);
             Layer.Update();
@@ -53,6 +49,13 @@ namespace ET
         void ILayerClient.BattleReady(bool bok)
         {
             Log.Debug($"battle ready......{bok}");
+
+            //TODO: 等GameObjectPool.cache完场景资源后,再play bgm
+            var scnData = Layer.Data;
+            if(!scnData.BGM.IsNullOrWhitespace() )
+            {
+                EventSystem.Instance.Publish<PlayBgm>(PlayBgm.Static.Clone(true, scnData.BGM));
+            }
         }
 
         //ILayerClient接口实现,供layer层调用

+ 10 - 5
Unity/Assets/Scripts/Codes/HotfixView/Client/Effect/EffectMgr.cs

@@ -69,6 +69,11 @@ namespace ET.Client
                 if (time < 0f) time = EffectPlayInfo.TIME_FOREVER;
                 setupEffect(go, effect, render, pos, rotation);
             }
+            else if(!effect.SoundName.IsNullOrWhitespace())
+            {
+                //TODO: 音效的位置这里还有一堆逻辑的
+                SoundManager.Instance.Play3DSound(effect.SoundName, pos).Coroutine();
+            }
 
             if (effect.EarthQuakeMS > 0)
             {
@@ -76,11 +81,6 @@ namespace ET.Client
                 CameraMgr.ShakeMe(effect.EarthQuakeMS, vecTemp);
             }
 
-            if (!effect.SoundName.IsNullOrWhitespace())
-            {
-                //TODO: Sound
-            }
-
             if (go != null)
             {
                 var epi = ObjectPool.Instance.Fetch<EffectPlayInfo>();
@@ -155,6 +155,11 @@ namespace ET.Client
                 }
             }
             go.SetActive(true);
+
+            if (!effectData.SoundName.IsNullOrWhitespace())
+            {
+                SoundManager.Instance.Play3DSound(effectData.SoundName, gt.position).Coroutine();
+            }
         }
 
         public void Clear()

+ 1 - 1
Unity/Assets/Scripts/Codes/HotfixView/Client/EntryEvent3_InitClient.cs

@@ -8,7 +8,7 @@
             Root.Instance.Scene.AddComponent<GlobalViewComponent>();
 
             Game.AddSingleton<EffectMgr>();
-            //Game.AddSingleton<SoundManager>();
+            Game.AddSingleton<SoundManager>();
 
             Scene clientScene = await SceneFactory.CreateClientScene(1, "Game");
             await EventSystem.Instance.PublishAsync(clientScene, new EventType.AppStartInitFinish());

+ 1 - 0
Unity/Assets/Scripts/Codes/HotfixView/Client/Scene/AfterCreateCurrentScene_AddComponent.cs

@@ -7,6 +7,7 @@
         {
             scene.AddComponent<GameObjectPool>();
             scene.AddComponent<ModelViewComponent>();
+            //scene.AddComponent<OperaComponent>();
             await ETTask.CompletedTask;
         }
     }

+ 96 - 26
Unity/Assets/Scripts/Codes/HotfixView/Client/Scene/GameObjectPool.cs

@@ -1,7 +1,9 @@
 using CommonAI.Zone;
+using CommonAI.Zone.ZoneEditor;
 using CommonLang;
 using Sirenix.Utilities;
 using System.Collections.Generic;
+using System.Text.RegularExpressions;
 using UnityEngine;
 
 namespace ET.Client
@@ -36,12 +38,25 @@ namespace ET.Client
         public static GameObjectPool Instance;
 
         private readonly HashMap<string, List<GameObject>> goPool = new();
+        private readonly HashMap<string, AudioClip> audioPool = new();
 
         //TODO: 选取当前场景的单位、技能(事件触发等等)
         //TODO: BUFF
-        public async ETTask CacheSceneObject(/*int scnId*/)
+        public async ETTask CacheSceneObject(int scnId)
         {
-            var templates = BattleResourceMgr.Instance.GameEditorTemplates.Templates;
+            var mgr = BattleResourceMgr.Instance.GameEditorTemplates;
+            var templates = mgr.Templates;
+
+            SceneData sceneData = mgr.LoadScene(scnId, false, true);
+            BattleMgr.Instance.Layer.Data = sceneData;
+
+            List<string> effectlist = new();
+            List<string> soundlist = new();
+
+            if(!sceneData.BGM.IsNullOrWhitespace())
+            {
+                soundlist.Add(sceneData.BGM);
+            }
 
             //遍历模型
             var units = templates.getUnits();
@@ -53,9 +68,12 @@ namespace ET.Client
                 var gameobj = UnityEngine.Object.Instantiate(prefab, GlobalViewComponent.Instance.RecycleNode, true);
                 gameobj.name = name;
                 RecycleObject(gameobj);
+
+                if(unit.FootCircleEffect != null) CacheLaunchEffect(unit.FootCircleEffect, ref effectlist, ref soundlist);
+                if (unit.SpawnEffect != null) CacheLaunchEffect(unit.SpawnEffect, ref effectlist, ref soundlist);
+                if (unit.DeadActionEffect != null) CacheLaunchEffect(unit.DeadActionEffect, ref effectlist, ref soundlist);
             }
 
-            List<string> effectlist = new();
             var skills = templates.getAllSkillData();
             foreach (var skt in skills.Values)
             {
@@ -67,13 +85,13 @@ namespace ET.Client
                     }
                     foreach (var kf in act.KeyFrames)
                     {
-                        if (kf.Effect != null && !kf.Effect.Name.IsNullOrWhitespace())
+                        if (kf.Effect != null)
                         {
-                            effectlist.Add(kf.Effect.Name);
+                            CacheLaunchEffect(kf.Effect, ref effectlist, ref soundlist);
                         }
                         if (kf.Spell != null)
                         {
-                            CacheSpellEffect(templates, kf.Spell.SpellID, ref effectlist);
+                            CacheSpellEffect(templates, kf.Spell.SpellID, ref effectlist, ref soundlist);
                         }
                     }
                 }
@@ -88,9 +106,40 @@ namespace ET.Client
                 gameobj.name = name;
                 RecycleObject(gameobj);
             }
+
+            foreach(var sound in soundlist)
+            {
+                var key = sound;
+                var m = Regex.Match(key, "/?res/sound/.*/([\\w_\\d]+)\\.assetbundles$");
+                if (m.Success)
+                {
+                    key = m.Groups[1].Value.ToLower();
+                }
+                if(audioPool.ContainsKey(key))
+                {
+                    continue;
+                }
+                //Log.Debug($"cache audio: {key}");
+                var handle = await YooAssetProxy.LoadAssetAsync<AudioClip>($"Sound_{key}");
+                var ac = handle.GetAssetObject<AudioClip>();
+                ac.LoadAudioData();
+                audioPool.Add(key, ac);
+            }
         }
 
-        private void CacheSpellEffect(TemplateManager templates, int spellid, ref List<string> effectlist)
+        private void CacheLaunchEffect(LaunchEffect effect, ref List<string>effectlist, ref List<string> soundlist)
+        {
+            if(!effect.Name.IsNullOrWhitespace())
+            {
+                effectlist.Add(effect.Name);
+            }
+            if(!effect.SoundName.IsNullOrWhitespace())
+            {
+                soundlist.Add(effect.SoundName);
+            }
+        }
+
+        private void CacheSpellEffect(TemplateManager templates, int spellid, ref List<string> effectlist, ref List<string> soundlist)
         {
             var spell = templates.getSpell(spellid);
             if (spell == null)
@@ -106,24 +155,24 @@ namespace ET.Client
             var frame = spell.HitIntervalKeyFrame;
             if (frame != null)
             {
-                if (frame.Effect != null && !frame.Effect.Name.IsNullOrWhitespace())
+                if (frame.Effect != null)
                 {
-                    effectlist.Add(frame.Effect.Name);
+                    CacheLaunchEffect(frame.Effect, ref effectlist, ref soundlist);
                 }
                 if (frame.Spell != null && frame.Spell.SpellID != 0)
                 {
-                    CacheSpellEffect(templates, frame.Spell.SpellID, ref effectlist);
+                    CacheSpellEffect(templates, frame.Spell.SpellID, ref effectlist, ref soundlist);
                 }
                 if (frame.Attack != null)
                 {
                     var attack = frame.Attack;
-                    if (attack.Effect != null && !attack.Effect.Name.IsNullOrWhitespace())
+                    if (attack.Effect != null)
                     {
-                        effectlist.Add(attack.Effect.Name);
+                        CacheLaunchEffect(attack.Effect, ref effectlist, ref soundlist);
                     }
                     if (attack.Spell != null && attack.Spell.SpellID != 0)
                     {
-                        CacheSpellEffect(templates, attack.Spell.SpellID, ref effectlist);
+                        CacheSpellEffect(templates, attack.Spell.SpellID, ref effectlist, ref soundlist);
                     }
                 }
             }
@@ -131,48 +180,48 @@ namespace ET.Client
             frame = spell.HitOnExplosionKeyFrame;
             if (spell.HitOnExplosion && frame != null)
             {
-                if (frame.Effect != null && !frame.Effect.Name.IsNullOrWhitespace())
+                if (frame.Effect != null)
                 {
-                    effectlist.Add(frame.Effect.Name);
+                    CacheLaunchEffect(frame.Effect, ref effectlist, ref soundlist);
                 }
                 if (frame.Spell != null && frame.Spell.SpellID != 0)
                 {
-                    CacheSpellEffect(templates, frame.Spell.SpellID, ref effectlist);
+                    CacheSpellEffect(templates, frame.Spell.SpellID, ref effectlist, ref soundlist);
                 }
                 if (frame.Attack != null)
                 {
                     var attack = frame.Attack;
-                    if (attack.Effect != null && !attack.Effect.Name.IsNullOrWhitespace())
+                    if (attack.Effect != null)
                     {
-                        effectlist.Add(attack.Effect.Name);
+                        CacheLaunchEffect(attack.Effect, ref effectlist, ref soundlist);
                     }
                     if (attack.Spell != null && attack.Spell.SpellID != 0)
                     {
-                        CacheSpellEffect(templates, attack.Spell.SpellID, ref effectlist);
+                        CacheSpellEffect(templates, attack.Spell.SpellID, ref effectlist, ref soundlist);
                     }
                 }
             }
 
             foreach (var frm in spell.KeyFrames)
             {
-                if (frm.Effect != null && !frm.Effect.Name.IsNullOrWhitespace())
+                if (frm.Effect != null)
                 {
-                    effectlist.Add(frm.Effect.Name);
+                    CacheLaunchEffect(frm.Effect, ref effectlist, ref soundlist);
                 }
                 if (frm.Spell != null && frame.Spell.SpellID != 0)
                 {
-                    CacheSpellEffect(templates, frm.Spell.SpellID, ref effectlist);
+                    CacheSpellEffect(templates, frm.Spell.SpellID, ref effectlist, ref soundlist);
                 }
                 if (frm.Attack != null)
                 {
                     var attack = frm.Attack;
-                    if (attack.Effect != null && !attack.Effect.Name.IsNullOrWhitespace())
+                    if (attack.Effect != null)
                     {
-                        effectlist.Add(attack.Effect.Name);
+                        CacheLaunchEffect(attack.Effect, ref effectlist, ref soundlist);
                     }
                     if (attack.Spell != null && attack.Spell.SpellID != 0)
                     {
-                        CacheSpellEffect(templates, attack.Spell.SpellID, ref effectlist);
+                        CacheSpellEffect(templates, attack.Spell.SpellID, ref effectlist, ref soundlist);
                     }
                 }
             }
@@ -188,6 +237,12 @@ namespace ET.Client
                 }
             }
             goPool.Clear();
+
+            foreach(var ac in audioPool.Values)
+            {
+                ac.UnloadAudioData();
+            }
+            audioPool.Clear();
         }
 
         public void RecycleObject(GameObject go, string key = "")
@@ -224,7 +279,7 @@ namespace ET.Client
             {
                 goPool.Add(key, new List<GameObject>());
             }
-            Log.Warning($"new gameobject: ({key})");
+            Log.Warning($"not cache gameobject: ({key})");
 
             var handle = await YooAssetProxy.LoadAssetAsync<GameObject>(key);
             var prefab = handle.GetAssetObject<GameObject>();
@@ -232,5 +287,20 @@ namespace ET.Client
             gameobj.name = key;
             return gameobj;
         }
+
+        public async ETTask<AudioClip> AcquireSound(string key)
+        {
+            if(audioPool.TryGetValue(key, out var ac))
+            {
+                return ac;
+            }
+            Log.Warning($"not cache audio: ({key})");
+
+            var handle = await YooAssetProxy.LoadAssetAsync<AudioClip>($"Sound_{key}");
+            var aac = handle.GetAssetObject<AudioClip>();
+            aac.LoadAudioData();
+            audioPool.Add(key, aac);
+            return aac;
+        }
     }
 }

+ 4 - 4
Unity/Assets/Scripts/Codes/HotfixView/Client/Scene/SceneChangeStart_AddComponent.cs

@@ -8,8 +8,9 @@ namespace ET.Client
         protected override async ETTask Run(Scene scene, EventType.SceneChangeStart args)
         {
             UIHelper.Create("Loading").Coroutine();
-            Scene currentScene = scene.CurrentScene();
-            var scnName = currentScene.Name;
+
+            var mapInfo = MapConfigCategory.Instance.Get(args.mapId);
+            var scnName = mapInfo.MapName;
             Log.Debug($"loading scene: {scnName}.");
             // 加载场景资源 & 加载
             var task = await YooAssetProxy.LoadSceneAsync("Scene_" + scnName);
@@ -18,9 +19,8 @@ namespace ET.Client
             await TimerComponent.Instance.WaitAsync(1000);
             UIHelper.Remove("Lobby");
             UIHelper.SetVisible("Loading", false);
-            currentScene.AddComponent<OperaComponent>();
 
-            await GameObjectPool.Instance.CacheSceneObject();
+            await GameObjectPool.Instance.CacheSceneObject(mapInfo.Id);
 
             // 通知等待场景切换的协程
             EventSystem.Instance.Publish<EventType.SceneLoadFinish>();

+ 8 - 0
Unity/Assets/Scripts/Codes/HotfixView/Client/Sound.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 7a09fc521359e9043afd79dff3593662
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 85 - 0
Unity/Assets/Scripts/Codes/HotfixView/Client/Sound/SoundManager.cs

@@ -0,0 +1,85 @@
+using Animancer;
+using ET;
+using ET.Client;
+using ET.EventType;
+using Mono;
+using System.Text.RegularExpressions;
+using UnityEngine;
+
+[Event(SceneType.None)]
+public class PlayBGMHandler : BEvent<ET.EventType.PlayBgm>
+{
+    public override void OnEvent(PlayBgm args)
+    {
+        if (args.Play)
+        {
+            SoundManager.Instance.PlayBgm(args.Bgm).Coroutine();
+        }
+        else
+        {
+            SoundManager.Instance.StopBgm();
+        }
+    }
+}
+
+public class SoundManager : Singleton<SoundManager>, ISingletonAwake
+{
+    public AudioSource UnityAudioSource { get; private set; }
+    public bool Mute
+    {
+        get { return UnityAudioSource.mute; }
+        set { UnityAudioSource.mute = value; }
+    }
+    public float Volume
+    {
+        get { return UnityAudioSource.volume; }
+        set { UnityAudioSource.volume = value; }
+    }
+    public void Awake()
+    {
+        UnityAudioSource = AudioComponent.Instance.Source;
+        UnityAudioSource.loop = true;
+        UnityAudioSource.volume = 1f;
+    }
+
+    public async ETTask PlayBgm(string name)
+    {
+        Log.Debug($"play bgm:{name}");
+        var ac = await GameObjectPool.Instance.AcquireSound(name);
+        UnityAudioSource.clip = ac;
+        UnityAudioSource.Play();
+    }
+    public void StopBgm()
+    {
+        Log.Debug("stop bgm");
+        UnityAudioSource.Stop();
+    }
+
+    public async ETTask PlayUISound(string name, float duration = -1f)
+    {
+        var key = name;
+        var m = Regex.Match(key, "/?res/sound/.*/([\\w_\\d]+)\\.assetbundles$");
+        if (m.Success)
+        {
+            key = m.Groups[1].Value.ToLower();
+        }
+        var ac = await GameObjectPool.Instance.AcquireSound(key);
+        UnityAudioSource.PlayOneShot(ac);
+    }
+
+    //TODO:实现3D音源随物体移动
+    public async ETTask Play3DSound(string name, Vector3 pos, float duration = -1f)
+    {
+        var key = name;
+        var m = Regex.Match(key, "/?res/sound/.*/([\\w_\\d]+)\\.assetbundles$");
+        if (m.Success)
+        {
+            key = m.Groups[1].Value.ToLower();
+        }
+        //Log.Debug($"play 3dsound: {key}");
+        var ac = await GameObjectPool.Instance.AcquireSound(key);
+        //AudioSource.PlayClipAtPoint(ac, pos);
+        UnityAudioSource.PlayOneShot(ac);
+
+    }
+}

+ 11 - 0
Unity/Assets/Scripts/Codes/HotfixView/Client/Sound/SoundManager.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 75e28736c556744459df0739f25e4ec9
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 13 - 0
Unity/Assets/Scripts/Codes/Model/Client/EventTypeClient.cs

@@ -83,6 +83,19 @@ namespace ET
                 return this;
             }
         }
+        public class PlayBgm
+        {
+            public bool Play;
+            public string Bgm;
+
+            public static PlayBgm Static = new PlayBgm();
+            public PlayBgm Clone(bool play, string bgm)
+            {
+                Play = play;
+                Bgm = bgm;
+                return this;
+            }
+        }
     }
 
     //状态指令

+ 3 - 1
Unity/Assets/Scripts/Codes/Model/Share/EventType.cs

@@ -3,7 +3,9 @@ namespace ET
 {
     namespace EventType
     {
-        public struct SceneChangeStart { }
+        public struct SceneChangeStart {
+            public int mapId;
+        }
         public struct SceneChangeFinish { }
         public struct AfterCreateClientScene { }
         public struct AfterCreateCurrentScene { }

+ 16 - 0
Unity/Assets/Scripts/Codes/Mono/AudioComponent.cs

@@ -0,0 +1,16 @@
+using UnityEngine;
+
+namespace Mono
+{
+    public class AudioComponent : MonoBehaviour
+    {
+        public static AudioComponent Instance;
+        public AudioSource Source;
+        public AudioListener Listener;
+
+        protected void Awake()
+        {
+            Instance = this;
+        }
+    }
+}

+ 11 - 0
Unity/Assets/Scripts/Codes/Mono/AudioComponent.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 34b0cf3d7495149429324838ac38fbc8
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: