UGCProjects/GZJ/Script/Manager/EffectSystemManager.lua

359 lines
16 KiB
Lua
Raw Permalink Normal View History

2025-01-08 22:46:12 +08:00
---技能特效系统,仅存在于客户端
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