diff --git a/examples/main.go b/examples/main.go new file mode 100644 index 0000000..6b1efda --- /dev/null +++ b/examples/main.go @@ -0,0 +1,36 @@ +package main + +import ( + "fmt" + "time" + + "joylink.club/ecs" +) + +func main() { + sim := ecs.NewWorld(20) + sim.StartUp() + sim.Pause() + + go func() { + time.Sleep(1 * time.Second) + sim.Resume() + }() + + // 超出channel缓冲区(超出后,会阻塞) + for i := 0; i < 50; i++ { + sim.Execute(func() { + fmt.Println("测试执行") + }) + } + + // 请求功能测试 + future := ecs.Request[int](sim, func() int { + fmt.Println("执行请求") + return 20 + }) + result := <-future + fmt.Println("执行结果:", result) + + time.Sleep(2 * time.Second) +} diff --git a/request.go b/request.go new file mode 100644 index 0000000..585a504 --- /dev/null +++ b/request.go @@ -0,0 +1,15 @@ +package ecs + +// 请求世界执行给定函数 +func Request[T any](w World, fn func() T) chan T { + future := make(chan T) + w.Execute(func() { + r := fn() + select { + // 及时外面不接收,也不会卡停World运行 + case future <- r: + default: + } + }) + return future +} diff --git a/world.go b/world.go index 75afe48..4618c9a 100644 --- a/world.go +++ b/world.go @@ -1,9 +1,7 @@ package ecs import ( - "context" "fmt" - "log" "math" "time" @@ -20,6 +18,7 @@ const ( Running Pause Error + Close Closed ) @@ -32,21 +31,16 @@ type ( Resume() SetSpeed(speed float64) error AddSystem(sys ...ISystem) - // 在世界中执行逻辑(在世界运行线程中) - Execute(fn ExecuteFunc) + // 在世界中执行处理逻辑(在世界运行线程中) + Execute(fn HandleFunc) Close() - // 世界时间间隔 + // 世界运行间隔 Tick() int Running() bool } - // 世界执行函数 - ExecuteFunc func() - RequestFunc func() any - WorldRequest struct { - req RequestFunc - context context.Context - } + // 处理函数 + HandleFunc func() ) type world struct { @@ -55,14 +49,13 @@ type world struct { state WorldState tick int ticker *time.Ticker - speed float64 - // 下一帧需要执行的次数 + // 世界运行倍速 + speed float64 + // 下一帧系统需要执行的次数 times float64 - // 退出信号 - quit chan struct{} // 待执行函数 - toBeExecuteds chan ExecuteFunc + toBeExecuteds chan HandleFunc } // 新建一个组件类型 @@ -71,7 +64,7 @@ func NewComponentType[T any](opts ...interface{}) *ComponentType[T] { return &ComponentType[T]{ct} } -// 新建一个标签(注意:新建的标签如果作为全局变量,使用Each,First等方法时必须在World线程中执行,即调用World.Execute执行) +// 新建一个标签 func NewTag() *ComponentType[struct{}] { return NewComponentType[struct{}]() } @@ -88,6 +81,9 @@ func Entries(w World, entities []donburi.Entity) []*Entry { // 初始化一个新World // tick 单位为ms,且必须大于0,(小于15ms的值在Windows系统中会达不到,Windows系统中系统中断好像默认是15.6ms,也就是一秒最多64次) func NewWorld(tick int) World { + if tick <= 0 { + panic("tick必须大于0") + } return &world{ World: donburi.NewWorld(), systems: make([]ISystem, 0), @@ -96,8 +92,7 @@ func NewWorld(tick int) World { ticker: time.NewTicker(time.Duration(tick) * time.Millisecond), speed: 1, times: 1, - quit: make(chan struct{}), - toBeExecuteds: make(chan ExecuteFunc, 256), + toBeExecuteds: make(chan HandleFunc, 32), } } func (w *world) Running() bool { @@ -136,7 +131,7 @@ const ( SpeedMax = 10 ) -// 设置世界运行速度 +// 设置世界运行倍速 func (w *world) SetSpeed(speed float64) error { if speed < SpeedMin || speed > SpeedMax { return fmt.Errorf("速度必须在[%f, %d]之间", SpeedMin, SpeedMax) @@ -154,23 +149,23 @@ func (w *world) StartUp() { } // 在世界线程执行逻辑 -func (w *world) Execute(fn ExecuteFunc) { +func (w *world) Execute(fn HandleFunc) { w.toBeExecuteds <- fn } // 关闭世界 func (w *world) Close() { - w.quit <- struct{}{} + w.state = Close } // 执行待处理方法 func (w *world) executeTodos() { - manageEventChan := w.toBeExecuteds + funcs := w.toBeExecuteds for { select { - case callBack := <-manageEventChan: + case fn := <-funcs: { - callBack() + fn() } default: return @@ -179,19 +174,13 @@ func (w *world) executeTodos() { } func (w *world) run() { for { - select { - case <-w.quit: // 退出信号 - // 仿真退出,更新状态 - log.Println("仿真退出,id:", w.World.Id()) - w.state = Closed - default: - } if w.state == Error { // 世界错误,关闭世界 return } - if w.state == Closed { + if w.state == Close { // 世界正常关闭 + w.state = Closed return } <-w.ticker.C