jl-ecs/world.go

254 lines
5.2 KiB
Go
Raw Normal View History

2023-08-04 11:02:08 +08:00
package ecs
import (
2023-08-31 16:19:41 +08:00
"bytes"
2023-08-04 11:02:08 +08:00
"fmt"
"log"
2023-08-31 16:19:41 +08:00
"runtime"
"strconv"
2023-08-04 11:02:08 +08:00
"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.
2023-08-04 16:56:36 +08:00
Create(components ...donburi.IComponentType) *Entry
2023-08-04 11:02:08 +08:00
// CreateMany creates a new entity with the specified components.
2023-08-04 16:56:36 +08:00
CreateMany(n int, components ...donburi.IComponentType) []*Entry
2023-08-04 11:02:08 +08:00
// 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()
2023-08-15 09:17:22 +08:00
Tick() int
2023-08-15 16:48:55 +08:00
Running() bool
2023-08-31 16:19:41 +08:00
GoroutineId() uint64
2023-08-04 11:02:08 +08:00
}
type world struct {
2023-08-31 16:19:41 +08:00
gId uint64
2023-08-04 11:02:08 +08:00
world donburi.World
systems []ISystem
state WorldState
tick int
speed float64
2023-08-31 16:19:41 +08:00
quit chan struct{}
chanManageEvent chan ManageEventFunc
2023-08-04 11:02:08 +08:00
}
func NewComponentType[T any](opts ...interface{}) *ComponentType[T] {
ct := donburi.NewComponentType[T](opts...)
return &ComponentType[T]{ct}
}
func NewWorld(tick int) World {
return &world{
2023-08-31 16:19:41 +08:00
world: donburi.NewWorld(),
systems: make([]ISystem, 0),
state: Init,
tick: tick,
speed: 1,
quit: make(chan struct{}),
chanManageEvent: make(chan ManageEventFunc, 1024),
2023-08-04 11:02:08 +08:00
}
}
2023-08-31 16:19:41 +08:00
func (w *world) GoroutineId() uint64 {
return w.gId
}
2023-08-15 16:48:55 +08:00
func (w *world) Running() bool {
return w.state == Running
}
2023-08-15 09:17:22 +08:00
func (w *world) Tick() int {
return w.tick
}
2023-08-04 11:02:08 +08:00
func (w *world) Id() WorldId {
return WorldId(w.world.Id())
}
2023-08-04 16:56:36 +08:00
func (w *world) Create(components ...donburi.IComponentType) *Entry {
2023-08-04 13:19:59 +08:00
entity := w.world.Create(components...)
2023-08-04 16:56:36 +08:00
return &Entry{w.world.Entry(entity)}
2023-08-04 11:02:08 +08:00
}
2023-08-04 16:56:36 +08:00
func (w *world) CreateMany(n int, components ...donburi.IComponentType) []*Entry {
2023-08-04 11:02:08 +08:00
entitys := w.world.CreateMany(n, components...)
2023-08-04 16:56:36 +08:00
ets := make([]*Entry, len(entitys))
2023-08-04 11:02:08 +08:00
for i, e := range entitys {
2023-08-04 16:56:36 +08:00
ets[i] = &Entry{w.world.Entry(e)}
2023-08-04 11:02:08 +08:00
}
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) Close() {
w.quit <- struct{}{}
}
2023-08-31 16:19:41 +08:00
// 获取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
}
}
}
2023-08-04 11:02:08 +08:00
func (w *world) run() {
2023-08-31 16:19:41 +08:00
w.gId = currentGoId()
2023-08-04 11:02:08 +08:00
for {
select {
case <-w.quit: // 退出信号
log.Println("仿真退出,id:", w.world.Id())
w.state = Closed
default:
}
if w.state == Error {
log.Println("世界错误,关闭世界,id:", w.world.Id())
return
}
if w.state == Closed {
log.Println("世界正常关闭,id:", w.world.Id())
return
}
if w.state == Pause { // 暂停不更新
log.Println("仿真暂停中,id:", w.world.Id())
sleep := int64(float64(w.tick) / (w.speed))
time.Sleep(time.Duration(sleep) * time.Millisecond)
continue
}
start := time.Now()
// fmt.Println("仿真更新,id:", info.id)
for _, sys := range w.systems {
sys.Update(w)
}
2023-08-31 16:19:41 +08:00
// 处理事件管理相关
w.processManageEventFuncs()
2023-08-04 11:02:08 +08:00
// 处理所有事件
2023-08-31 16:19:41 +08:00
processAllEvents(w)
2023-08-04 11:02:08 +08:00
// 执行逻辑花费时间单位ms
ot := time.Duration(time.Now().Nanosecond() - start.Nanosecond()).Milliseconds()
// 根据间隔和速度计算休眠时间
sleep := int64(float64(w.tick)/(w.speed)) - ot
if sleep > 0 {
time.Sleep(time.Duration(sleep) * time.Millisecond)
} else {
log.Println("仿真无休眠,id:", w.world.Id())
}
}
}
2023-08-31 16:19:41 +08:00
// 获取当前协程id
func currentGoId() (gid uint64) {
b := make([]byte, 16)
b = b[:runtime.Stack(b, false)]
b = bytes.TrimPrefix(b, []byte("goroutine "))
b = b[:bytes.IndexByte(b, ' ')]
n, err := strconv.ParseUint(string(b), 10, 64)
if err != nil {
panic(err)
2023-08-04 11:02:08 +08:00
}
2023-08-31 16:19:41 +08:00
return n
2023-08-04 11:02:08 +08:00
}