Browse Source

增加特效播放支持

大爷 2 years ago
parent
commit
a8bb2d3d12

+ 21 - 7
Unity/Assets/Scripts/Codes/Hotfix/Client/battle/BattleMgr.cs

@@ -1,14 +1,16 @@
 using CommonAI.Zone;
 using CommonAI.ZoneClient;
 using CommonLang;
+using CommonLang.Geometry;
 using ET.Client;
+using ET.EventType;
 using System.IO;
 using XmdsCommon.Message;
 
 namespace ET
 {
     [FriendOf(typeof(UnitMgr))]
-    public partial class BattleMgr : Singleton<BattleMgr>, ISingletonUpdate, ILayerClient
+    public partial class BattleMgr : Singleton<BattleMgr>, ISingletonAwake, ISingletonUpdate, ILayerClient
     {
         public ZoneLayer Layer;
 
@@ -16,8 +18,9 @@ namespace ET
         private readonly MemoryStream writeBuffer = new MemoryStream(2048);
         private EventDispatcher<ZoneEvent> zoneEventHandler;
         private EventDispatcher<ObjectEvent> objectEventHandler;
+        private static CommonLang.Geometry.Vector3 vecTemp = new();
 
-        public async ETTask InitAsync()
+        public void Awake()
         {
             zoneEventHandler = new();
             objectEventHandler = new();
@@ -32,8 +35,6 @@ namespace ET
             Layer.MessageReceived += LayerEvent_MessageReceived;
             Layer.DecorationChanged += LayerEvent_DecorationChanged;
             isInited = true;
-
-            await ETTask.CompletedTask;
         }
 
         public void Update()
@@ -73,6 +74,7 @@ namespace ET
         //客户端自己模拟创建消息,发送到zonelayer层处理
         public void PostMsg2Layer(CommonLang.Protocol.IMessage msg)
         {
+            Layer.ProcessMessage(msg);
         }
 
         //layer层在处理好战斗服推送的ClientEnterScene消息后回调
@@ -85,7 +87,7 @@ namespace ET
         //单位进入战斗  
         protected void LayerEvent_ObjectEnter(ZoneLayer layer, ZoneObject obj)
         {
-            Log.Debug($"OnObjectEnter: {obj.Name}");
+            Log.Debug($"OnObjectEnter: {obj}@{obj.ObjectID}");
 
             var unit = BattleUnitFactory.Instance.Create(obj);
             if(unit != null )
@@ -106,7 +108,7 @@ namespace ET
         //单位离开战斗   
         protected void LayerEvent_ObjectLeave(ZoneLayer layer, ZoneObject obj)
         {
-            Log.Debug($"OnObjectLeave: {obj.Name}");
+            Log.Debug($"OnObjectLeave: {obj.ObjectID}");
 
             var unit = UnitMgr.Instance.GetUnit(obj.ObjectID);
             if(unit == null)
@@ -174,13 +176,25 @@ namespace ET
             objectEventHandler.AddListener<BuffActiveSkillEventB2C>((ev) =>
             {
             });
+            objectEventHandler.AddListener<UnitEffectEvent>((ev) =>
+            {
+                var e = ev as UnitEffectEvent;
+                EventSystem.Instance.Publish<PlayEffectEvent>(PlayEffectEvent.Static.Clone(e.effect, e.ObjectID, CommonLang.Geometry.Vector3.Zero));
+            });
             //NPCCureEventB2C
             //MonsterSufferDamageInfoB2C
             //BattleHintNumberB2C
             //BattleFloatTipsEventB2C
             //BubbleTipsEventB2C
 
-            zoneEventHandler.AddListener<ChatEvent>((ev) => { });
+            zoneEventHandler.AddListener<AddEffectEvent>((ev) => {
+                var e = ev as AddEffectEvent;
+                if(e.hostId == 0 || UnitMgr.Instance.HasUnit(e.hostId))
+                {
+                    vecTemp.Set(e.x, e.y, 0);
+                    EventSystem.Instance.Publish<PlayEffectEvent>(PlayEffectEvent.Static.Clone(e.effect, e.hostId, vecTemp));
+                }
+            });
             /*BubbleTalkEvent
             AddEffectEvent
             SyncEnvironmentVarEvent

+ 6 - 1
Unity/Assets/Scripts/Codes/Hotfix/Client/battle/BattleResourceMgr.cs

@@ -13,11 +13,16 @@ using XmdsCommon.Plugin;
 using Log = ET.Log;
 
 
-public class BattleResourceMgr : Singleton<BattleResourceMgr>
+public class BattleResourceMgr : Singleton<BattleResourceMgr>, ISingletonAwake
 {
     public EditorTemplates GameEditorTemplates;
     public SynchronizedBattleCodec BattleMsgDecoder;
 
+    public void Awake()
+    {
+        InitAsync().Coroutine();
+    }
+
     public async ETTask InitAsync()
     {
         GameEditorTemplates = new EditorTemplates("", TemplateManager.MessageCodec);

+ 0 - 5
Unity/Assets/Scripts/Codes/Hotfix/Client/battle/BattleUnitFactory.cs

@@ -5,11 +5,6 @@ using UnitType = CommonAI.Zone.UnitInfo.UnitType;
 
 class BattleUnitFactory : Singleton<BattleUnitFactory>//, ISingletonUpdate
 {
-    public async ETTask InitAsync()
-    {
-        await ETTask.CompletedTask;
-    }
-
     public BattleObject Create(ZoneObject zo)
     {
         BattleObject unit = null;

+ 23 - 6
Unity/Assets/Scripts/Codes/HotfixView/Client/Camera/CameraMgr.cs

@@ -1,16 +1,33 @@
-using UnityEngine;
+using DG.Tweening;
+using UnityEngine;
 
 namespace ET.Client
 {
-	public static class CameraMgr
-	{
+    [FriendOfAttribute(typeof(ET.Client.GlobalViewComponent))]
+    public static class CameraMgr
+    {
         //相机跟随主角
         public static void FollowMe(Vector3 pos)
-		{
+        {
             var camera = Camera.main;
             pos.y = 7;
             pos.z -= 15;
             camera.transform.position = pos;
-		}
-	}
+        }
+
+        private static bool bShaking = false;
+        public static void ShakeMe(float shakeTime, Vector3 shakeStength)
+        {
+            if (bShaking) return;
+            bShaking = true;
+
+            Transform trans = GlobalViewComponent.Instance.BattleCamera.transform;
+            Tweener tweener = trans.DOShakePosition(shakeTime, shakeStength);
+            tweener.OnComplete<Tweener>(() =>
+            {
+                trans.localPosition = Vector3.zero;
+                bShaking = false;
+            });
+        }
+    }
 }

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

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

+ 219 - 0
Unity/Assets/Scripts/Codes/HotfixView/Client/Effect/EffectMgr.cs

@@ -0,0 +1,219 @@
+using CommonAI.Zone;
+using System;
+using System.Collections.Generic;
+using CommonAI.ZoneClient;
+using UnityEngine;
+using System.Text.RegularExpressions;
+using CommonLang;
+using Sirenix.Utilities;
+using ET.EventType;
+
+namespace ET.Client
+{
+    
+    [Event(SceneType.None)]
+    public class PlayEffectEventHandler : BEvent<EventType.PlayEffectEvent>
+    {
+        private static Vector3 vecTemp = new();
+        public override void OnEvent(PlayEffectEvent args)
+        {
+            vecTemp.Set(args.Pos.X, args.Pos.Y, args.Pos.Z);
+            EffectMgr.Instance.PlayEffect(args.Effect, args.HostId, vecTemp, args.Time, args.Rotation).Coroutine();
+        }
+    }
+
+    public class EffectMgr : Singleton<EffectMgr>, ISingletonAwake, ISingletonUpdate
+    {
+        private HashMap<uint, EffectPlayInfo> playingList = new();
+        private HashMap<string, List<GameObject>> effectPool = new();
+        private static Vector3 vecTemp = new();
+
+        public void Awake()
+        {
+        }
+
+        public void Update()
+        {
+            var now = Time.realtimeSinceStartup;
+            foreach (var epi in playingList.Values)
+            {
+                if (epi.EndTime >= now)
+                {
+                    playingList.Remove(epi.Id);
+                }
+            }
+        }
+
+        public async ETTask<uint> PlayEffect(LaunchEffect effect, uint HostId, Vector3 pos, float time = 0f, float rotation = 0f)
+        {
+            var starttime = Time.realtimeSinceStartup;
+
+            GameObject go = null;
+            if (!effect.Name.IsNullOrWhitespace())
+            {
+                go = await loadEffect(effect.Name);
+                UnitRenderComponet render = null;
+                if (effect.BindBody)
+                {
+                    render = ModelViewComponent.Instance.GetChild<UnitRenderComponet>(HostId);
+                    if (render == null)
+                    {
+                        Log.Debug($"ignore unit effect: {effect.Name}@{HostId}, cause of No Render");
+                        recycleEffect(go);
+                        return 0;
+                    }
+                }
+
+                var timeComponent = go.GetComponent<EffectTime>();
+                if (time == 0f) time = timeComponent.duration;
+                if (time < 0f) time = EffectPlayInfo.TIME_FOREVER;
+                setupEffect(go, effect, render, pos, rotation);
+            }
+
+            if (effect.EarthQuakeMS > 0)
+            {
+                vecTemp.Set(effect.EarthQuakeXYZ, effect.EarthQuakeXYZ, effect.EarthQuakeXYZ);
+                CameraMgr.ShakeMe(effect.EarthQuakeMS, vecTemp);
+            }
+
+            if (!effect.SoundName.IsNullOrWhitespace())
+            {
+                //TODO: Sound
+            }
+
+            var epi = ObjectPool.Instance.Fetch<EffectPlayInfo>();
+            epi.Reset(go, starttime + time);
+            playingList.Add(epi.Id, epi);
+            return epi.Id;
+        }
+
+        private void setupEffect(GameObject go, LaunchEffect effectData, UnitRenderComponet render, Vector3 pos, float rotation)
+        {
+            var gt = go.transform;
+
+            if (effectData.BindBody)
+            {
+                if (!effectData.BindPartName.IsNullOrWhitespace())
+                {
+                    gt.parent = render.GetBindPart(effectData.BindPartName);
+                }
+                else
+                {
+                    gt.parent = render.GameObject.transform;
+                }
+                vecTemp.Set(effectData.EffectOffsetX, 0, effectData.EffectOffsetY);
+                gt.localPosition = vecTemp;
+                if (effectData.Tag == "FixStartRotaion")
+                {
+                    gt.rotation = Quaternion.Euler(0, 90, 0);
+                }
+                else
+                {
+                    gt.localRotation = Quaternion.identity;
+                }
+            }
+            else
+            {
+                gt.parent = GlobalViewComponent.Instance.Unit;
+            }
+
+            if (pos != Vector3.zero)
+            {
+                vecTemp.Set(effectData.EffectOffsetX, effectData.EffectHight, effectData.EffectOffsetY);
+                gt.position = pos + vecTemp;
+            }
+            if (rotation != 0)
+            {
+                gt.rotation = Quaternion.Euler(0, rotation * Mathf.Rad2Deg + 90, 0);
+            }
+            var scale = effectData.ScaleToBodySize != 0 ? effectData.ScaleToBodySize : 1f;
+            gt.localScale = new Vector3(scale, scale, scale);
+
+            if (!string.IsNullOrEmpty(effectData.Tag))
+            {
+                //Effect支持Tag设置Event,格式:Event:事件名(事件参数)
+                Match m = Regex.Match(effectData.Tag, @"^Event:(\w+)\((.*)\)");
+                if (m.Groups.Count >= 3)
+                {
+                    string eventName = m.Groups[1].Value;
+                    string eventParam = m.Groups[2].Value;
+                    if (!string.IsNullOrEmpty(eventName))
+                    {
+                        Log.Error("Not support: Effect({0}) Triggle event:{1}", effectData.Name, effectData.Tag);
+                        /*EventManager.Fire("Event." + eventName, new Dictionary<string, object>()
+                        {
+                            {"param", eventParam},
+                            {"position", gt.position}
+                        });*/
+                    }
+                }
+            }
+        }
+
+        public void Clear()
+        {
+            foreach (var epi in playingList.Values)
+            {
+                GameObject.Destroy(epi.GameObj);
+            }
+            playingList.Clear();
+
+            foreach (var list in effectPool.Values)
+            {
+                foreach (var go in list)
+                {
+                    GameObject.Destroy(go);
+                }
+            }
+            effectPool.Clear();
+        }
+
+        public void RemoveEffect(uint id)
+        {
+            if (playingList.ContainsKey(id))
+            {
+                var info = playingList[id];
+                playingList.Remove(id);
+                recycleEffect(info.GameObj);
+            }
+        }
+
+        private async ETTask<GameObject> loadEffect(string prefabName)
+        {
+            if (effectPool.TryGetValue(prefabName, out var golist))
+            {
+                if (golist.Count > 0)
+                {
+                    var gobj = golist[0];
+                    golist.RemoveRange(0, 1);
+                    return gobj;
+                }
+            }
+            else
+            {
+                effectPool.Add(prefabName, new List<GameObject>());
+            }
+
+            var handle = await YooAssetProxy.LoadAssetAsync<GameObject>($"Effect_{prefabName}");
+            var prefab = handle.GetAssetObject<GameObject>();
+            var gameobj = UnityEngine.Object.Instantiate(prefab, GlobalViewComponent.Instance.Unit, true);
+            gameobj.name = prefabName;
+            return gameobj;
+        }
+
+        private void recycleEffect(GameObject go)
+        {
+            go.SetActive(false);
+            go.transform.SetParent(GlobalViewComponent.Instance.RecycleNode, false);
+            var name = go.name;
+            if (effectPool.TryGetValue(name, out var golist))
+            {
+                golist.Add(go);
+            }
+            else
+            {
+                effectPool.Add(name, new List<GameObject>() { go });
+            }
+        }
+    }
+}

