PGRData/Script/matrix/xcommon/XSignBoardPlayer.lua
2024-09-01 22:49:41 +02:00

485 lines
No EOL
14 KiB
Lua
Raw 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 XSignBoardPlayer
local XSignBoardPlayer = {}
local PlayerState = {
IDLE = 0,
PLAYING = 1,
CHANGING = 2,
PAUSE = 3,
STOP = 4
}
--创建一个播放器
function XSignBoardPlayer.New(playUi, coolTime, delay)
if playUi == nil then
return nil
end
local player = {}
setmetatable(player, { __index = XSignBoardPlayer })
player:Init(playUi, coolTime, delay)
return player
end
--初始化
function XSignBoardPlayer:Init(playUi, coolTime, delay)
self.CoolTime = coolTime --冷却时间
self.PlayUi = playUi --执行Ui
self:SetStatus(PlayerState.IDLE)
self.DelayStart = XTime.GetServerNowTimestamp() + delay
self.LastPlayTime = -1
self.Delay = delay
self.Time = XTime.GetServerNowTimestamp()
self.AutoPlay = true
self.PlayOne = false
end
-- self.PlayerData.PlayerList = {} --播放列表
-- self.PlayerData..PlayingElement = nil --播放对象
-- self.PlayerData.PlayedList = {} --播放过的列表
-- self.LastPlayTime = -1 --上次播放时间
function XSignBoardPlayer:SetPlayerData(data)
self.PlayerData = data
end
--设置播放队列
function XSignBoardPlayer:SetPlayList(playList)
if not playList or #playList <= 0 then
return
end
self.PlayerData.PlayerList = {}
self.PlayerData.LastPlayTime = -1
self.DelayStart = self.Time + self.Delay
for _, element in ipairs(playList) do
table.insert(self.PlayerData.PlayerList, element)
end
end
--清空播放队列
function XSignBoardPlayer:ClearPlayList()
if not self.PlayerData then
return
end
self.PlayerData.PlayerList = {}
end
--播放
function XSignBoardPlayer:Play(tab, cvType)
if not tab then
return false
end
if not self:IsActive() then
return false
end
if self.PlayerData.PlayingElement and self.PlayerData.PlayingElement.Id == tab.Id then
return false
end
local element = {}
element.Id = tab.Id --Id
element.AddTime = self.Time -- 添加事件
element.StartTime = -1 --开始播放的时间
element.EndTime = -1 --结束时间
-- 获取相应语言的动作持续时间
local duration
local defaultCvType = 1
local curElementCvType = cvType or CS.UnityEngine.PlayerPrefs.GetInt("CV_TYPE", defaultCvType)
if tab.Duration[curElementCvType] == nil then
if tab.Duration[defaultCvType] == nil then
XLog.Error(string.format("XSignBoardPlayer:Play函数错误配置表SignboardFeedback.tab没有配置Id:%s的Duration数据", tostring(element.Id)))
return false
end
duration = tab.Duration[defaultCvType]
else
duration = tab.Duration[curElementCvType]
end
element.Duration = duration
element.Validity = tab.Validity --有效期
element.CoolTime = 0--tab.CoolTime --冷却时间
element.Weight = tab.Weight --权重
element.SignBoardConfig = tab
element.CvType = cvType
table.insert(self.PlayerData.PlayerList, 1, element)
return true
end
--播放下一个
--isRecord决定是否要保存当前动作播放记录
function XSignBoardPlayer:PlayNext(isRecord)
if not self:IsActive() then
return
end
if not self.PlayerData.PlayerList or #self.PlayerData.PlayerList == 0 then
return
end
--获取第一个在有限期之类的动画
local head = nil
--只播放权重最高的动画模式,同权限动画,只随机播放其中一个
if self.PlayOne then
local highestWeight = 0
local randomList = {}
for index, element in ipairs(self.PlayerData.PlayerList) do
if element.Weight > highestWeight and self:CheckAnimValidity(element) then
highestWeight = element.Weight --记录最高权重
end
end
for index, element in ipairs(self.PlayerData.PlayerList) do
if element.Weight == highestWeight and self:CheckAnimValidity(element) then
table.insert(randomList,element)
end
end
if #randomList > 0 then
local index = math.random(1, #randomList)
head = randomList[index]
end
else --顺序播放动画
while #self.PlayerData.PlayerList > 0 and not head do
local element = table.remove(self.PlayerData.PlayerList, 1)
-- local lastPlayTime = self.PlayerData.PlayedList[temp.Id]
-- --如果还在冷却中
-- if lastPlayTime and self.Time < lastPlayTime then
-- if #self.PlayerData.PlayerList <= 0 then
-- break
-- end
-- temp = table.remove(self.PlayerData.PlayerList, 1)
-- end
--检测是否过期
if self:CheckAnimValidity(element) then
head = element
end
end
end
--如果找不到合适的动画
if not head then
return
end
head.StartTime = self.Time
self.PlayerData.PlayingElement = head
self:SetStatus(PlayerState.PLAYING)
self.PlayerData.LastPlayTime = head.StartTime + head.Duration
if isRecord then
-- 记录播放过的动作
XDataCenter.SignBoardManager.RecordSignBoard(head.SignBoardConfig)
end
self.PlayUi:Play(head)
self:PlayActionAnim(head)
if self.PlayOne then
-- 清空播放列表,只播放当前权重最高的动画(head)
self.PlayerData.PlayerList = {}
end
end
function XSignBoardPlayer:PlayNextCross(isRecord)
if not self:IsActive() then
return
end
if not self.PlayerData.PlayerList or #self.PlayerData.PlayerList == 0 then
return
end
--获取第一个在有限期之类的动画
local head = nil
--只播放权重最高的动画模式,同权限动画,只随机播放其中一个
if self.PlayOne then
local highestWeight = 0
local randomList = {}
for index, element in ipairs(self.PlayerData.PlayerList) do
if element.Weight > highestWeight and self:CheckAnimValidity(element) then
highestWeight = element.Weight --记录最高权重
end
end
for index, element in ipairs(self.PlayerData.PlayerList) do
if element.Weight == highestWeight and self:CheckAnimValidity(element) then
table.insert(randomList,element)
end
end
if #randomList > 0 then
local index = math.random(1, #randomList)
head = randomList[index]
end
else --顺序播放动画
while #self.PlayerData.PlayerList > 0 and not head do
local element = table.remove(self.PlayerData.PlayerList, 1)
-- local lastPlayTime = self.PlayerData.PlayedList[temp.Id]
-- --如果还在冷却中
-- if lastPlayTime and self.Time < lastPlayTime then
-- if #self.PlayerData.PlayerList <= 0 then
-- break
-- end
-- temp = table.remove(self.PlayerData.PlayerList, 1)
-- end
--检测是否过期
if self:CheckAnimValidity(element) then
head = element
end
end
end
--如果找不到合适的动画
if not head then
return
end
head.StartTime = self.Time
self.PlayerData.PlayingElement = head
self:SetStatus(PlayerState.PLAYING)
self.PlayerData.LastPlayTime = head.StartTime + head.Duration
if isRecord then
-- 记录播放过的动作
XDataCenter.SignBoardManager.RecordSignBoard(head.SignBoardConfig)
end
self.PlayUi:PlayCross(head)
self:PlayActionAnim(head)
if self.PlayOne then
-- 清空播放列表,只播放当前权重最高的动画(head)
self.PlayerData.PlayerList = {}
end
end
--检查动画是否过期(时效性)
function XSignBoardPlayer:CheckAnimValidity(Element)
if Element.Validity < 0 then
return true
else
local validity = Element.Validity + Element.AddTime
if validity > self.Time then
return true
end
end
return false
end
--停止
function XSignBoardPlayer:Stop(force)
if self.PlayerData.PlayingElement == nil then
return
end
self.PlayerData.PlayedList[self.PlayerData.PlayingElement.Id] = XTime.GetServerNowTimestamp() + self.PlayerData.PlayingElement.CoolTime
self:SetStatus(PlayerState.IDLE)
self.PlayUi:OnStop(self.PlayerData.PlayingElement, force)
self:StopActionAnim()
self.PlayerData.PlayingElement = nil
self.LastPlayTime = XTime.GetServerNowTimestamp()
end
--暂停
function XSignBoardPlayer:Pause()
self:SetStatus(PlayerState.PAUSE)
self:PauseActionAnim()
end
function XSignBoardPlayer:Freeze()
self:SetStatus(PlayerState.STOP)
self:PauseActionAnim()
end
function XSignBoardPlayer:Resume()
self.LastPlayTime = XTime.GetServerNowTimestamp()
local status = self.PlayerData.PlayingElement == nil and PlayerState.IDLE or PlayerState.PLAYING
self:SetStatus(status)
self:ResumeActionAnim()
end
--更新
function XSignBoardPlayer:Update(deltaTime)
if not self:IsActive() then
return
end
if (not self.PlayerData.PlayerList or #self.PlayerData.PlayerList == 0) and self.PlayerData.PlayingElement == nil then
return
end
if self.Status == PlayerState.STOP then
return
end
if self.Status == PlayerState.PAUSE then
return
end
self.Time = self.Time + deltaTime
if self.Time < self.DelayStart then
return
end
local nextElementTime = self.PlayerData.LastPlayTime + self.CoolTime
--存在播放中的动作
if self.PlayerData.PlayingElement ~= nil and self.PlayerData.PlayingElement.Duration > 0 then
local deadline = self.PlayerData.PlayingElement.StartTime + self.PlayerData.PlayingElement.Duration
if deadline < self.Time then
if self.PlayUi.Parent.SetWhetherPlayChangeActionEffect then
--动作生命周期正常结束,不用播放打断特效
self.PlayUi.Parent:SetWhetherPlayChangeActionEffect(false)
end
self:SetInterruptDetection(false)
self:Stop()
return
end
end
--冷却时间
if nextElementTime < self.Time and self.Status ~= PlayerState.PLAYING and self.AutoPlay then
self:PlayNextCross(true)
end
end
function XSignBoardPlayer:SetInterruptDetection(boolValue)
self.IsInInterruptDetection = boolValue
end
function XSignBoardPlayer:GetInterruptDetection()
return self.IsInInterruptDetection
end
--强制运行
function XSignBoardPlayer:ForcePlay(tab, cvType, isRecord)
if self.Status == PlayerState.STOP then
return
end
if self:Play(tab, cvType) then
self:PlayNext(isRecord)
end
end
function XSignBoardPlayer:ForcePlayCross(tab, cvType, isRecord)
if self.Status == PlayerState.STOP then
return
end
if self:Play(tab, cvType) then
self:PlayNextCross(isRecord)
end
end
function XSignBoardPlayer:IsPlaying()
return self.Status == PlayerState.PLAYING
end
--设置自动播放
function XSignBoardPlayer:SetAutoPlay(bAutoPlay)
self.AutoPlay = bAutoPlay
end
-- 播放队列是否只播放权重最高的动画
function XSignBoardPlayer:SetPlayOne(bPlayOne)
self.PlayOne = bPlayOne
end
---生命周期----------------------------------------------
function XSignBoardPlayer:IsActive()
return self.Active
end
function XSignBoardPlayer:OnEnable()
self.Active = true
self:Resume()
end
function XSignBoardPlayer:OnDisable()
self.Active = false
self:Stop()
self:ClearPlayList()
end
function XSignBoardPlayer:OnDestroy()
self:Stop()
end
-- v1.32 角色特殊动作
--===================================================================
-- 当前播放的动作是否有特殊场景动画
function XSignBoardPlayer:IsPlayingElementHaveSceneAnim()
if self.PlayerData.PlayingElement == nil then
return false
end
return XSignBoardConfigs.CheckIsHaveSceneAnim(self.PlayerData.PlayingElement.SignBoardConfig.Id)
end
-- 当前播放的动作是否有特殊Ui动画
function XSignBoardPlayer:IsPlayingElementHaveUiAnim()
if self.PlayerData.PlayingElement == nil then
return false
end
return XSignBoardConfigs.CheckIsShowHideUi(self.PlayerData.PlayingElement.SignBoardConfig.Id)
end
-- 开始播放
function XSignBoardPlayer:PlayActionAnim(head)
-- Ui动画
if XSignBoardConfigs.CheckIsShowHideUi(head.SignBoardConfig.Id) then
if self.PlayUi.PlayUiAnim then
self.PlayUi:PlayUiAnim()
end
XEventManager.DispatchEvent(XEventId.EVENT_ROLE_ACTION_UIANIM_START, head.SignBoardConfig.Id, head.Duration)
end
-- 镜头动画
if XSignBoardConfigs.CheckIsHaveSceneAnim(head.SignBoardConfig.Id) and self.PlayUi.PlaySceneAnim then
self.PlayUi:PlaySceneAnim(head)
else -- 避免本次播放没有镜头动画而上个动作有镜头动画且其处于被打断暂停状态时的镜头残留
XDataCenter.SignBoardManager.SceneAnimStop()
end
end
function XSignBoardPlayer:PauseActionAnim()
if self:IsPlayingElementHaveSceneAnim() then
XDataCenter.SignBoardManager.SceneAnimPause()
end
end
function XSignBoardPlayer:ResumeActionAnim()
if self:IsPlayingElementHaveSceneAnim() then
XDataCenter.SignBoardManager.SceneAnimResume()
end
end
-- 结束播放
function XSignBoardPlayer:StopActionAnim()
-- Ui动画处理
if self:IsPlayingElementHaveUiAnim() then
local signBoardid = self.PlayerData.PlayingElement ~= nil and self.PlayerData.PlayingElement.SignBoardConfig.Id
XEventManager.DispatchEvent(XEventId.EVENT_ROLE_ACTION_UIANIM_END, signBoardid)
end
if self:IsPlayingElementHaveSceneAnim() then
XDataCenter.SignBoardManager.SceneAnimStop()
end
-- 取消打断监听
XDataCenter.SignBoardManager.StopBreakTimer()
end
function XSignBoardPlayer:SetStatus(status)
self.Status = status
end
--===================================================================
return XSignBoardPlayer