ecs添加事件处理

This commit is contained in:
xzb 2023-08-31 16:19:41 +08:00
parent 8ffea356da
commit 0cdbe6fdd0
3 changed files with 181 additions and 27 deletions

105
events.go
View File

@ -1,11 +1,102 @@
package ecs package ecs
type ( import (
EventType[T any] struct { "reflect"
eventName string
componentType *ComponentType[T]
w World
}
Subscriber[T any] func(w *World, event T) "github.com/yohamta/donburi"
"github.com/yohamta/donburi/features/events"
) )
// 注意事件相关操作的最终执行者均为world协程
// 事件相关定义
type (
// 事件类型定义
EventType[T any] struct {
et *events.EventType[T]
subscriberMap map[uintptr]events.Subscriber[T]
chanToWorld chan<- ManageEventFunc
}
// 事件订阅者定义
Subscriber[T any] func(w World, event T)
// 事件管理回调定义
ManageEventFunc func()
)
func init() {
//开启事件处理调试
events.Debug = true
}
// 创建事件类型的实例
func NewEventType[T any](w World) *EventType[T] {
return &EventType[T]{
et: events.NewEventType[T](),
subscriberMap: make(map[uintptr]events.Subscriber[T]),
chanToWorld: w.(*world).chanManageEvent,
}
}
// 迭代处理所有事件
// 在world协程中执行
func processAllEvents(w World) {
events.ProcessAllEvents(w.(*world).world)
}
// 订阅该类型的事件
func (me *EventType[T]) Subscribe(wd World, subscriber Subscriber[T]) {
if wd.GoroutineId() == currentGoId() {
me.subscribe(wd, subscriber)
} else {
me.chanToWorld <- func() {
me.subscribe(wd, subscriber)
}
}
}
// 取消订阅该类型的事件
func (me *EventType[T]) Unsubscribe(wd World, subscriber Subscriber[T]) {
if wd.GoroutineId() == currentGoId() {
me.unsubscribe(wd, subscriber)
} else {
me.chanToWorld <- func() {
me.unsubscribe(wd, subscriber)
}
}
}
// 发布该类型的事件
func (me *EventType[T]) Publish(wd World, event *T) {
if wd.GoroutineId() == currentGoId() {
me.publish(wd, event)
} else {
me.chanToWorld <- func() {
me.publish(wd, event)
}
}
}
///////////////////////////////////////////////////////////////////////////////////
// 订阅该类型的事件
func (me *EventType[T]) subscribe(wd World, subscriber Subscriber[T]) {
wdSubscriberPointer := reflect.ValueOf(subscriber).Pointer()
me.subscriberMap[wdSubscriberPointer] = func(w donburi.World, event T) {
subscriber(wd, event)
}
me.et.Subscribe(wd.(*world).world, me.subscriberMap[wdSubscriberPointer])
}
// 取消订阅该类型的事件
func (me *EventType[T]) unsubscribe(wd World, subscriber Subscriber[T]) {
wdSubscriberPointer := reflect.ValueOf(subscriber).Pointer()
if sub, ok := me.subscriberMap[wdSubscriberPointer]; ok {
me.et.Unsubscribe(wd.(*world).world, sub)
delete(me.subscriberMap, wdSubscriberPointer)
}
}
// 发布该类型的事件
func (me *EventType[T]) publish(wd World, event *T) {
me.et.Publish(wd.(*world).world, *event)
}

View File

@ -0,0 +1,31 @@
package main
import (
"fmt"
"time"
"joylink.club/ecs"
)
type FireSwitchDcEvent struct {
Dc bool
}
func main() {
world := ecs.NewWorld(1000)
world.StartUp()
//
fireSwitchDcEventType := ecs.NewEventType[FireSwitchDcEvent](world)
fireSwitchDcEventType.Subscribe(world, func(w ecs.World, event FireSwitchDcEvent) {
fmt.Println("==>>1 触发道岔定操事件 : dc = ", event.Dc)
})
fireSwitchDcEventType.Subscribe(world, func(w ecs.World, event FireSwitchDcEvent) {
fmt.Println("==>>2 触发道岔定操事件 : dc = ", event.Dc)
})
//
time.Sleep(3 * time.Second)
//
fireSwitchDcEventType.Publish(world, &FireSwitchDcEvent{Dc: true})
fireSwitchDcEventType.Publish(world, &FireSwitchDcEvent{Dc: false})
time.Sleep(30 * time.Second)
}

View File

@ -1,9 +1,11 @@
package ecs package ecs
import ( import (
"bytes"
"fmt" "fmt"
"log" "log"
"reflect" "runtime"
"strconv"
"time" "time"
"github.com/yohamta/donburi" "github.com/yohamta/donburi"
@ -47,16 +49,19 @@ type World interface {
Close() Close()
Tick() int Tick() int
Running() bool Running() bool
GoroutineId() uint64
} }
type world struct { type world struct {
gId uint64
world donburi.World world donburi.World
systems []ISystem systems []ISystem
state WorldState state WorldState
tick int tick int
speed float64 speed float64
quit chan struct{} quit chan struct{}
chanManageEvent chan ManageEventFunc
} }
func NewComponentType[T any](opts ...interface{}) *ComponentType[T] { func NewComponentType[T any](opts ...interface{}) *ComponentType[T] {
@ -66,14 +71,18 @@ func NewComponentType[T any](opts ...interface{}) *ComponentType[T] {
func NewWorld(tick int) World { func NewWorld(tick int) World {
return &world{ return &world{
world: donburi.NewWorld(), world: donburi.NewWorld(),
systems: make([]ISystem, 0), systems: make([]ISystem, 0),
state: Init, state: Init,
tick: tick, tick: tick,
speed: 1, speed: 1,
quit: make(chan struct{}), quit: make(chan struct{}),
chanManageEvent: make(chan ManageEventFunc, 1024),
} }
} }
func (w *world) GoroutineId() uint64 {
return w.gId
}
func (w *world) Running() bool { func (w *world) Running() bool {
return w.state == Running return w.state == Running
} }
@ -165,7 +174,29 @@ func (w *world) Close() {
w.quit <- struct{}{} 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() { func (w *world) run() {
w.gId = currentGoId()
for { for {
select { select {
case <-w.quit: // 退出信号 case <-w.quit: // 退出信号
@ -192,10 +223,10 @@ func (w *world) run() {
for _, sys := range w.systems { for _, sys := range w.systems {
sys.Update(w) sys.Update(w)
} }
// 处理事件管理相关
w.processManageEventFuncs()
// 处理所有事件 // 处理所有事件
// w.ProcessAllEvents() processAllEvents(w)
// 执行逻辑花费时间单位ms // 执行逻辑花费时间单位ms
ot := time.Duration(time.Now().Nanosecond() - start.Nanosecond()).Milliseconds() ot := time.Duration(time.Now().Nanosecond() - start.Nanosecond()).Milliseconds()
// 根据间隔和速度计算休眠时间 // 根据间隔和速度计算休眠时间
@ -208,14 +239,15 @@ func (w *world) run() {
} }
} }
func NewEventType[T any](w World) *EventType[T] { // 获取当前协程id
// events.NewEventType() func currentGoId() (gid uint64) {
ct := NewComponentType[T]() b := make([]byte, 16)
var et T b = b[:runtime.Stack(b, false)]
name := reflect.TypeOf(et).Name() b = bytes.TrimPrefix(b, []byte("goroutine "))
return &EventType[T]{ b = b[:bytes.IndexByte(b, ' ')]
name, n, err := strconv.ParseUint(string(b), 10, 64)
ct, if err != nil {
w, panic(err)
} }
return n
} }