--需要处理例子特效的ui对象 需要继承该类 比如baseview baseitem UIPartical = UIPartical or BaseClass(UIZDepth) local UIPartical = UIPartical local UIDepth = UIDepth local rawget = rawget local IsNull = IsNull --每个layer的起始值 UIPartical.Start_SortingOrder_list = { ["Scene"] = 0, ["Main"] = 200, ["UI"] = 400, ["Activity"] = 600, ["Top"] = 800, ["UpTop"] = 1000, } --每个layer的当前层数 UIPartical.curr_SortingOrder_list = { ["Scene"] = UIPartical.Start_SortingOrder_list.Scene, ["Main"] = UIPartical.Start_SortingOrder_list.Main, ["UI"] = UIPartical.Start_SortingOrder_list.UI, ["Activity"] = UIPartical.Start_SortingOrder_list.Activity, ["Top"] = UIPartical.Start_SortingOrder_list.Top, ["UpTop"] = UIPartical.Start_SortingOrder_list.UpTop, } --设置渲染特效所在的layer层 UIPartical.RenderingOther_List = { DEFAULT = 0, UI = 5, UIForward = 8, Role = 9, Blackground = 10, UIBackward = 14, UIBackRole = 15, Reflection = 29, Ground = 30, UI3D = 16, } function UIPartical:__init() self.layer_name = "Main" self.depth_counter = 0 self.partical_list = {} self.callback_list = {} self.lastTime_list = {} self.cache_partical_map = {} self.show_partical_map = {} self.wait_load_effect_trans = {} self.speed = 1 self.effect_cd_list = {}--特效冷却时间列表 self.effect_timer_list = {}--特效时间定时器列表 end function UIPartical:__delete() self:ClearAllEffect() self:ClearCacheEffect() end function UIPartical:ClearCacheEffect() for abname,state in pairs(self.cache_partical_map) do lua_resM:ClearObjPool(abname) end self.cache_partical_map = {} self.wait_load_effect_trans = {} self.show_partical_map = {} end function UIPartical:DeleteCurrLayerDepth(layer_name,count) if UIPartical.curr_SortingOrder_list[layer_name] then UIPartical.curr_SortingOrder_list[layer_name] = UIPartical.curr_SortingOrder_list[layer_name] - count end if UIPartical.Start_SortingOrder_list[layer_name] then if self:GetCurrLayerDepth(layer_name) < UIPartical.Start_SortingOrder_list[layer_name] then UIPartical.curr_SortingOrder_list[layer_name] = UIPartical.Start_SortingOrder_list[layer_name] end end end function UIPartical:AddCurrLayerDepth(layer_name,count) if UIPartical.curr_SortingOrder_list[layer_name] then UIPartical.curr_SortingOrder_list[layer_name] = UIPartical.curr_SortingOrder_list[layer_name] + (count or 1) end end function UIPartical:GetCurrLayerDepth(layer_name) return UIPartical.curr_SortingOrder_list[layer_name] end --打开界面的时候 设置UI SortingOrder深度 function UIPartical:SetUIDepth(gameObject) if self.layer_name and self.layer_name ~= "Main" then if UIPartical.GetCurrLayerDepth(self, self.layer_name) < UIPartical.Start_SortingOrder_list[self.layer_name] then UIPartical.curr_SortingOrder_list[self.layer_name] = UIPartical.Start_SortingOrder_list[self.layer_name] end self.depth_counter = self.depth_counter + 1 UIPartical.AddCurrLayerDepth(self, self.layer_name) gameObject.layer = LayerMask.NameToLayer("UI") UIDepth.SetUIDepth(gameObject,true,self:GetCurrLayerDepth(self.layer_name)) end end function UIPartical:SetGameObjectDepth(gameObject) if gameObject == nil then return end if self.layer_name and self.layer_name ~= "Main" then self.depth_counter = self.depth_counter + 1 UIPartical.AddCurrLayerDepth(self, self.layer_name) UIDepth.SetUIDepth(gameObject,true,self:GetCurrLayerDepth(self.layer_name)) gameObject.layer = LayerMask.NameToLayer("UI") end end function UIPartical:SetGameObjectDepthByLayerName(gameObject, layer_name) if gameObject == nil then return end layer_name = layer_name or "UI" self.depth_counter = self.depth_counter + 1 UIPartical.AddCurrLayerDepth(self, layer_name) UIDepth.SetUIDepth(gameObject,true,self:GetCurrLayerDepth(layer_name)) gameObject.layer = LayerMask.NameToLayer("UI") end --关闭界面的时候重置UI深度 function UIPartical:ResetUIDepth(count) if rawget(self, "layer_name") and (self.layer_name ~= "Main" or self.need_to_reset_layer) then if count then if count > 0 then UIPartical.DeleteCurrLayerDepth(self, self.layer_name,count ) self.depth_counter = self.depth_counter - count end else if self.depth_counter > 0 then UIPartical.DeleteCurrLayerDepth(self, self.layer_name,self.depth_counter ) self.depth_counter = 0 end end end end --这里分为UI层跟其它层,UI层的粒子层级加1,而其他层级,例如主界面,则固定为1 function UIPartical:SetParticleDepth(gameObject, forceAdd) if self.layer_name then if self.layer_name == "Main" and not forceAdd then local depth = UIPartical.Start_SortingOrder_list[self.layer_name] + 1 if depth ~= nil then UIDepth.SetUIDepth(gameObject,false,depth) end else self.depth_counter = self.depth_counter + 1 UIPartical.AddCurrLayerDepth(self, self.layer_name) UIDepth.SetUIDepth(gameObject,false,self:GetCurrLayerDepth(self.layer_name)) end end end --添加屏幕特效 function UIPartical:AddScreenEffect(resname, pos, scale, is_loop ,last_time) local parent_go = UiFactory.createChild(panelMgr:GetParent(self.layer_name), UIType.EmptyObject, resname) local function call_back_func() destroy(parent_go) end self:AddUIEffect(resname, parent_go.transform, self.layer_name, pos, scale, is_loop ,last_time, nil, call_back_func) end --[[ 功能:添加到UI上的特效 如果是baseview里面设置特效 需要在opencallback方法里设置才行 baseitem需要再baseview调用opencallback的时候重新设置 uiTranform 只能挂接一个特效 其他. lastTime为-1时播放结束不主动销毁 save_by_batch: 合并批处理,这个和useMask是互斥关系,如两个特效的resname相同时,不能一个用useMask另一个用save_by_batch。因为共享材质只有一个。 ]] function UIPartical:AddUIEffectConfig(config) config = config or {} local resname = config.resname local pos = config.pos local scale = config.scale or 1 local is_loop = config.is_loop local last_time = config.last_time local useMask = config.useMask local call_back_func = config.call_back_func local load_finish_func = config.load_finish_func local speed = config.speed local layer = config.layer local not_delete_old_ps = config.not_delete_old_ps local save_by_batch = config.save_by_batch local need_cache = config.need_cache local uiTranform = config.uiTranform local layer_name = config.layer_name local use_ex_depth = config.use_ex_depth --修改深度时候处理隐藏节点,根据特效决定是否使用 self:AddUIEffect(resname, uiTranform, layer_name, pos, scale, is_loop ,last_time, useMask, call_back_func,load_finish_func, speed, layer, not_delete_old_ps, save_by_batch, need_cache, use_ex_depth) end function UIPartical:AddUIEffect(resname, uiTranform, layer_name, pos, scale, is_loop ,last_time, useMask, call_back_func,load_finish_func, speed, layer, not_delete_old_ps, save_by_batch, need_cache, use_ex_depth) if uiTranform then local instance_id = uiTranform:GetInstanceID() if self.wait_load_effect_trans[instance_id] then return end self.layer_name = layer_name or self.layer_name pos = pos or Vector3.zero scale = scale if is_loop == nil then is_loop = true end if need_cache == nil then need_cache = true end local function load_call_back(objs, is_gameObject) self.wait_load_effect_trans[instance_id] = false if self.transform then --没有删除根变换 if self._use_delete_method then return end if IsNull(uiTranform) then return end --如果没特效,则返回 if not objs or not objs[0] then return end local curr_effect_sortingOrder = nil if self.layer_name and self.layer_name ~= "Main" then self.depth_counter = self.depth_counter + 1 self:AddCurrLayerDepth(self.layer_name) curr_effect_sortingOrder = self:GetCurrLayerDepth(self.layer_name) end local go = is_gameObject and objs[0] or newObject(objs[0]) local shader_mask = UIParticleMaskShader.Res[resname] if shader_mask then local objs = go:GetComponentsInChildren(typeof(UnityEngine.Renderer)) for i=1,objs.Length do local mats = objs[i-1].sharedMaterials for i=0, mats.Length - 1 do if mats[i] then local shader_config = UIParticleMaskShader.Shader[mats[i].shader.name] if shader_config then mats[i].shader = ShaderTools.GetShader(shader_config) end end end end end self.partical_list[go] = true local gameobject_id = go:GetInstanceID() self.show_partical_map[gameobject_id] = resname local transform = go.transform transform:SetParent(uiTranform) transform.localPosition = pos SetLocalRotation(transform) if type(scale) == "number" then if scale ~= -1 then -- if not is_gameObject or (Scene and Scene.Instance:IsPreLoadPoolEffect(resname)) then -- 备注Hierarchy = 0,Local = 1,Shape = 2 -- local particleSystems = go:GetComponentsInChildren(typeof(UnityEngine.ParticleSystem)) -- if particleSystems and scale ~= 1 then -- for i = 0, particleSystems.Length - 1 do -- particleSystems[i].main.scalingMode = UnityEngine.ParticleSystemScalingMode.IntToEnum(1) -- end -- end -- cs_particleM:SetScale(go,scale) -- end transform.localScale = Vector3.one * scale * 100 end elseif type(scale) == "table" then local particleSystems = go:GetComponentsInChildren(typeof(UnityEngine.ParticleSystem)) if scale.z == nil then scale.z = 1 end for i = 0, particleSystems.Length - 1 do local ps = particleSystems[i] ps.main.scalingMode = UnityEngine.ParticleSystemScalingMode.IntToEnum(1) ps.transform.localScale = Vector3(scale.x, scale.y, scale.z) end transform.localScale = Vector3(scale.x, scale.y, scale.z) * 100 else transform.localScale = Vector3(72,72,72) end PrintParticleInfo(go) self:SetSpeed(go, speed) go:SetActive(false) go:SetActive(true) self:SetUILayer(uiTranform, layer) if useMask then self:SetEffectMask(go) else if curr_effect_sortingOrder then if use_ex_depth then self:SetUIDepthEx(go, false, curr_effect_sortingOrder) else UIDepth.SetUIDepth(go, false, curr_effect_sortingOrder) end else self:SetParticleDepth(go, maskID) end if save_by_batch then --需要动态批处理,设置共享材质 local renders = go:GetComponentsInChildren(typeof(UnityEngine.Renderer)) for i = 0, renders.Length - 1 do local mats = renders[i].sharedMaterials for j = 0, mats.Length - 1 do mats[j]:SetFloat("_Stencil", 0) end end local curTrans = go.transform.parent local maskImage while(curTrans and curTrans.name ~= "Canvas") do maskImage = curTrans:GetComponent("Mask") if maskImage then break else curTrans = curTrans.parent end end if maskImage then local canvas = curTrans:GetComponent("Canvas") if canvas then UIDepth.SetUIDepth(go,false,canvas.sortingOrder + 1) end end else --由于使用遮罩的材质调用了共享材质,这里对不使用遮罩的特效使用实例化材质 local renders = go:GetComponentsInChildren(typeof(UnityEngine.Renderer)) for i = 0, renders.Length - 1 do local mats = renders[i].materials for j = 0, mats.Length - 1 do mats[j]:SetFloat("_Stencil", 0) end end end end self.callback_list[go] = call_back_func if last_time and last_time > 0 and not self.lastTime_list[go] then local function onDelayFunc() self.show_partical_map[gameobject_id] = nil self:PlayEnd(go,need_cache,resname) if not need_cache and not self._use_delete_method then lua_resM:reduceRefCount(self, resname) end end self.lastTime_list[go] = GlobalTimerQuest:AddDelayQuest(onDelayFunc,last_time) end if is_loop then cs_particleM:SetLoop(go,is_loop) elseif last_time ~= -1 and not self.lastTime_list[go] then local function playEndCallback(go) self.show_partical_map[gameobject_id] = nil self:PlayEnd(go,need_cache,resname) if not need_cache and not self._use_delete_method then lua_resM:reduceRefCount(self, resname) end end ParticleManager:getInstance():AddUIPartical(go,playEndCallback) end if load_finish_func then load_finish_func(go) end ClearTrailRenderer(go) end end if not not_delete_old_ps then self:ClearUIEffect(uiTranform) end self.wait_load_effect_trans[instance_id] = true lua_resM:loadPrefab(self,resname,resname, load_call_back,false,ASSETS_LEVEL.HIGHT) end end function UIPartical:SetUIDepthEx( go, isUI, order ) if isUI then local canvas = go:GetComponent(typeof(UnityEngine.Canvas)) if (canvas == nil) then canvas = go:AddComponent(typeof(UnityEngine.Canvas)) end canvas.overrideSorting = true canvas.sortingOrder = order else local renders = go:GetComponentsInChildren(typeof(UnityEngine.Renderer), true) if renders then for i=0,renders.Length-1 do renders[i].sortingOrder = order end end end end -- {resname,--资源名 -- uiTranform, -- -- layer_name, -- pos, scale, -- is_loop -- ,last_time, --持续时间 -- useMask, --遮罩 -- call_back_func, -- load_finish_func, -- speed, --速度 -- layer, -- -- not_delete_old_ps--不删除旧特效 --} --id唯一 判断是否是同一个类型(类型不一定是特效不相等)比如"SceneSpecialTipView_ui_effcet_rolelvup" function UIPartical:AddUIEffectByTime(data, time_cd, id) if not data or not data.resname then print("huangcong:UIPartical [269]特效资源名为空: ") return end time_cd = time_cd or 1 id = id or data.resname if not self.effect_cd_list[id] then self.effect_cd_list[id] = {id = id, can_effect = false} elseif self.effect_cd_list[id] and self.effect_cd_list[id].can_effect then self.effect_cd_list[id].can_effect = false else print("huangcong:UIPartical [289]特效还在冷却!: ",data.id) return end self.effect_timer_list[id] = GlobalTimerQuest:AddDelayQuest(function() self.effect_cd_list[id].can_effect = true self.effect_timer_list[id] = nil end, time_cd) self:AddUIEffect( data.resname, data.uiTranform, data.layer_name, data.pos, data.scale, data.is_loop, data.last_time, data.useMask, data.call_back_func, data.load_finish_func, data.speed, data.layer, data.not_delete_old_ps) end function UIPartical:SetSpeed(go, speed) self.speed = speed or self.speed if self.partical_list[go] and self.speed then cs_particleM:SetSpeed(go,self.speed) end end --清除挂接在父容器的所有对象, 判断进入对象缓存池 function UIPartical:ClearUIEffect(uiTranform) if not IsNull(uiTranform) then for i = 0,uiTranform.childCount - 1 do local go = uiTranform:GetChild(0).gameObject local cache_res = self.show_partical_map[go:GetInstanceID()] if cache_res then self:PlayEnd(go,cache_res,cache_res) end end else PrintCallStack() end end --删除所有特效 function UIPartical:ClearAllEffect() UIPartical.ResetUIDepth(self) for go,callback in pairs(self.callback_list) do callback() self.partical_list[go] = nil end for go,last_time_id in pairs(self.lastTime_list) do TimerQuest.CancelQuest(GlobalTimerQuest, last_time_id) self.lastTime_list[go] = nil end for go,_ in pairs(self.partical_list) do ParticleManager.RemoveUIPartical(ParticleManager:getInstance(), go) local gomeobject_id = go:GetInstanceID() local cache_res = self.show_partical_map[gomeobject_id] if cache_res then self.show_partical_map[gomeobject_id] = nil if not IsNull(go) then go:SetActive(false) lua_resM:AddObjToPool(self, cache_res, cache_res, go) self.cache_partical_map[cache_res] = true end else destroy(go,true) end self.partical_list[go] = nil end end --单个特效播放结束 function UIPartical:PlayEnd(go,need_cache,resname) if go and not IsNull(go) then local callback = self.callback_list[go] if callback and not self._use_delete_method then callback() end self.callback_list[go] = nil local last_time_id = self.lastTime_list[go] if last_time_id then TimerQuest.CancelQuest(GlobalTimerQuest, last_time_id) end self.lastTime_list[go] = nil ParticleManager.RemoveUIPartical(ParticleManager:getInstance(), go) self.partical_list[go] = nil if need_cache and resname then self.cache_partical_map[resname] = true go:SetActive(false) lua_resM:AddObjToPool(self, resname, resname, go) else destroy(go,true) end if self.layer_name ~= "Main" and self.depth_counter > 0 then self.depth_counter = self.depth_counter - 1 UIPartical.DeleteCurrLayerDepth(self, self.layer_name, 1) end end end function UIPartical:SetUILayer(obj, layer) layer = layer or UIPartical.RenderingOther_List.UIForward if IsNull(obj) then return end for i = 0,obj.childCount - 1 do obj:GetChild(i).gameObject.layer = layer self:SetUILayer(obj:GetChild(i), layer) end end function UIPartical:SetForwardUILayer(obj, layer) layer = layer or UIPartical.RenderingOther_List.UIForward if IsNull(obj) then return end for i = 0,obj.childCount - 1 do obj:GetChild(i).gameObject.layer = layer self:SetUILayer(obj:GetChild(i), layer) end end function UIPartical:SetRTUILayer(obj, layer) layer = layer or UIPartical.RenderingOther_List.UI3D if IsNull(obj) then return end for i = 0,obj.childCount - 1 do obj:GetChild(i).gameObject.layer = layer self:SetUILayer(obj:GetChild(i), layer) end end function UIPartical:SetUIBackwardLayer(obj, layer) layer = layer or UIPartical.RenderingOther_List.UIBackward if IsNull(obj) then return end for i = 0,obj.childCount - 1 do obj:GetChild(i).gameObject.layer = layer self:SetUILayer(obj:GetChild(i), layer) end end function UIPartical:SetUIbackRoleLayer(obj, layer) layer = layer or UIPartical.RenderingOther_List.UIBackRole if IsNull(obj) then return end for i = 0,obj.childCount - 1 do obj:GetChild(i).gameObject.layer = layer self:SetUILayer(obj:GetChild(i), layer) end end function UIPartical:SetEffectMask(obj) local renders = obj:GetComponentsInChildren(typeof(UnityEngine.Renderer)) for i = 0, renders.Length - 1 do --使用Renderer.material获取Material引用时,会把Render里Materials列表第一个预设的Material进行实例,这样每个object都有各自的材质对象,无法实现批处理draw call local mats = renders[i].sharedMaterials for j = 0, mats.Length - 1 do if mats[j] then mats[j]:SetFloat("_Stencil", 1) end end end local curTrans = obj.transform.parent local maskImage while(curTrans and curTrans.name ~= "Canvas") do maskImage = curTrans:GetComponent("Mask") if maskImage then break else curTrans = curTrans.parent end end if maskImage then local canvas = curTrans:GetComponent("Canvas") if canvas then UIDepth.SetUIDepth(obj,false,canvas.sortingOrder + 1) end end end function UIPartical:RegisterMask(maskImage) self:ApplyMaskID(maskImage, 1) self.need_to_reset_layer = true return 1 end function UIPartical:ApplyMaskID(maskImage, maskID) local function callback(objs) if objs and objs[0] and not IsNull(maskImage) then maskImage.material = Material.New(objs[0]) maskImage.material:SetFloat("_StencilID", maskID) end end resMgr:LoadMaterial("scene_material", "mat_mask_image" , callback, ASSETS_LEVEL.HIGHT) maskImage.gameObject.layer = UIPartical.RenderingOther_List.UI self:SetUILayer(maskImage.transform) self.depth_counter = self.depth_counter + 1 self:AddCurrLayerDepth(self.layer_name) local oldMask = maskImage:GetComponent("Mask") local showMaskGraphic = oldMask.showMaskGraphic UnityEngine.Object.DestroyImmediate(oldMask) local newMask = maskImage.gameObject:AddComponent(typeof(EffectMask)) newMask.showMaskGraphic = showMaskGraphic UIDepth.SetUIDepth(maskImage.gameObject,true,self:GetCurrLayerDepth(self.layer_name)) if self.stencilGo then return end self.stencilGo = UiFactory.createChild(maskImage.transform.parent,UIType.ImageExtend,"StencilImage") self.stencilGo:SetActive(true) local stencilTrans,img,rect = self.stencilGo.transform, self.stencilGo:GetComponent("Image"),maskImage.transform.rect stencilTrans.localPosition = Vector2(rect.center.x, rect.center.y, 0) stencilTrans:SetSiblingIndex(maskImage.transform:GetSiblingIndex() + 1) local sizeDelta = maskImage.transform.sizeDelta stencilTrans.sizeDelta = Vector2(rect.width, rect.height) img.alpha = 0 img.raycastTarget = false img.material:SetFloat("_Stencil", 1) img.material:SetFloat("_StencilOp", 1) img.material:SetFloat("_StencilComp",8) local canvas = self.stencilGo:AddComponent(typeof(UnityEngine.Canvas)) canvas.overrideSorting = true self:AddCurrLayerDepth(self.layer_name) self:AddCurrLayerDepth(self.layer_name) self.depth_counter = self.depth_counter + 2 canvas.sortingOrder = self:GetCurrLayerDepth(self.layer_name) end function UIPartical:UnRegisterMask(maskID) end function UIPartical:AddUIComponent( ui_component ) if not ui_component then return end ui_component = ui_component.New()--不想在外部.New,因为ui_component不需要在外部DeleteMe的,这样就破坏了New和DeleteMe成对出现的规范了 ui_component:Init(self) if self.is_loaded then ui_component:OnLoad() end self.ui_components = self.ui_components or {} table.insert(self.ui_components, ui_component) return ui_component end function UIPartical:RemoveUIComponent( ui_component ) if not ui_component then return end for k,v in pairs(self.ui_components or {}) do if v == ui_component then ui_component:OnDestroy() table.remove(self.ui_components, k) break end end end function UIPartical:BeforeLoad( ) if self.ui_components then for i,v in ipairs(self.ui_components) do if v.OnLoad then v:OnLoad() end end end end function UIPartical:AfterDestroy( ) if self.ui_components then for i,v in ipairs(self.ui_components) do if v.OnDestroy then v:OnDestroy() v:DeleteMe() end end self.ui_components = nil end end