2023-08-04 11:02:08 +08:00
|
|
|
|
package ecs
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"log"
|
|
|
|
|
"reflect"
|
|
|
|
|
"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-04 11:02:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type world struct {
|
|
|
|
|
world donburi.World
|
|
|
|
|
systems []ISystem
|
|
|
|
|
state WorldState
|
|
|
|
|
tick int
|
|
|
|
|
speed float64
|
|
|
|
|
|
|
|
|
|
quit chan struct{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewComponentType[T any](opts ...interface{}) *ComponentType[T] {
|
|
|
|
|
ct := donburi.NewComponentType[T](opts...)
|
|
|
|
|
return &ComponentType[T]{ct}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewWorld(tick int) World {
|
|
|
|
|
return &world{
|
|
|
|
|
world: donburi.NewWorld(),
|
|
|
|
|
systems: make([]ISystem, 0),
|
|
|
|
|
state: Init,
|
|
|
|
|
tick: tick,
|
|
|
|
|
speed: 1,
|
|
|
|
|
quit: make(chan struct{}),
|
|
|
|
|
}
|
|
|
|
|
}
|
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{}{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (w *world) run() {
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理所有事件
|
|
|
|
|
// w.ProcessAllEvents()
|
|
|
|
|
|
|
|
|
|
// 执行逻辑花费时间,单位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())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewEventType[T any](w World) *EventType[T] {
|
|
|
|
|
// events.NewEventType()
|
|
|
|
|
ct := NewComponentType[T]()
|
|
|
|
|
var et T
|
|
|
|
|
name := reflect.TypeOf(et).Name()
|
|
|
|
|
return &EventType[T]{
|
|
|
|
|
name,
|
|
|
|
|
ct,
|
|
|
|
|
w,
|
|
|
|
|
}
|
|
|
|
|
}
|