217 lines
4.0 KiB
Go
217 lines
4.0 KiB
Go
package ecs
|
||
|
||
import (
|
||
"fmt"
|
||
"log/slog"
|
||
"math"
|
||
"time"
|
||
|
||
"github.com/yohamta/donburi"
|
||
"github.com/yohamta/donburi/features/events"
|
||
)
|
||
|
||
type WorldState int
|
||
|
||
type WorldId = donburi.WorldId
|
||
|
||
const (
|
||
Init WorldState = iota
|
||
Running
|
||
Pause
|
||
Error
|
||
Close
|
||
Closed
|
||
)
|
||
|
||
type (
|
||
World interface {
|
||
donburi.World
|
||
|
||
StartUp()
|
||
Pause()
|
||
Resume()
|
||
SetSpeed(speed float64) error
|
||
AddSystem(sys ...ISystem)
|
||
// 在世界中执行处理逻辑(在世界运行线程中)
|
||
Execute(fn HandleFunc)
|
||
Close()
|
||
// 世界运行间隔
|
||
Tick() int
|
||
Running() bool
|
||
}
|
||
|
||
// 处理函数
|
||
HandleFunc func()
|
||
)
|
||
|
||
type world struct {
|
||
donburi.World
|
||
systems []ISystem
|
||
state WorldState
|
||
tick int
|
||
ticker *time.Ticker
|
||
// 世界运行倍速
|
||
speed float64
|
||
// 下一帧系统需要执行的次数
|
||
times float64
|
||
|
||
// 待执行函数
|
||
toBeExecuteds chan HandleFunc
|
||
}
|
||
|
||
// 新建一个组件类型
|
||
func NewComponentType[T any](opts ...interface{}) *ComponentType[T] {
|
||
ct := donburi.NewComponentType[T](opts...)
|
||
return &ComponentType[T]{ct}
|
||
}
|
||
|
||
// 新建一个标签
|
||
func NewTag() *ComponentType[struct{}] {
|
||
return NewComponentType[struct{}]()
|
||
}
|
||
|
||
// 将entity列表转换为entry列表
|
||
func Entries(w World, entities []donburi.Entity) []*Entry {
|
||
entries := make([]*Entry, len(entities))
|
||
for i, entity := range entities {
|
||
entries[i] = w.Entry(entity)
|
||
}
|
||
return entries
|
||
}
|
||
|
||
// 初始化一个新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),
|
||
state: Init,
|
||
tick: tick,
|
||
ticker: time.NewTicker(time.Duration(tick) * time.Millisecond),
|
||
speed: 1,
|
||
times: 1,
|
||
toBeExecuteds: make(chan HandleFunc, 32),
|
||
}
|
||
}
|
||
func (w *world) Running() bool {
|
||
return w.state == Running
|
||
}
|
||
func (w *world) Tick() int {
|
||
return w.tick
|
||
}
|
||
|
||
// 添加系统
|
||
func (w *world) AddSystem(sys ...ISystem) {
|
||
w.systems = append(w.systems, sys...)
|
||
}
|
||
|
||
// 执行所有事件处理
|
||
func (w *world) ProcessAllEvents() {
|
||
events.ProcessAllEvents(w.World)
|
||
}
|
||
|
||
// 暂停世界
|
||
func (w *world) Pause() {
|
||
if w.state == Running {
|
||
w.state = Pause
|
||
}
|
||
}
|
||
|
||
// 恢复世界运行
|
||
func (w *world) Resume() {
|
||
if w.state == Pause {
|
||
w.state = Running
|
||
}
|
||
}
|
||
|
||
const (
|
||
SpeedMin = 0.1
|
||
SpeedMax = 10
|
||
)
|
||
|
||
// 设置世界运行倍速
|
||
func (w *world) SetSpeed(speed float64) error {
|
||
if speed < SpeedMin || speed > SpeedMax {
|
||
return fmt.Errorf("速度必须在[%f, %d]之间", SpeedMin, SpeedMax)
|
||
}
|
||
w.speed = speed
|
||
return nil
|
||
}
|
||
|
||
// 启动世界,世界逻辑开始执行且世界为运行状态
|
||
func (w *world) StartUp() {
|
||
if w.state == Init { // 避免重复运行
|
||
w.state = Running
|
||
go w.run()
|
||
}
|
||
}
|
||
|
||
// 在世界线程执行逻辑
|
||
func (w *world) Execute(fn HandleFunc) {
|
||
w.toBeExecuteds <- fn
|
||
}
|
||
|
||
// 关闭世界
|
||
func (w *world) Close() {
|
||
w.state = Close
|
||
}
|
||
|
||
// 执行待处理方法
|
||
func (w *world) executeTodos() {
|
||
funcs := w.toBeExecuteds
|
||
for {
|
||
select {
|
||
case fn := <-funcs:
|
||
{
|
||
fn()
|
||
}
|
||
default:
|
||
return
|
||
}
|
||
}
|
||
}
|
||
func (w *world) run() {
|
||
defer func() {
|
||
if err := recover(); err != nil {
|
||
slog.Error("世界运行异常:", "stacks", err)
|
||
w.state = Error
|
||
}
|
||
}()
|
||
for {
|
||
if w.state == Error {
|
||
// 世界错误,关闭世界
|
||
return
|
||
}
|
||
if w.state == Close {
|
||
// 世界正常关闭
|
||
w.state = Closed
|
||
return
|
||
}
|
||
<-w.ticker.C
|
||
// start := time.Now()
|
||
if w.state == Pause { // 暂停不更新
|
||
continue
|
||
}
|
||
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.times = w.times - float64(times) + w.speed
|
||
} else {
|
||
w.times += w.speed
|
||
}
|
||
// dt := time.Since(start)
|
||
// slog.Info("仿真系统执行耗时:" + dt.Milliseconds() + "ms")
|
||
}
|
||
}
|