jl-ecs/world.go
walker cbb36d8c08 删除goroutineid及相关逻辑
修改世界运行逻辑循环从使用睡眠改为使用Ticker(睡眠会有因go调度产生的额外几毫秒时间问题)
2023-09-20 15:30:51 +08:00

254 lines
5.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package ecs
import (
"fmt"
"log"
"time"
"github.com/yohamta/donburi"
"github.com/yohamta/donburi/features/events"
)
type WorldState int
type WorldId int
const (
Init WorldState = iota
Running
Pause
Error
Closed
)
type World interface {
// Id returns the unique identifier for the world.
Id() WorldId
// Create creates a new entity with the specified components.
Create(components ...donburi.IComponentType) *Entry
// CreateMany creates a new entity with the specified components.
CreateMany(n int, components ...donburi.IComponentType) []*Entry
// Entry returns an entry for the specified entity.
Entry(entity Entity) *Entry
// Remove removes the specified entity.
Remove(entity Entity)
// Valid returns true if the specified entity is valid.
Valid(e Entity) bool
// Len returns the number of entities in the world.
Len() int
StartUp()
Pause()
Resume()
SetSpeed(speed float64) error
AddSystem(sys ...ISystem)
Close()
// 世界时间间隔
Tick() int
Running() bool
}
type world struct {
world donburi.World
systems []ISystem
state WorldState
tick int
lastTick time.Time
ticker *time.Ticker
speed float64
quit chan struct{}
chanManageEvent chan ManageEventFunc
}
func NewComponentType[T any](opts ...interface{}) *ComponentType[T] {
ct := donburi.NewComponentType[T](opts...)
return &ComponentType[T]{ct}
}
// 初始化一个新World
// tick 单位为ms且必须大于0
func NewWorld(tick int) World {
return &world{
world: donburi.NewWorld(),
systems: make([]ISystem, 0),
state: Init,
tick: tick,
lastTick: time.Now(),
ticker: time.NewTicker(time.Duration(tick) * time.Millisecond),
speed: 1,
quit: make(chan struct{}),
chanManageEvent: make(chan ManageEventFunc, 1024),
}
}
func (w *world) Running() bool {
return w.state == Running
}
func (w *world) Tick() int {
return w.tick
}
func (w *world) Id() WorldId {
return WorldId(w.world.Id())
}
func (w *world) Create(components ...donburi.IComponentType) *Entry {
entity := w.world.Create(components...)
return &Entry{w.world.Entry(entity)}
}
func (w *world) CreateMany(n int, components ...donburi.IComponentType) []*Entry {
entitys := w.world.CreateMany(n, components...)
ets := make([]*Entry, len(entitys))
for i, e := range entitys {
ets[i] = &Entry{w.world.Entry(e)}
}
return ets
}
func (w *world) Entry(entity Entity) *Entry {
return &Entry{w.world.Entry(entity.Entity)}
}
func (w *world) Remove(entity Entity) {
w.world.Remove(entity.Entity)
}
func (w *world) Valid(e Entity) bool {
return w.world.Valid(e.Entity)
}
func (w *world) Len() int {
return w.world.Len()
}
// 添加系统
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
fmt.Println("更新速度实际tick=", w.ActualTick())
w.ticker.Reset(time.Duration(w.ActualTick()) * time.Millisecond)
return nil
}
// 世界实际运行频率
func (w *world) ActualTick() int64 {
tick := int64(float64(w.tick) / (w.speed))
if tick <= 0 {
return 1
}
return tick
}
// 启动世界,世界逻辑开始执行且世界为运行状态
func (w *world) StartUp() {
if w.state == Init { // 避免重复运行
w.state = Running
go w.run()
}
}
// 关闭世界
func (w *world) Close() {
w.quit <- struct{}{}
}
// 获取world与事件系统间的管道的只读引用
func (w *world) eventChanReader() <-chan ManageEventFunc {
return w.chanManageEvent
}
// 事件管理相关处理
func (w *world) processManageEventFuncs() {
manageEventChan := w.eventChanReader()
for {
select {
case callBack := <-manageEventChan:
{
callBack()
}
default:
return
}
}
}
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 {
// 世界正常关闭
return
}
<-w.ticker.C
if w.state == Pause { // 暂停不更新
// time.Sleep(1 * time.Millisecond)
continue
}
// dt := time.Since(w.lastTick).Milliseconds()
// if dt >= w.ActualTick() {
// // fmt.Println("仿真更新,id:", info.id)
// w.lastTick = time.Now()
// for _, sys := range w.systems {
// sys.Update(w)
// }
// // 处理事件管理相关
// w.processManageEventFuncs()
// // 处理所有事件
// processAllEvents(w)
// }
// time.Sleep(15 * time.Millisecond)
for _, sys := range w.systems {
sys.Update(w)
}
// 处理事件管理相关
w.processManageEventFuncs()
// 处理所有事件
processAllEvents(w)
}
}