---@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 function XSpecialTrainActionRandom:SetAnimator(animator, actionArray, panelRoleModel) self._Animator = animator self._ActionArray = actionArray 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() 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 return XSpecialTrainActionRandom