jl-ecs/world.go

256 lines
5.3 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 (
"context"
"fmt"
"log"
"math"
"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)
// 在世界中执行逻辑(在世界运行线程中)
Execute(fn ExecuteFunc)
Close()
// 世界时间间隔
Tick() int
Running() bool
}
// 世界执行函数
ExecuteFunc func()
RequestFunc func() any
WorldRequest struct {
req RequestFunc
context context.Context
}
)
type world struct {
world donburi.World
systems []ISystem
state WorldState
tick int
ticker *time.Ticker
speed float64
// 下一帧需要执行的次数
times float64
// 退出信号
quit chan struct{}
// 待执行函数
toBeExecuteds chan ExecuteFunc
}
// 新建一个组件类型
func NewComponentType[T any](opts ...interface{}) *ComponentType[T] {
ct := donburi.NewComponentType[T](opts...)
return &ComponentType[T]{ct}
}
// 新建一个标签注意新建的标签如果作为全局变量使用EachFirst等方法时必须在World线程中执行即调用World.Execute执行
func NewTag() *ComponentType[struct{}] {
return NewComponentType[struct{}]()
}
// 初始化一个新World
// tick 单位为ms且必须大于0,(小于15ms的值在Windows系统中会达不到Windows系统中系统中断好像默认是15.6ms也就是一秒最多64次)
func NewWorld(tick int) World {
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,
quit: make(chan struct{}),
toBeExecuteds: make(chan ExecuteFunc, 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
return nil
}
// 启动世界,世界逻辑开始执行且世界为运行状态
func (w *world) StartUp() {
if w.state == Init { // 避免重复运行
w.state = Running
go w.run()
}
}
// 在世界线程执行逻辑
func (w *world) Execute(fn ExecuteFunc) {
w.toBeExecuteds <- fn
}
// 关闭世界
func (w *world) Close() {
w.quit <- struct{}{}
}
// 执行待处理方法
func (w *world) executeTodos() {
manageEventChan := w.toBeExecuteds
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 { // 暂停不更新
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
}
}
}