PGRData/Script/matrix/xui/xuispecialtrainbreakthrough/XSpecialTrainActionRandom.lua
2024-09-01 22:49:41 +02:00

176 lines
5.9 KiB
Lua
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---@class XSpecialTrainActionRandom
local XSpecialTrainActionRandom = XClass(nil, "XSpecialTrainActionRandom")
function XSpecialTrainActionRandom:Ctor()
self._Animator = false
self._ActionArray = false
self._RandomActionArray = false
self._PanelRoleModel = false
self._LastIndex = false
self._AnimatorTimer = false
self._IdleTime = 0
self._IdleActionName = false
-- 随机播放动作的间隔
self._TimeToPlayAction = 0
self._CrossFadeTime = 0.2
self._CrossFadeConflictProtectTime = 1
end
---@param animator UnityEngine.Animator
---@param actionArray string[]|nil 当状态机配置好Parameters时可不传, By zlb
function XSpecialTrainActionRandom:SetAnimator(animator, actionArray, panelRoleModel)
self._Animator = animator
local actionArrayFromParam = self:_GetActionArrayByParam(animator)
if #actionArrayFromParam > 0 then
self._ActionArray = actionArrayFromParam
else
self._ActionArray = actionArray
end
self._PanelRoleModel = panelRoleModel
end
function XSpecialTrainActionRandom:Play()
self:_RandomIdleDuration()
self:_PlayRandomAnimation()
self._IdleActionName = self:_GetRunningActionName(self._Animator)
-- 第一次播放间隔总是1秒
self._IdleTime = self._TimeToPlayAction - 1
end
function XSpecialTrainActionRandom:Stop()
if self._AnimatorTimer then
XScheduleManager.UnSchedule(self._AnimatorTimer)
end
self._Animator = false
self._ActionArray = false
self._RandomActionArray = false
self._PanelRoleModel = false
self._LastIndex = false
self._AnimatorTimer = false
self._IdleTime = 0
self._IdleActionName = false
self._TimeToPlayAction = 0
end
-- 策划做了状态机,里面放了要使用的多组动作
function XSpecialTrainActionRandom:_PlayRandomAnimation()
if self._AnimatorTimer then
return
end
local animator = self._Animator
self._AnimatorTimer = XScheduleManager.ScheduleForever(function()
if not animator or XTool.UObjIsNil(animator) then
self:Stop()
return
end
local currentName, animatorClipInfo = self:_GetRunningActionName(animator)
if currentName == self._IdleActionName then
self._IdleTime = self._IdleTime + CS.UnityEngine.Time.deltaTime
if self._IdleTime > self._TimeToPlayAction then
-- 融合时间内有事件冲突
if not self:_IsAnimatorEventConflict(animator, animatorClipInfo) or
-- 冲突时间过久,强制播放
(self._IdleTime > self._TimeToPlayAction + self._CrossFadeConflictProtectTime) then
self._IdleTime = 0
self:_PlayNextAction()
self:_RandomIdleDuration()
end
end
end
end, 0)
end
function XSpecialTrainActionRandom:_PlayNextAction()
local nextActionName = self:_GetNextAction()
if not nextActionName then
return false
end
if self._PanelRoleModel then
self._PanelRoleModel:CrossFadeAnim(nextActionName, self._CrossFadeTime)
end
return true
end
function XSpecialTrainActionRandom:_GetNextAction()
local length = #self._ActionArray
if length == 1 then
return self._ActionArray[1]
end
if length == 0 then
return false
end
self._LastIndex = self:_GetDifferentIndex()
return self._ActionArray[self._LastIndex]
end
function XSpecialTrainActionRandom:_GetDifferentIndex()
local index = math.random(1, #self._ActionArray)
if index == self._LastIndex then
return self:_GetDifferentIndex()
end
return index
end
function XSpecialTrainActionRandom:_GetRunningActionName(animator)
local animatorClipInfo, name = self:_GetRunningActionClipInfo(animator)
return name, animatorClipInfo
end
-- 由于使用了crossFade融合时会同时触发两个动作的事件导致之前动作的表情覆盖了之后动作的表情
-- 检查动画事件是否在两个动作融合时间内触发
function XSpecialTrainActionRandom:_IsAnimatorEventConflict(animator, animatorClipInfo)
if not animatorClipInfo then
return false
end
local passedActionTime = self:_GetPassedActionTime(animator)
for i = 0, animatorClipInfo.clip.events.Length - 1 do
local animationEvent = animatorClipInfo.clip.events[i]
local animationEventTime = animationEvent.time
if passedActionTime + self._CrossFadeTime > animationEventTime and passedActionTime < animationEventTime then
return true
end
end
return false
end
-- 当前动作已播放时间
function XSpecialTrainActionRandom:_GetPassedActionTime(animator)
local layer = 0
local stateInfo = animator:GetCurrentAnimatorStateInfo(layer)
return stateInfo.normalizedTime * stateInfo.length
end
function XSpecialTrainActionRandom:_RandomIdleDuration()
self._TimeToPlayAction = math.random(30, 50) / 10
end
function XSpecialTrainActionRandom:_GetRunningActionClipInfo(animator)
local layer = 0
local stateInfo = animator:GetCurrentAnimatorStateInfo(layer)
local animatorClipInfos = animator:GetCurrentAnimatorClipInfo(layer)
if animatorClipInfos.Length <= 0 then
return nil
end
for i = 0, animatorClipInfos.Length - 1 do
local animatorClipInfo = animatorClipInfos[i]
local name = animatorClipInfo.clip.name
if CS.UnityEngine.Animator.StringToHash(name) == stateInfo.shortNameHash then
return animatorClipInfo, name
end
end
return nil
end
function XSpecialTrainActionRandom:_GetActionArrayByParam(animator)
local actionArray = {}
local parameters = animator.parameters
for i = 0, parameters.Length - 1 do
local param = parameters[i]
local name = param.name
actionArray[#actionArray + 1] = name
end
return actionArray
end
return XSpecialTrainActionRandom