调整仿真运行逻辑

完善仿真状态切换逻辑
添加仿真状态变更事件可由外部监听
This commit is contained in:
walker 2023-10-12 11:07:12 +08:00
parent e779734672
commit 74c0211614
3 changed files with 144 additions and 41 deletions

View File

@ -38,13 +38,11 @@ func NewEventType[T any]() *EventType[T] {
}
// 迭代处理所有事件
// 在world协程中执行
func processAllEvents(w World) {
events.ProcessAllEvents(w)
}
// 发布该类型的事件
// 在world协程外执行
func (me *EventType[T]) Publish(wd World, event *T) {
wd.Execute(func() {
me.et.Publish(wd, *event)

37
examples/close/main.go Normal file
View File

@ -0,0 +1,37 @@
package main
import (
"log/slog"
"os"
"time"
"joylink.club/ecs"
)
type WorldTimeSys struct {
}
func (s *WorldTimeSys) Update(w ecs.World) {
slog.Info("世界更新")
// panic("更新异常")
}
func main() {
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})))
w := ecs.NewWorld(15)
// ecs.EventsDebugEnable()
ecs.WorldStateChangeEvent.Subscribe(w, func(_ ecs.World, e ecs.WorldStateChange) {
slog.Info("世界状态变更", "statechange", e)
if e.NewState == ecs.WorldClosed {
panic("状态变更监听处理异常")
}
})
slog.Info("世界启动")
w.AddSystem(&WorldTimeSys{})
w.StartUp()
time.Sleep(2 * time.Second)
w.Close()
time.Sleep(4 * time.Second)
}

146
world.go
View File

@ -15,35 +15,49 @@ type WorldState int
type WorldId = donburi.WorldId
const (
Init WorldState = iota
Running
Pause
Error
Close
Closed
WorldInit WorldState = iota
WorldRunning
WorldPause
WorldError
WorldClose
WorldClosed
)
type (
World interface {
donburi.World
// 世界运行间隔时间
Tick() int
// 启动世界
StartUp()
// 暂停世界
Pause()
// 恢复世界
Resume()
// 关闭世界
Close()
// 设置时间运行倍速
SetSpeed(speed float64) error
// 添加系统
AddSystem(sys ...ISystem)
// 在世界中执行处理逻辑(在世界运行线程中)
Execute(fn HandleFunc)
Close()
// 世界运行间隔
Tick() int
Running() bool
}
// 处理函数
HandleFunc func()
// 世界状态变更消息
WorldStateChange struct {
OldState WorldState
NewState WorldState
}
)
// 世界状态变更事件
var WorldStateChangeEvent = NewEventType[WorldStateChange]()
type world struct {
donburi.World
systems []ISystem
@ -88,7 +102,7 @@ func NewWorld(tick int) World {
return &world{
World: donburi.NewWorld(),
systems: make([]ISystem, 0),
state: Init,
state: WorldInit,
tick: tick,
ticker: time.NewTicker(time.Duration(tick) * time.Millisecond),
speed: 1,
@ -97,7 +111,7 @@ func NewWorld(tick int) World {
}
}
func (w *world) Running() bool {
return w.state == Running
return w.state == WorldRunning
}
func (w *world) Tick() int {
return w.tick
@ -115,27 +129,48 @@ func (w *world) ProcessAllEvents() {
// 暂停世界
func (w *world) Pause() {
if w.state == Running {
w.state = Pause
if w.state == WorldRunning {
w.updateState(WorldPause)
}
}
// 恢复世界运行
func (w *world) Resume() {
if w.state == Pause {
w.state = Running
if w.state == WorldPause {
w.updateState(WorldRunning)
}
}
func (w *world) updateState(state WorldState) {
if w.state != state {
old := w.state
slog.Debug("世界状态变更", "oldstate", old, "state", state)
w.state = state
WorldStateChangeEvent.Publish(w, &WorldStateChange{
OldState: old,
NewState: state,
})
WorldStateChangeEvent.et.ProcessEvents(w)
}
}
const (
SpeedMin = 0.1
SpeedMax = 10
speedMin = 0.1
speedMax = 10
)
func WorldSpeedMax() float64 {
return speedMax
}
func WorldSpeedMin() float64 {
return speedMin
}
// 设置世界运行倍速
func (w *world) SetSpeed(speed float64) error {
if speed < SpeedMin || speed > SpeedMax {
return fmt.Errorf("速度必须在[%f, %d]之间", SpeedMin, SpeedMax)
if speed < speedMin || speed > speedMax {
return fmt.Errorf("世界倍速必须在[%f, %d]之间", speedMin, speedMax)
}
w.speed = speed
return nil
@ -143,8 +178,8 @@ func (w *world) SetSpeed(speed float64) error {
// 启动世界,世界逻辑开始执行且世界为运行状态
func (w *world) StartUp() {
if w.state == Init { // 避免重复运行
w.state = Running
if w.state == WorldInit { // 避免重复运行
w.updateState(WorldRunning)
go w.run()
}
}
@ -156,7 +191,12 @@ func (w *world) Execute(fn HandleFunc) {
// 关闭世界
func (w *world) Close() {
w.state = Close
if w.state == WorldRunning || w.state == WorldPause {
w.updateState(WorldClose)
} else if w.state == WorldError {
w.updateState(WorldClosed)
w.handleRequestAndEvent()
}
}
// 执行待处理方法
@ -173,38 +213,32 @@ func (w *world) executeTodos() {
}
}
}
// 世界循环
func (w *world) run() {
defer func() {
if err := recover(); err != nil {
slog.Error("世界运行异常:", "stacks", err)
w.state = Error
w.exception(err)
}
}()
for {
if w.state == Error {
// 世界错误,关闭世界
return
}
if w.state == Close {
for range w.ticker.C {
if w.state == WorldClose {
// 世界正常关闭
w.state = Closed
w.close()
return
}
<-w.ticker.C
// start := time.Now()
if w.state == Pause { // 暂停不更新
if w.state != WorldRunning { // 世界非运行状态
w.handleRequestAndEvent()
continue
}
if w.times > 1 {
if w.times >= 1 {
times := int(math.Floor(w.times))
for i := 0; i < times; i++ {
for _, sys := range w.systems {
sys.Update(w)
}
// 处理事件管理相关
w.executeTodos()
// 处理所有事件
processAllEvents(w)
w.handleRequestAndEvent()
}
w.times = w.times - float64(times) + w.speed
} else {
@ -214,3 +248,37 @@ func (w *world) run() {
// slog.Info("仿真系统执行耗时:" + dt.Milliseconds() + "ms")
}
}
// 处理请求和事件执行
func (w *world) handleRequestAndEvent() {
// 执行待执行逻辑
w.executeTodos()
// 处理所有事件
processAllEvents(w)
}
// 世界运行异常处理
func (w *world) exception(err any) {
slog.Error("世界出现异常", "error", err)
w.updateState(WorldError)
// // 关闭定时器
// w.ticker.Stop()
w.handleRequestAndEvent()
}
// 世界正常关闭逻辑
func (w *world) close() {
// 世界正常关闭
w.updateState(WorldClosed)
// 关闭定时器
w.ticker.Stop()
go func() {
defer func() {
if err := recover(); err != nil {
slog.Error("世界关闭监听处理可能异常", "error", err)
}
}()
w.handleRequestAndEvent()
}()
slog.Debug("世界关闭finish")
}