From ba2f3af39855b5d860e6483f0281e430742f591b Mon Sep 17 00:00:00 2001 From: kercylan98 Date: Tue, 17 Oct 2023 15:47:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20fight.TurnBased=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E7=9B=91=E5=90=AC=E5=9B=9E=E5=90=88=E5=8F=98=E6=9B=B4=E4=BB=A5?= =?UTF-8?q?=E5=8F=8A=E5=88=B7=E6=96=B0=E5=BD=93=E5=89=8D=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E5=9B=9E=E5=90=88=E8=B6=85=E6=97=B6=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- game/fight/turn_based.go | 31 ++++++++++++++++++++--------- game/fight/turn_based_controller.go | 17 +++++++++++++++- game/fight/turn_based_events.go | 14 +++++++++++++ game/fight/turn_based_test.go | 6 ++++++ 4 files changed, 58 insertions(+), 10 deletions(-) diff --git a/game/fight/turn_based.go b/game/fight/turn_based.go index 6f9110a..b988e75 100644 --- a/game/fight/turn_based.go +++ b/game/fight/turn_based.go @@ -7,10 +7,15 @@ import ( ) const ( - signalFinish = 1 + iota // 操作结束信号 - signalStop // 停止回合制信号 + signalFinish = 1 + iota // 操作结束信号 + 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++ - } - } } diff --git a/game/fight/turn_based_controller.go b/game/fight/turn_based_controller.go index 174ee70..9f4f727 100644 --- a/game/fight/turn_based_controller.go +++ b/game/fight/turn_based_controller.go @@ -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{} +} diff --git a/game/fight/turn_based_events.go b/game/fight/turn_based_events.go index 9e0759f..a3b4119 100644 --- a/game/fight/turn_based_events.go +++ b/game/fight/turn_based_events.go @@ -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) + } +} diff --git a/game/fight/turn_based_test.go b/game/fight/turn_based_test.go index 7fda339..8504ae9 100644 --- a/game/fight/turn_based_test.go +++ b/game/fight/turn_based_test.go @@ -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(), "开始行动")