miduo_client/Assets/ManagedResources/~Lua/Modules/Battle/View/Unit/SkillCaster.lua

607 lines
23 KiB
Lua

local Bezier = require("Base.Bezier")
local SkillLogicConfig = ConfigManager.GetConfig(ConfigName.SkillLogicConfig)
local BuffEffectConfig = ConfigManager.GetConfig(ConfigName.BuffEffectConfig)
SkillCaster = {}
function SkillCaster.New(unit, actionTime, soundTime, soundName, castingEfectNode, castingNameNode)
local o = {}
setmetatable(o, {__index = SkillCaster})
o:ctor(unit, actionTime, soundTime, soundName, castingEfectNode, castingNameNode)
return o
end
function SkillCaster:ctor(unit, actionTime, soundTime, soundName, castingEfectNode, castingNameNode)
self.spLoader = unit.spLoader
self.owner = unit
self.actionTime = actionTime -- 立绘攻击动作时间
self.soundTime = soundTime -- 声音播放时机
self.soundName = soundName -- 声音资源名称
self.castingEfectNode = castingEfectNode -- cast特效资源
self.castingNameNode = castingNameNode -- cast名称资源
self.effectRoot = self.owner.RootPanel.skillEffectRoot
--
self.owner.role.Event:AddEvent(BattleEventName.SkillCast, self.OnSkillCast, self)
end
function SkillCaster:OnSkillCast(skill)
if not skill then return end
local eid = BattleManager.GetCombatIdBySkin(skill.id, self.owner.skinId)
local combat = BattleManager.GetSkillCombat(eid)
if not combat then return end
-- 追击显示追击文字
if skill.isAdd then
self.owner.Floater:ImageBuffFloating("z_zhandou_zhuiji_zh")
end
-- 高亮
BattleManager.PauseBattle()
-- 调用上层接口
if self.owner.OnSkillCastStart then
self.owner:OnSkillCastStart()
end
self.owner.RootPanel.SetRoleHighLight(self.owner, skill:GetDirectTargets(), function()
local duration = combat.KeyFrame/1000
local function _PlaySkill()
if IsNull(self.owner.GameObject) then
return
end
-- 调用上层接口
if self.owner.OnSkillPlay then
self.owner:OnSkillPlay()
end
-- 播放
-- 这里相当于技能前摇,等待立绘播放到需要释放关键帧的时间时继续释放技能(人物前摇特效)
if self.owner.role.type == BattleUnitType.Role then
self:CheckSkillForoleEffect(combat, skill)
end
self.owner:DelayFunc(self.actionTime, function()
self:CheckFullSceenSkill(combat, skill)
-- 继续战斗放在特效加载之后,避免特效加载时间对战斗时间得影响
BattleManager.ResumeBattle()
-- 取消高亮
self.owner:DelayFunc((combat.KeyFrame + combat.SkillDuration)/1000, function()
-- 恢复高亮
self.owner.RootPanel.SetRoleHighLight()
-- 调用上层接口
if self.owner.OnSkillEnd then
self.owner:OnSkillEnd()
end
end)
end)
-- 攻击音效
if self.soundName then
self.owner:DelayFunc(self.soundTime - 0.3, function()
SoundManager.PlaySound(self.soundName)
end)
end
end
--
if combat.VerticalDrawing == 1 then
_PlaySkill()
elseif combat.VerticalDrawing == 2 then
self:PlaySkillCastingEffect(combat, skill, function()
_PlaySkill()
end)
end
end)
end
function SkillCaster:PlaySkillCastingEffect(combat, skill, func)
-- 播放casting
self.castingEfectNode:SetActive(false)
self.castingEfectNode:SetActive(true)
-- 播放casting声音
SoundManager.PlaySound(SoundConfig.Sound_RoleCasting)
if combat.skillname and combat.skillname ~= "" then
self.castingNameNode:SetActive(true)
self.castingNameNode:GetComponent("Image").sprite = self.spLoader:LoadSprite(combat.skillname)
self.castingNameNode:GetComponent("Image"):SetNativeSize()
else
self.castingNameNode:SetActive(false)
end
-- 技能名音效
if IS_PLAY_VOICE and combat.SkillNameVoice and GetCurLanguage() == 0 then
SoundManager.PlaySound(combat.SkillNameVoice)
end
-- 这里相当于技能前摇,等待立绘播放到需要释放关键帧的时间时继续释放技能(灵兽前摇特效)
if self.owner.role.type == BattleUnitType.Monster then
self:CheckSkillForoleEffect(combat, skill)
end
-- 调用上层接口
if self.owner.OnSkillCastingStart then
self.owner:OnSkillCastingStart()
end
self.owner:DelayFunc(2, function()
self.castingEfectNode:SetActive(false)
-- 调用上层接口
if self.owner.OnSkillCastingEnd then
self.owner:OnSkillCastingEnd()
end
if func then func() func = nil end
end)
end
local FullEffectPosition = {
My_All = Vector3.New(0, -566, 0),
My_Front = Vector3.New(-120, -410, 0),
My_Behind = Vector3.New(20, -760, 0),
My_COL_1 = Vector3.New(-300, -566, 0),
My_COL_2 = Vector3.New(0, -566, 0),
My_COL_3 = Vector3.New(300, -566, 0),
Enemy_All = Vector3.New(0, 430, 0),
Enemy_Front = Vector3.New(-100, 340, 0),
Enemy_Behind = Vector3.New(50, 540, 0),
Enemy_COL_1 = Vector3.New(-300, 430, 0),
Enemy_COL_2 = Vector3.New(0, 430, 0),
Enemy_COL_3 = Vector3.New(300, 430, 0),
}
function SkillCaster:GetEffectSPostion(skill)
local chooseId = skill:GetDirectChooseId()
local chooseLimit = math.floor(chooseId / 10000) % 10
local targets = skill:GetDirectTargets()
local targetPos = targets[1].position
if chooseLimit == 3 then
local col = (targetPos-1) % 3 + 1
return self.owner.camp == 0 and FullEffectPosition["My_COL_"..col] or FullEffectPosition["Enemy_COL_"..col]
else
return self.owner.camp == 0 and FullEffectPosition.My_All or FullEffectPosition.Enemy_All
end
end
function SkillCaster:GetEffectPosition(skill)
local chooseId = skill:GetDirectChooseId()
local chooseLimit = math.floor(chooseId / 10000) % 10
local targets = skill:GetDirectTargets()
local targetCamp = targets[1].camp
local targetPos = targets[1].position
if chooseLimit == 0 or chooseLimit == 4 or chooseLimit == 5 then
return targetCamp == 0 and FullEffectPosition.My_All or FullEffectPosition.Enemy_All
elseif chooseLimit == 1 or chooseLimit == 2 then
if targetCamp == 0 then
return targetPos <= 3 and FullEffectPosition.My_Front or FullEffectPosition.My_Behind
else
return targetPos <= 3 and FullEffectPosition.Enemy_Front or FullEffectPosition.Enemy_Behind
end
elseif chooseLimit == 3 then
local col = (targetPos-1) % 3 + 1
return targetCamp == 0 and FullEffectPosition["My_COL_"..col] or FullEffectPosition["Enemy_COL_"..col]
end
end
-- 检测特效旋转
function SkillCaster:CheckRotate(go, orientation)
-- 判断是否旋转
if orientation==nil then
-- body
return false
end
local isR = orientation[1] and orientation[1][1] or 0
local rt = orientation[2]
rt = rt and Vector3.New(rt[1], rt[2], rt[3]) or Vector3.zero
if (self.owner.camp == 0 and isR == 1)
or (self.owner.camp == 1 and isR == 2) then
go.transform.localRotation = rt
return true
end
go.transform.localRotation = Vector3.zero
end
-- 检测是否需要释放全屏技能
function SkillCaster:CheckFullSceenSkill(combat, skill)
if not skill then
return
end
-- 指定目标弹道特效
if combat.EffectType == 1 then
local targets = skill:GetDirectTargets()
for _, target in ipairs(targets) do
self:RoleViewBullet(combat, target)
end
-- 全屏特效
elseif combat.EffectType == 2 then
local path = combat.Bullet
if path then
local pos = self:GetEffectPosition(skill)
if not pos then
return
end
-- 特效的偏移量
local offset = combat.Offset and Vector3.New(combat.Offset[1], combat.Offset[2], 0) or Vector3.zero
--
local go = BattleManager.LoadAsset(path, self.effectRoot:GetComponent("Canvas").sortingOrder)
-- 检测特效旋转
if self:CheckRotate(go, combat.Orientation) then
offset = -offset
end
go.transform:SetParent(self.effectRoot.transform)
go.transform.localScale = Vector3.one
go.transform.localPosition = pos + offset
go:SetActive(true)
BattleManager.AddDelayRecycleRes(path, go, 4)
end
-- 全屏弹道特效
elseif combat.EffectType == 3 then
local path = combat.Bullet
if path then
local spos = self:GetEffectSPostion(skill)
local tpos = self:GetEffectPosition(skill)
if not spos or not tpos then
return
end
-- 时间
local duration = combat.BulletTime/1000
-- 特效的偏移量
local offset = combat.Offset and Vector3.New(combat.Offset[1], combat.Offset[2], 0) or Vector3.zero
local go = BattleManager.LoadAsset(path, self.effectRoot:GetComponent("Canvas").sortingOrder)
go.transform:SetParent(self.effectRoot.transform)
-- 检测特效旋转
if self:CheckRotate(go, combat.Orientation) then
offset = -offset
end
go.transform.localPosition = spos + offset
go.transform.localScale = Vector3.one
go:SetActive(true)
BattleManager.AddDelayRecycleRes(path, go, duration)
if self.fullBulletTween then self.fullBulletTween:Kill() end
self.fullBulletTween = go.transform:DOLocalMove(tpos + offset, duration):SetEase(Ease.OutSine)
-- :OnComplete(function()
-- go:SetActive(false)
-- end)
end
-- 指定目标特效
elseif combat.EffectType == 4 then
local targets = skill:GetDirectTargets()
for _, target in ipairs(targets) do
local tv = self.owner.RootPanel.GetRoleView(target)
if tv then
local offset = combat.Offset and Vector3.New(combat.Offset[1], combat.Offset[2], 0) or Vector3.zero
local sortingOrder = self.effectRoot:GetComponent("Canvas").sortingOrder
local go2 = BattleManager.LoadAsset(combat.Bullet, sortingOrder)
go2.transform:SetParent(tv.GameObject.transform.parent)
-- 检测特效旋转
if self:CheckRotate(go2, combat.Orientation) then
offset = -offset
end
go2.transform.localPosition = Vector3.zero
go2.transform.anchoredPosition = offset
go2.transform:SetParent(self.effectRoot.transform)
go2.transform.localScale = Vector3.one
go2:SetActive(true)
BattleManager.AddDelayRecycleRes(combat.Bullet, go2, 4)
end
end
-- 全屏特效屏幕中心
elseif combat.EffectType == 5 then
local offset = combat.Offset and Vector3.New(combat.Offset[1], combat.Offset[2], 0) or Vector3.zero
local sortingOrder = self.effectRoot:GetComponent("Canvas").sortingOrder
local go2 = BattleManager.LoadAsset(combat.Bullet, sortingOrder)
go2.transform:SetParent(self.effectRoot.transform)
-- 检测特效旋转
if self:CheckRotate(go2, combat.Orientation) then
offset = -offset
end
go2.transform.localScale = Vector3.one
go2.transform.localPosition = Vector3.zero
go2.transform.anchoredPosition = offset
go2:SetActive(true)
BattleManager.AddDelayRecycleRes(combat.Bullet, go2, 4)
-- 会自己动的指定目标特效
elseif combat.EffectType == 6 then
local targets = skill:GetDirectTargets()
for _, target in ipairs(targets) do
local tv = self.owner.RootPanel.GetRoleView(target)
if tv then
local offset = combat.Offset and Vector3.New(combat.Offset[1], combat.Offset[2], 0) or Vector3.zero
local sortingOrder = self.effectRoot:GetComponent("Canvas").sortingOrder
local go2 = BattleManager.LoadAsset(combat.Bullet, sortingOrder)
go2.transform:SetParent(tv.GameObject.transform.parent)
-- 检测特效旋转
if self:CheckRotate(go2, combat.Orientation) then
offset = -offset
end
go2.transform.localPosition = Vector3.zero
go2.transform.anchoredPosition = offset
go2.transform:SetParent(self.effectRoot.transform)
go2.transform.localScale = Vector3.one
go2:SetActive(true)
--
local targetPos = go2.transform.localPosition
local startPos = targetPos + Vector3.New(0, 800, 0)
go2.transform.localPosition = startPos
go2.transform:DOLocalMove(targetPos, combat.KeyFrame/1000, false)
BattleManager.AddDelayRecycleRes(combat.Bullet, go2, combat.KeyFrame/1000)
end
end
-- 射线特效
elseif combat.EffectType == 7 then
local targets = skill:GetDirectTargets()
for _, target in ipairs(targets) do
local tv = self.owner.RootPanel.GetRoleView(target)
if tv then
local offset = combat.Offset and Vector3.New(combat.Offset[1], combat.Offset[2], 0) or Vector3.zero
local sortingOrder = self.effectRoot:GetComponent("Canvas").sortingOrder
local go2 = BattleManager.LoadAsset(combat.Bullet, sortingOrder)
go2.transform:SetParent(self.owner.GameObject.transform.parent)
-- 检测特效旋转
if self:CheckRotate(go2, combat.Orientation) then
offset = -offset
end
go2.transform.localPosition = Vector3.zero
go2.transform.anchoredPosition = offset
-- 特效旋转补正
local fixRotate = self:CalRoleRotate(self.owner, tv)
go2.transform.localEulerAngles = go2.transform.localEulerAngles + fixRotate
-- 缩放
go2.transform:SetParent(self.effectRoot.transform)
go2:SetActive(true)
local dis = self:CheckRoleDistance(self.effectRoot, self.owner, tv)
local sl = dis/1000
go2.transform.localScale = Vector3.New(1, sl, 1)
--
BattleManager.AddDelayRecycleRes(combat.Bullet, go2, combat.KeyFrame/1000)
end
end
end
-- 取消高亮
self.owner:DelayFunc(combat.KeyFrame/1000, function()
self:CheckSkillHitEffect("skill", combat, skill)
self:checkShake(combat)
end)
end
function SkillCaster:CalRoleRotate(baseRole, targetRole)
local basePos = baseRole.GameObject.transform.position
local targetPos = targetRole.GameObject.transform.position
local deltaX = targetPos.x - basePos.x
local deltaY = targetPos.y - basePos.y
local deltaR = math.atan(math.abs(deltaX/deltaY))/math.pi*180
if baseRole.camp == 0 and deltaX > 0 then
return Vector3.New(0, 0, -deltaR)
elseif baseRole.camp == 0 and deltaX < 0 then
return Vector3.New(0, 0, deltaR)
elseif baseRole.camp == 1 and deltaX < 0 then
return Vector3.New(0, 0, -deltaR)
elseif baseRole.camp == 1 and deltaX > 0 then
return Vector3.New(0, 0, deltaR)
end
return Vector3.zero
end
function SkillCaster:CheckRoleDistance(baseRoot, role1, role2)
local pos1 = baseRoot.transform:InverseTransformPoint(role1.GameObject.transform.position)
local pos2 = baseRoot.transform:InverseTransformPoint(role2.GameObject.transform.position)
local dis = math.distanceXY(pos1, pos2)
return dis
end
-- 检测前摇技能释放
function SkillCaster:CheckSkillForoleEffect(combat, skill)
if not skill then
return
end
if not combat.BeforeBullet or combat.BeforeBullet == "" then
return
end
local go
local path = combat.BeforeBullet
local offset = combat.BeforeOffset and Vector3.New(combat.BeforeOffset[1], combat.BeforeOffset[2], 0) or Vector3.zero
local pos = Vector3.zero
-- 挂在人身上,以人物中心为原点
if combat.BeforeEffectType == 1 then
if self.owner.role.type == BattleUnitType.Role then
local sortingOrder
if self.owner.cam == 0 then
sortingOrder = self.owner.GameObject:GetComponent("Canvas").sortingOrder
else
sortingOrder = BattleManager.GetBattleSorting() + 20
end
go = BattleManager.LoadAsset(path, sortingOrder)
go.transform:SetParent(self.owner.GameObject.transform)
elseif self.owner.role.type == BattleUnitType.Monster then
go = BattleManager.LoadAsset(path)
go.transform:SetParent(self.owner.RoleLiveGO2.gameObject.transform)
end
-- 屏幕中心
elseif combat.BeforeEffectType == 2 then
local sortingOrder = self.effectRoot:GetComponent("Canvas").sortingOrder
go = BattleManager.LoadAsset(path, sortingOrder)
go.transform:SetParent(self.effectRoot.transform)
-- 根据目标位置
elseif combat.BeforeEffectType == 3 then
pos = self:GetEffectPosition(skill)
go = BattleManager.LoadAsset(path, self.effectRoot:GetComponent("Canvas").sortingOrder)
go.transform:SetParent(self.effectRoot.transform)
end
-- 检测特效旋转
if self:CheckRotate(go, combat.BeforeOrientation) then
offset = -offset
end
go.transform.localScale = Vector3.one
go.transform.localPosition = Vector3.zero
go.transform.anchoredPosition = offset + pos
go:SetActive(true)
BattleManager.AddDelayRecycleRes(path, go, 4)
end
-- 检测技能命中特效显示
function SkillCaster:CheckSkillHitEffect(checkType, combat, skill)
if not combat then return end
if checkType == "skill" then
-- 释放技能时检测,如果是范围命中效果
if combat.HitEffectType == 2 and combat.Hit then
local targets = skill:GetDirectTargets()
if not targets or not targets[1] then return end -- or targets[1]:IsDead() 删除了死亡的判断,会偶现被击特效不显示的问题
local tv = self.owner.RootPanel.GetRoleView(targets[1])
if not tv then return end
local tpos = self:GetEffectPosition(skill)
if not tpos then
return
end
-- 特效的偏移量
local offset = combat.HitOffset and Vector3.New(combat.HitOffset[1], combat.HitOffset[2], 0) or Vector3.zero
local sortingOrder = tv.role.camp == 0 and tv.GameObject:GetComponent("Canvas").sortingOrder + 21 or BattleManager.GetBattleSorting() + 20
local go = BattleManager.LoadAsset(combat.Hit, sortingOrder)
go.transform:SetParent(self.effectRoot.transform)
-- 检测特效旋转
if self:CheckRotate(go, combat.HitOrientation) then
offset = -offset
end
go.transform.localScale = Vector3.one
go.transform.localPosition = tpos + offset
go:SetActive(true)
BattleManager.AddDelayRecycleRes(combat.Hit, go, 5)
end
elseif checkType == "hit" then
-- 被击中时检测,如果是目标命中
if combat.HitEffectType == 1 and combat.Hit then
local offset = combat.HitOffset and Vector3.New(combat.HitOffset[1], combat.HitOffset[2], 0) or Vector3.zero
local sortingOrder = self.owner.role.camp == 0 and self.owner.GameObject:GetComponent("Canvas").sortingOrder + 21 or BattleManager.GetBattleSorting() + 20
local go2 = BattleManager.LoadAsset(combat.Hit, sortingOrder)
go2.transform:SetParent(self.owner.GameObject.transform.parent)
-- 检测特效旋转
if self:CheckRotate(go2, combat.HitOrientation) then
offset = -offset
end
go2.transform.localPosition = Vector3.zero--self.GameObject.transform.localPosition + Vector3.New(0, self.BuffFloatingCount * 180, 0)
go2.transform.anchoredPosition = offset--Vector2.zero
go2.transform:SetParent(self.effectRoot.transform)
go2.transform.localScale = Vector3.one
go2:SetActive(true)
BattleManager.AddDelayRecycleRes(combat.Hit, go2, 5)
end
end
end
-- 检测是否需要震动屏幕
function SkillCaster:checkShake(combat)
if combat.ShockScreen == 1 then
self.owner.RootPanel:SetShake()
end
end
--弹道轨迹
local plist = {
[1] = {
Vector2.New(0.2, 0.9),
},
[2] = {
Vector2.New(1.12, 0.33),
Vector2.New(-0.15, 0.67),
},
[3] = {
Vector2.New(0.9, 0.2),
},
}
-- 播放弹道特效
function SkillCaster:RoleViewBullet(combat, target)
if not self.owner.RootPanel.GetRoleView(target) then return end
if not combat then return end
local duration = combat.BulletTime/1000
local bulletEffect = combat.Bullet
if not bulletEffect or bulletEffect == "" or duration == 0 then return end
local go = BattleManager.LoadAsset(bulletEffect, self.effectRoot:GetComponent("Canvas").sortingOrder)
go.transform:SetParent(self.effectRoot.transform)
go.transform.localScale = Vector3.one
go.transform.position = self.owner.GameObject.transform.position
Util.ClearTrailRender(go)
go:SetActive(true)
local startV3 = go.transform.position
local endV3 = self.owner.RootPanel.GetRoleView(target).GameObject.transform.position
local startV2 = Vector2.New(0, 0)
local endV2 = Vector2.New(1, 1)
local pL = plist[math.random(1, #plist)]
--飞行子弹轨迹
DoTween.To(
DG.Tweening.Core.DOGetter_float( function () return 0 end),
DG.Tweening.Core.DOSetter_float(function (progress)
local v2 = Bezier.CalPos(progress, startV2, endV2, pL)
go.transform.position = Vector3.New(startV3.x * (1-v2.x) + endV3.x * v2.x,
startV3.y * (1-v2.y) + endV3.y * v2.y, startV3.z)
end), 1, duration)
:SetEase(Ease.InQuad)
:OnComplete(function ()
poolManager:UnLoadAsset(bulletEffect, go, PoolManager.AssetType.GameObject)
end)
end
return SkillCaster