359 lines
16 KiB
Lua
359 lines
16 KiB
Lua
|
---技能特效系统,仅存在于客户端
|
||
|
EffectSystemManager = LuaClass("EffectSystemManager")
|
||
|
|
||
|
--存储所有特效实例
|
||
|
EffectSystemManager.ExistedEffectList = {}
|
||
|
|
||
|
EffectSystemManager.EffectTable = require('Script.Global.EffectTables')
|
||
|
|
||
|
--调试信息开关
|
||
|
EffectSystemManager.OpenDebug = GlobalConfigs.OpenDebug
|
||
|
|
||
|
function EffectSystemManager.ctor()
|
||
|
end
|
||
|
|
||
|
------------------------------------------------------ [[外部接口]] ---------------------------------------------------------------
|
||
|
|
||
|
---播放粒子特效: 默认生成在CasterActor上,若ActorList不为nil则生成在ActorList中Actor的位置
|
||
|
---@param InstanceId number 特效实例ID
|
||
|
---@param EffectId number 特效ID(保存在EffectTables.lua文件中)
|
||
|
---@param CasterActor AActor 特效发起Actor
|
||
|
---@param ActorList AActor[] 特效目标Actor列表(可为空)
|
||
|
---@param Duration number 特效持续时间(0则表示AutoDestroy)
|
||
|
---@param SpawnLocationType EEffectSpawnLocationType 特效生成位置(Bottom 脚下, Middle 中间, Top 头顶, Attach 吸附骨骼,)
|
||
|
---@param BoneName string 特效吸附骨骼(仅当SpawnLocationType为Attach时才生效)
|
||
|
function EffectSystemManager.PlayEffect(InstanceId, EffectId, CasterActor, ActorList, Duration, SpawnLocationType, BoneName)
|
||
|
EffectSystemManager.ApplyEffect(InstanceId, EffectId, CasterActor, ActorList, Duration, SpawnLocationType, BoneName)
|
||
|
end
|
||
|
|
||
|
---播放指向型粒子特效: 默认CasterActor为起点, DestActor为终点; 若DestActor为nil, 则Rotation为指定角度
|
||
|
---@param InstanceId number 特效实例ID
|
||
|
---@param EffectId number 特效ID(保存在EffectTables.lua文件中)
|
||
|
---@param CasterActor AActor 特效起始Actor
|
||
|
---@param DestActor AActor 特效终点Actor
|
||
|
---@param Duration number 特效持续时间(0则表示AutoDestroy)
|
||
|
---@param Rotation FRotator 指定角度(DestActor为空时才生效)
|
||
|
function EffectSystemManager.PlayDirectionalEffect(InstanceId, EffectId, CasterActor, DestActor, Duration, Rotation)
|
||
|
EffectSystemManager.ApplyDirectionalEffect(InstanceId, EffectId, CasterActor, DestActor, Duration, Rotation)
|
||
|
end
|
||
|
|
||
|
---播放粒子特效在世界坐标
|
||
|
---@param InstanceId number 特效实例ID
|
||
|
---@param EffectId number 特效ID(保存在EffectTables.lua文件中)
|
||
|
---@param CasterActor AActor 特效发起Actor(可为空)
|
||
|
---@param Location FVector 指定位置
|
||
|
---@param Rotation FRotator 指定旋转
|
||
|
---@param Duration number 特效持续时间(0则表示AutoDestroy)
|
||
|
---@return UParticleSystemComponent
|
||
|
function EffectSystemManager.PlayEffectAtLocation(InstanceId, EffectId, CasterActor, Location, Rotation, Duration)
|
||
|
return EffectSystemManager.ApplyEffectAtLocation(InstanceId, EffectId, CasterActor, Location, Rotation, Duration)
|
||
|
end
|
||
|
|
||
|
---获取特效实例
|
||
|
---可在获取后做进一步处理,如调整特效位置
|
||
|
|
||
|
---根据InstanceId获取EffectInstance
|
||
|
---@param InstanceId number 特效实例ID
|
||
|
---@return EffectInstance
|
||
|
function EffectSystemManager.GetEffectInstanceWithId(InstanceId)
|
||
|
for _, v in pairs(EffectSystemManager.ExistedEffectList) do
|
||
|
if v.InstanceId == InstanceId then
|
||
|
return v
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
---根据CasterActor获取所有关联EffectInstance
|
||
|
---@param CasterActor AActor 特效发起Actor
|
||
|
------@return EffectInstance[]
|
||
|
function EffectSystemManager.GetEffectInstanceListOfActor(CasterActor)
|
||
|
local EffectInstanceList = {}
|
||
|
for _, v in pairs(EffectSystemManager.ExistedEffectList) do
|
||
|
if v.CasterActor == CasterActor then
|
||
|
table.insert(EffectInstanceList, v)
|
||
|
end
|
||
|
end
|
||
|
return EffectInstanceList
|
||
|
end
|
||
|
|
||
|
--------------------------------------------------------- [[内部调用]] ---------------------------------------------------------
|
||
|
|
||
|
function EffectSystemManager.ApplyEffect(InstanceId, EffectId, CasterActor, ActorList, Duration, SpawnLocationType, BoneName)
|
||
|
if InstanceId == nil or EffectId == nil or CasterActor == nil then
|
||
|
return
|
||
|
end
|
||
|
if Duration == nil or type(Duration) ~= "number" then
|
||
|
Duration = 0
|
||
|
end
|
||
|
if SpawnLocationType == nil then
|
||
|
SpawnLocationType = EEffectSpawnLocationType.Bottom
|
||
|
end
|
||
|
local bAutoDestroy = Duration < 0.01
|
||
|
|
||
|
local bSpawnEmitterSuccess = EffectSystemManager.PlayParticleSystem(InstanceId, EffectId, CasterActor, ActorList, SpawnLocationType, BoneName, bAutoDestroy)
|
||
|
if not bSpawnEmitterSuccess then
|
||
|
UE.LogError("[EffectSystemManager.ApplyEffect] Failed. EffectId: %d", EffectId)
|
||
|
return
|
||
|
end
|
||
|
|
||
|
if bAutoDestroy == false then
|
||
|
CasterActor.EffectDurationTimer = EventSystem.SetTimer(CasterActor, function()
|
||
|
EffectSystemManager.RemoveEffectByInstanceId(InstanceId)
|
||
|
CasterActor.EffectDurationTimer = nil
|
||
|
end, Duration)
|
||
|
end
|
||
|
|
||
|
UE.Log("[EffectSystemManager.ApplyEffect] Success. InstanceId: %d, EffectId: %d", InstanceId, EffectId)
|
||
|
end
|
||
|
|
||
|
function EffectSystemManager.ApplyDirectionalEffect(InstanceId, EffectId, CasterActor, DestActor, Duration, Rotation)
|
||
|
if InstanceId == nil or EffectId == nil or CasterActor == nil then
|
||
|
return
|
||
|
end
|
||
|
if Duration == nil or type(Duration) ~= "number" then
|
||
|
Duration = 0
|
||
|
end
|
||
|
|
||
|
local bAutoDestroy = Duration < 0.01
|
||
|
|
||
|
local bSpawnEmitterSuccess = EffectSystemManager.PlayDirectionalParticleSystem(InstanceId, EffectId, CasterActor, DestActor, Rotation, bAutoDestroy)
|
||
|
if not bSpawnEmitterSuccess then
|
||
|
UE.LogError("[EffectSystemManager.ApplyDirectionalEffect] Failed. EffectId: %d", EffectId)
|
||
|
return
|
||
|
end
|
||
|
|
||
|
if bAutoDestroy == false then
|
||
|
CasterActor.EffectDurationTimer = EventSystem.SetTimer(CasterActor, function()
|
||
|
EffectSystemManager.RemoveEffectByInstanceId(InstanceId)
|
||
|
CasterActor.EffectDurationTimer = nil
|
||
|
end, Duration)
|
||
|
end
|
||
|
|
||
|
UE.Log("[EffectSystemManager.ApplyDirectionalEffect] Success. InstanceId: %d, EffectId: %d", InstanceId, EffectId)
|
||
|
end
|
||
|
|
||
|
function EffectSystemManager.ApplyEffectAtLocation(InstanceId, EffectId, CasterActor, Location, Rotation, Duration)
|
||
|
local ParticleTemplate = EffectSystemManager.GetEffectTemplateById(EffectId)
|
||
|
if ParticleTemplate == nil then
|
||
|
UE.LogError("[EffectSystemManager.ApplyEffectAtLocation] invalid EffectId: %d", EffectId)
|
||
|
return nil
|
||
|
end
|
||
|
if Duration == nil or type(Duration) ~= "number" then
|
||
|
Duration = 0
|
||
|
end
|
||
|
|
||
|
local bAutoDestroy = Duration < 0.01
|
||
|
local CurEmitter = GameplayStatics.SpawnEmitterAtLocation(CasterActor, ParticleTemplate, Location, Rotation, VectorHelper.ScaleOne(), bAutoDestroy)
|
||
|
|
||
|
if CurEmitter ~= nil and bAutoDestroy == false then
|
||
|
CasterActor.EffectDurationTimer = EventSystem.SetTimer(CasterActor, function()
|
||
|
EffectSystemManager.RemoveEffectByInstanceId(InstanceId)
|
||
|
CasterActor.EffectDurationTimer = nil
|
||
|
end, Duration)
|
||
|
end
|
||
|
|
||
|
UE.Log("[EffectSystemManager.ApplyEffectAtLocation] %s. InstanceId: %d, EffectId: %d", CurEmitter ~= nil and "Success" or "Failed", InstanceId, EffectId)
|
||
|
|
||
|
return CurEmitter
|
||
|
end
|
||
|
|
||
|
function EffectSystemManager.GetEffectTemplateById(EffectId)
|
||
|
local EffectTemplate = AsyncLoadTools.GetEffectByIndex(EffectId)
|
||
|
if EffectTemplate == nil then
|
||
|
local Path = EffectSystemManager.EffectTable.Paths[EffectId]
|
||
|
if Path ~= nil then
|
||
|
EffectTemplate = UE.LoadObject(Path)
|
||
|
end
|
||
|
end
|
||
|
return EffectTemplate
|
||
|
end
|
||
|
|
||
|
function EffectSystemManager.UpdateEffectInstanceList(InstanceId, EffectId, EmitterList, CasterActor)
|
||
|
local EffectInstance = {}
|
||
|
EffectInstance.InstanceId = InstanceId
|
||
|
EffectInstance.EffectName = EffectId
|
||
|
EffectInstance.EmitterList = EmitterList
|
||
|
EffectInstance.CasterActor = CasterActor
|
||
|
table.insert(EffectSystemManager.ExistedEffectList, EffectInstance)
|
||
|
end
|
||
|
|
||
|
function EffectSystemManager.PlayParticleSystem(InstanceId, EffectId, CasterActor, ActorList, SpawnLocationType, BoneName, bAutoDestroy)
|
||
|
local ParticleTemplate = EffectSystemManager.GetEffectTemplateById(EffectId)
|
||
|
if ParticleTemplate == nil then
|
||
|
UE.LogError("[EffectSystemManager.PlayParticleSystem] invalid EffectId: "..tostring(EffectId))
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
local EmitterList = {}
|
||
|
|
||
|
if ActorList == nil then
|
||
|
local CurEmitter = nil
|
||
|
if SpawnLocationType == EEffectSpawnLocationType.Attach then
|
||
|
if BoneName == nil then
|
||
|
BoneName = ""
|
||
|
end
|
||
|
CurEmitter = GameplayStatics.SpawnEmitterAttached(ParticleTemplate, CasterActor.Mesh, BoneName, VectorHelper.VectorZero(), VectorHelper.RotZero(), VectorHelper.ScaleOne(), EAttachLocation.SnapToTarget, bAutoDestroy)
|
||
|
else
|
||
|
local SpawnRot = CasterActor:K2_GetActorRotation()
|
||
|
local SpawnLoc = CasterActor:K2_GetActorLocation()
|
||
|
local SpawnLocZ = SpawnLoc.Z
|
||
|
|
||
|
if SpawnLocationType == EEffectSpawnLocationType.Bottom then
|
||
|
SpawnLocZ = SpawnLocZ - CasterActor.CapsuleComponent.CapsuleHalfHeight
|
||
|
elseif SpawnLocationType == EEffectSpawnLocationType.Top then
|
||
|
SpawnLocZ = SpawnLocZ + CasterActor.CapsuleComponent.CapsuleHalfHeight
|
||
|
end
|
||
|
SpawnLoc = {X = SpawnLoc.X, Y = SpawnLoc.Y, Z = SpawnLocZ}
|
||
|
|
||
|
CurEmitter = GameplayStatics.SpawnEmitterAtLocation(CasterActor, ParticleTemplate, SpawnLoc, SpawnRot, VectorHelper.ScaleOne(), bAutoDestroy)
|
||
|
end
|
||
|
|
||
|
if CurEmitter ~= nil then
|
||
|
table.insert(EmitterList, CurEmitter)
|
||
|
end
|
||
|
else
|
||
|
for _, Actor in pairs(ActorList) do
|
||
|
local CurEmitter = nil
|
||
|
if SpawnLocationType == EEffectSpawnLocationType.Attach then
|
||
|
if BoneName == nil then
|
||
|
BoneName = ""
|
||
|
end
|
||
|
CurEmitter = GameplayStatics.SpawnEmitterAttached(ParticleTemplate, Actor.Mesh, BoneName, VectorHelper.VectorZero(), VectorHelper.RotZero(), VectorHelper.ScaleOne(), EAttachLocation.SnapToTarget, bAutoDestroy)
|
||
|
else
|
||
|
local SpawnRot = Actor:K2_GetActorRotation()
|
||
|
local SpawnLoc = Actor:K2_GetActorLocation()
|
||
|
local SpawnLocZ = SpawnLocationType == EEffectSpawnLocationType.Bottom and SpawnLoc.Z - CasterActor.CapsuleComponent.CapsuleHalfHeight or SpawnLoc.Z + CasterActor.CapsuleComponent.CapsuleHalfHeight
|
||
|
SpawnLoc = {X = SpawnLoc.X, Y = SpawnLoc.Y, Z = SpawnLocZ}
|
||
|
|
||
|
CurEmitter = GameplayStatics.SpawnEmitterAtLocation(Actor, ParticleTemplate, SpawnLoc, SpawnRot, VectorHelper.ScaleOne(), bAutoDestroy)
|
||
|
end
|
||
|
|
||
|
if CurEmitter ~= nil then
|
||
|
table.insert(EmitterList, CurEmitter)
|
||
|
--EffectSystemManager.UpdateEffectInstanceList(InstanceId, EffectId, {CurEmitter}, Actor)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
EffectSystemManager.UpdateEffectInstanceList(InstanceId, EffectId, EmitterList, CasterActor)
|
||
|
return not table.isEmpty(EmitterList)
|
||
|
end
|
||
|
|
||
|
function EffectSystemManager.PlayDirectionalParticleSystem(InstanceId, EffectId, CasterActor, DestActor, Rotation, bAutoDestroy)
|
||
|
local ParticleTemplate = EffectSystemManager.GetEffectTemplateById(EffectId)
|
||
|
if ParticleTemplate == nil then
|
||
|
UE.LogError("[EffectSystemManager.PlayDirectionalParticleSystem] invalid EffectId: "..tostring(EffectId))
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
local EmitterList = {}
|
||
|
|
||
|
local SpawnLoc = CasterActor:K2_GetActorLocation()
|
||
|
local SpawnRot = VectorHelper.RotZero()
|
||
|
|
||
|
if DestActor ~= nil then
|
||
|
local DestLoc = DestActor:K2_GetActorLocation()
|
||
|
SpawnRot = KismetMathLibrary.FindLookAtRotation(SpawnLoc, DestLoc)
|
||
|
|
||
|
if GlobalConfigs.OpenDebug then
|
||
|
STExtraGameplayStatics.ClientDrawDebugLine(SpawnLoc, DestLoc, {R=1,G=0,B=0,A=1}, 5, 1)
|
||
|
end
|
||
|
else
|
||
|
SpawnRot = Rotation
|
||
|
end
|
||
|
|
||
|
local CurEmitter = GameplayStatics.SpawnEmitterAtLocation(CasterActor, ParticleTemplate, SpawnLoc, Rotation, VectorHelper.ScaleOne(), bAutoDestroy)
|
||
|
if CurEmitter ~= nil then
|
||
|
table.insert(EmitterList, CurEmitter)
|
||
|
end
|
||
|
|
||
|
EffectSystemManager.UpdateEffectInstanceList(InstanceId, EffectId, EmitterList, CasterActor)
|
||
|
return not table.isEmpty(EmitterList)
|
||
|
end
|
||
|
|
||
|
--------------------------------------------------------- 移除技能效果[外部接口] ---------------------------------------------------------
|
||
|
|
||
|
---移除指定Id对应的效果
|
||
|
function EffectSystemManager.RemoveEffectByInstanceId(InstanceId)
|
||
|
if InstanceId == nil then
|
||
|
UE.Log("[EffectSystemManager.RemoveEffectByInstanceId] InstanceId is nil")
|
||
|
return
|
||
|
end
|
||
|
|
||
|
local PendingEffectInstances = {}
|
||
|
for i, v in pairs(EffectSystemManager.ExistedEffectList) do
|
||
|
if v.InstanceId == InstanceId then
|
||
|
PendingEffectInstances[i] = v
|
||
|
end
|
||
|
|
||
|
-- 顺便把一些可能没正确去除的去掉
|
||
|
if v.CasterActor == nil or UE.IsValid(v.CasterActor) == false then
|
||
|
EffectSystemManager.RemoveEffectInstance(v)
|
||
|
EffectSystemManager.ExistedEffectList[i] = nil
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if not table.isEmpty(PendingEffectInstances) then
|
||
|
for i, EffectInstance in pairs(PendingEffectInstances) do
|
||
|
EffectSystemManager.RemoveEffectInstance(EffectInstance)
|
||
|
EffectSystemManager.ExistedEffectList[i] = nil
|
||
|
end
|
||
|
else
|
||
|
UE.LogError("[EffectSystemManager.RemoveEffectByInstanceId] Can't find EffectInstance with InstanceId: %d", InstanceId)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
---移除指定Name的效果
|
||
|
function EffectSystemManager.RemoveEffectByEffectName(CasterActor, EffectName)
|
||
|
if EffectName == nil then
|
||
|
UE.Log("[EffectSystemManager.RemoveEffectByEffectName] EffectName is nil")
|
||
|
return
|
||
|
end
|
||
|
|
||
|
local PendingEffectInstances = {}
|
||
|
for i, v in pairs(EffectSystemManager.ExistedEffectList) do
|
||
|
if v.EffectName == EffectName and v.CasterActor == CasterActor then
|
||
|
PendingEffectInstances[i] = v
|
||
|
end
|
||
|
|
||
|
-- 顺便把一些可能没正确去除的去掉
|
||
|
if v.CasterActor == nil or UE.IsValid(v.CasterActor) == false then
|
||
|
EffectSystemManager.ExistedEffectList[i] = nil
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if not table.isEmpty(PendingEffectInstances) then
|
||
|
for i, EffectInstance in pairs(PendingEffectInstances) do
|
||
|
EffectSystemManager.RemoveEffectInstance(EffectInstance)
|
||
|
EffectSystemManager.ExistedEffectList[i] = nil
|
||
|
end
|
||
|
else
|
||
|
UE.LogError("[EffectSystemManager.RemoveEffectByEffectName] Can't find EffectInstance with EffectName: "..tostring(EffectName))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
---移除指定Actor的所有效果
|
||
|
function EffectSystemManager.RemoveAllEffectOfActor(CasterActor)
|
||
|
for i, v in pairs(EffectSystemManager.ExistedEffectList) do
|
||
|
if v.CasterActor == CasterActor then
|
||
|
EffectSystemManager.RemoveEffectInstance(v)
|
||
|
EffectSystemManager.ExistedEffectList[i] = nil
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
------------------------------------------- 移除效果实例[内部接口] -------------------------------------------
|
||
|
|
||
|
---@param CasterActor AActor
|
||
|
---@param EffectInstance int
|
||
|
function EffectSystemManager.RemoveEffectInstance(EffectInstance)
|
||
|
if EffectInstance.EmitterList ~= nil and table.getCount(EffectInstance.EmitterList) > 0 then
|
||
|
for _, Emitter in pairs(EffectInstance.EmitterList) do
|
||
|
if Emitter ~= nil and UE.IsValid(Emitter) then
|
||
|
Emitter:K2_DestroyComponent()
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
return EffectSystemManager
|