+ 11 - 0
Unity/Assets/Scripts/Codes/HotfixView/Client/Effect/EffectMgr.cs.meta

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

+ 27 - 0
Unity/Assets/Scripts/Codes/HotfixView/Client/Effect/EffectPlayInfo.cs

@@ -0,0 +1,27 @@
+using CommonAI.Zone;
+using CommonAI.ZoneClient;
+using Pathfinding.ClipperLib;
+using System;
+using UnityEngine;
+
+public class EffectPlayInfo
+{
+    public uint Id { get; private set; }
+    public float EndTime { get; private set; }
+    public GameObject GameObj { get; private set; }
+
+    public EffectPlayInfo() { }
+    public void Reset(GameObject go, float endtime)
+    {
+        Id = IdGen();
+        EndTime = endtime;
+        GameObj = go;
+    }
+
+    private static uint _id = 0;
+    private static uint IdGen()
+    {
+        return ++_id; ;
+    }
+    public readonly static float TIME_FOREVER = 86400f;
+}

+ 11 - 0
Unity/Assets/Scripts/Codes/HotfixView/Client/Effect/EffectPlayInfo.cs.meta

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

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

@@ -5,10 +5,11 @@
     {
         protected override async ETTask Run(Scene scene, ET.EventType.EntryEvent3 args)
         {
-            // 加载配置
-            //Root.Instance.Scene.AddComponent<ResourcesComponent>();
             Root.Instance.Scene.AddComponent<GlobalViewComponent>();
 
+            Game.AddSingleton<EffectMgr>();
+            //Game.AddSingleton<SoundManager>();
+
             Scene clientScene = await SceneFactory.CreateClientScene(1, "Game");
             await EventSystem.Instance.PublishAsync(clientScene, new EventType.AppStartInitFinish());
         }

+ 2 - 1
Unity/Assets/Scripts/Codes/HotfixView/Unity.HotfixView.Codes.asmdef

@@ -14,7 +14,8 @@
         "UniTask",
         "Unity.ModelView.Codes",
         "Unity.Mono",
-        "Animancer"
+        "Animancer",
+        "UniTask.DOTween"
     ],
     "includePlatforms": [],
     "excludePlatforms": [],

