feat: fight.TurnBased 支持监听回合变更以及刷新当前操作回合超时时间

This commit is contained in:
kercylan98 2023-10-17 15:47:15 +08:00
parent 378f855992
commit ba2f3af398
4 changed files with 58 additions and 10 deletions

View File

@ -8,9 +8,14 @@ import (
const (
signalFinish = 1 + iota // 操作结束信号
signalStop // 停止回合制信号
signalRefresh // 刷新操作超时时间信号
)
type signal struct {
sign byte
data any
}
// NewTurnBased 创建一个新的回合制
// - calcNextTurnDuration 将返回下一次行动时间间隔,适用于按照速度计算下一次行动时间间隔的情况。当返回 0 时,将使用默认的行动超时时间
func NewTurnBased[CampID, EntityID comparable, Camp generic.IdR[CampID], Entity generic.IdR[EntityID]](calcNextTurnDuration func(Camp, Entity) time.Duration) *TurnBased[CampID, EntityID, Camp, Entity] {
@ -39,7 +44,7 @@ type TurnBased[CampID, EntityID comparable, Camp generic.IdR[CampID], Entity gen
calcNextTurnDuration func(Camp, Entity) time.Duration // 下一次行动时间间隔
actionTimeoutHandler func(Camp, Entity) time.Duration // 行动超时时间
signal chan byte // 信号
signal chan signal // 信号
round int // 当前回合数
currCamp Camp // 当前操作阵营
currEntity Entity // 当前操作实体
@ -77,7 +82,7 @@ func (slf *TurnBased[CampID, EntityID, Camp, Entity]) SetActionTimeout(actionTim
// Run 运行
func (slf *TurnBased[CampID, EntityID, Camp, Entity]) Run() {
slf.round = 1
slf.signal = make(chan byte, 1)
slf.signal = make(chan signal, 1)
var actionDuration = make(map[EntityID]time.Duration)
var actionSubmit = func() {
slf.actionMutex.Lock()
@ -141,24 +146,34 @@ func (slf *TurnBased[CampID, EntityID, Camp, Entity]) Run() {
}
breakListen:
for {
wait:
select {
case <-slf.actionWaitTicker.C:
actionSubmit()
slf.OnTurnBasedEntityActionTimeoutEvent(slf.controller)
break breakListen
case sign := <-slf.signal:
switch sign {
switch sign.sign {
case signalFinish:
actionSubmit()
slf.OnTurnBasedEntityActionFinishEvent(slf.controller)
break breakListen
case signalRefresh:
slf.actionWaitTicker.Reset(sign.data.(time.Duration))
goto wait
}
}
}
slf.OnTurnBasedEntityActionSubmitEvent(slf.controller)
if len(actionDuration) == 0 {
slf.round++
}
slf.closeMutex.Lock()
if slf.closed {
if len(actionDuration) == 0 {
slf.round--
}
if slf.ticker != nil {
slf.ticker.Stop()
slf.ticker = nil
@ -173,12 +188,10 @@ func (slf *TurnBased[CampID, EntityID, Camp, Entity]) Run() {
}
slf.closeMutex.Unlock()
break
} else if len(actionDuration) == 0 {
slf.OnTurnBasedRoundChangeEvent(slf.controller)
}
slf.closeMutex.Unlock()
if len(actionDuration) == 0 {
slf.round++
}
}
}

View File

@ -26,6 +26,8 @@ type TurnBasedControllerAction[CampID, EntityID comparable, Camp generic.IdR[Cam
TurnBasedControllerInfo[CampID, EntityID, Camp, Entity]
// Finish 结束当前操作,将立即切换到下一个操作实体
Finish()
// Refresh 刷新当前操作实体的行动超时时间并返回新的行动超时时间
Refresh(duration time.Duration) time.Time
}
// TurnBasedController 回合制控制器
@ -69,7 +71,7 @@ func (slf *TurnBasedController[CampID, EntityID, Camp, Entity]) Finish() {
defer slf.tb.actionMutex.Unlock()
if slf.tb.actioning {
slf.tb.actioning = false
slf.tb.signal <- signalFinish
slf.tb.signal <- signal{sign: signalFinish}
}
}
@ -77,3 +79,16 @@ func (slf *TurnBasedController[CampID, EntityID, Camp, Entity]) Finish() {
func (slf *TurnBasedController[CampID, EntityID, Camp, Entity]) Stop() {
slf.tb.Close()
}
// Refresh 刷新当前操作实体的行动超时时间
// - 当不在行动阶段时,将返回 time.Time 零值
func (slf *TurnBasedController[CampID, EntityID, Camp, Entity]) Refresh(duration time.Duration) time.Time {
slf.tb.actionMutex.Lock()
defer slf.tb.actionMutex.Unlock()
if slf.tb.actioning {
slf.tb.actioning = false
slf.tb.signal <- signal{sign: signalRefresh, data: duration}
return time.Now().Add(duration)
}
return time.Time{}
}

View File

@ -7,6 +7,7 @@ type (
TurnBasedEntityActionTimeoutEventHandler[CampID, EntityID comparable, Camp generic.IdR[CampID], Entity generic.IdR[EntityID]] func(controller TurnBasedControllerInfo[CampID, EntityID, Camp, Entity])
TurnBasedEntityActionFinishEventHandler[CampID, EntityID comparable, Camp generic.IdR[CampID], Entity generic.IdR[EntityID]] func(controller TurnBasedControllerInfo[CampID, EntityID, Camp, Entity])
TurnBasedEntityActionSubmitEventHandler[CampID, EntityID comparable, Camp generic.IdR[CampID], Entity generic.IdR[EntityID]] func(controller TurnBasedControllerInfo[CampID, EntityID, Camp, Entity])
TurnBasedRoundChangeEventHandler[CampID, EntityID comparable, Camp generic.IdR[CampID], Entity generic.IdR[EntityID]] func(controller TurnBasedControllerInfo[CampID, EntityID, Camp, Entity])
)
type turnBasedEvents[CampID, EntityID comparable, Camp generic.IdR[CampID], Entity generic.IdR[EntityID]] struct {
@ -14,6 +15,7 @@ type turnBasedEvents[CampID, EntityID comparable, Camp generic.IdR[CampID], Enti
actionTimeoutEventHandlers []TurnBasedEntityActionTimeoutEventHandler[CampID, EntityID, Camp, Entity]
actionFinishEventHandlers []TurnBasedEntityActionFinishEventHandler[CampID, EntityID, Camp, Entity]
actionSubmitEventHandlers []TurnBasedEntityActionSubmitEventHandler[CampID, EntityID, Camp, Entity]
roundChangeEventHandlers []TurnBasedRoundChangeEventHandler[CampID, EntityID, Camp, Entity]
}
// RegTurnBasedEntitySwitchEvent 注册回合制实体切换事件处理函数,该处理函数将在切换到实体切换为操作时机时触发
@ -70,3 +72,15 @@ func (slf *turnBasedEvents[CampID, EntityID, Camp, Entity]) OnTurnBasedEntityAct
handler(controller)
}
}
// RegTurnBasedRoundChangeEvent 注册回合制回合变更事件处理函数,该处理函数将在回合变更时触发
func (slf *turnBasedEvents[CampID, EntityID, Camp, Entity]) RegTurnBasedRoundChangeEvent(handler TurnBasedRoundChangeEventHandler[CampID, EntityID, Camp, Entity]) {
slf.roundChangeEventHandlers = append(slf.roundChangeEventHandlers, handler)
}
// OnTurnBasedRoundChangeEvent 触发回合制回合变更事件
func (slf *turnBasedEvents[CampID, EntityID, Camp, Entity]) OnTurnBasedRoundChangeEvent(controller TurnBasedControllerInfo[CampID, EntityID, Camp, Entity]) {
for _, handler := range slf.roundChangeEventHandlers {
handler(controller)
}
}

View File

@ -36,6 +36,10 @@ func TestTurnBased_Run(t *testing.T) {
t.Log("时间", time.Now().Unix(), "回合", controller.GetRound(), "阵营", controller.GetCamp().GetId(), "实体", controller.GetEntity().GetId(), "超时")
})
tbi.RegTurnBasedRoundChangeEvent(func(controller fight.TurnBasedControllerInfo[string, string, *Camp, *Entity]) {
t.Log("时间", time.Now().Unix(), "回合", controller.GetRound(), "回合切换")
})
tbi.RegTurnBasedEntitySwitchEvent(func(controller fight.TurnBasedControllerAction[string, string, *Camp, *Entity]) {
switch controller.GetEntity().GetId() {
case "1":
@ -44,6 +48,8 @@ func TestTurnBased_Run(t *testing.T) {
controller.Finish()
}()
case "2":
controller.Refresh(time.Second)
case "4":
controller.Stop()
}
t.Log("时间", time.Now().Unix(), "回合", controller.GetRound(), "阵营", controller.GetCamp().GetId(), "实体", controller.GetEntity().GetId(), "开始行动")