+ 23 - 1
Unity/Assets/Scripts/Codes/Model/Client/EventTypeClient.cs

@@ -1,4 +1,6 @@
-namespace ET
+using CommonAI.Zone;
+
+namespace ET
 {
     namespace EventType
     {
@@ -55,6 +57,26 @@
                 return this;
             }
         }
+        public class PlayEffectEvent
+        {
+            public LaunchEffect Effect;
+            public uint HostId;
+            public CommonLang.Geometry.Vector3 Pos;
+            public float Time;
+            public float Rotation;
+
+            public static PlayEffectEvent Static = new PlayEffectEvent();
+            public PlayEffectEvent Clone(LaunchEffect effect, uint hostId, CommonLang.Geometry.Vector3 pos, float time = 0f, float rotation = 0f)
+            {
+                Effect = effect;
+                HostId = hostId;
+                Pos = pos;
+                Time = time;
+                Rotation = rotation;
+
+                return this;
+            }
+        }
     }
 
     //状态指令

+ 4 - 2
Unity/Assets/Scripts/Codes/ModelView/Client/Global/GlobalViewComponent.cs

@@ -7,9 +7,11 @@ namespace ET.Client
     {
         [StaticField]
         public static GlobalViewComponent Instance;
-        
+
+        public Camera UICamera;
+        public Camera BattleCamera;
         public Transform Global;
         public Transform Unit { get; set; }
-        //public Transform UI;
+        public Transform RecycleNode { get; set; }
     }
 }

+ 6 - 0
Unity/Assets/Scripts/Codes/ModelView/Client/Unit/UnitRenderComponet.cs

@@ -17,6 +17,12 @@ namespace ET.Client
         public GameObject GameObject { get; set; }
         public AnimationData AniData;
         public AnimatorCommand DoingCmd;
+
+        //TODO: 获得模型绑定部件,如不存在返回Root
+        public Transform GetBindPart(string partName)
+        {
+            return GameObject.transform;
+        }
     }
 
     //TODO: 支持ObjectPool

+ 2 - 1
Unity/Assets/Scripts/Empty/HotfixView/Unity.HotfixView.asmdef

@@ -14,7 +14,8 @@
         "UniTask.YooAsset",
         "UniTask",
         "Unity.Mono",
-        "Animancer"
+        "Animancer",
+        "UniTask.DOTween"
     ],
     "includePlatforms": [],
     "excludePlatforms": [],