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
type (
EventType[T any] struct {
eventName string
componentType *ComponentType[T]
w World
}
import (
"reflect"
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
import (
"bytes"
"fmt"
"log"
"reflect"
"runtime"
"strconv"
"time"
"github.com/yohamta/donburi"
@ -47,16 +49,19 @@ type World interface {
Close()
Tick() int
Running() bool
GoroutineId() uint64
}
type world struct {
gId uint64
world donburi.World
systems []ISystem
state WorldState
tick int
speed float64
quit chan struct{}
quit chan struct{}
chanManageEvent chan ManageEventFunc
}
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 {
return &world{
world: donburi.NewWorld(),
systems: make([]ISystem, 0),
state: Init,
tick: tick,
speed: 1,
quit: make(chan struct{}),
world: donburi.NewWorld(),
systems: make([]ISystem, 0),
state: Init,
tick: tick,
speed: 1,
quit: make(chan struct{}),
chanManageEvent: make(chan ManageEventFunc, 1024),
}
}
func (w *world) GoroutineId() uint64 {
return w.gId
}
func (w *world) Running() bool {
return w.state == Running
}
@ -165,7 +174,29 @@ 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() {
w.gId = currentGoId()
for {
select {
case <-w.quit: // 退出信号
@ -192,10 +223,10 @@ func (w *world) run() {
for _, sys := range w.systems {
sys.Update(w)
}
// 处理事件管理相关
w.processManageEventFuncs()
// 处理所有事件
// w.ProcessAllEvents()
processAllEvents(w)
// 执行逻辑花费时间单位ms
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] {
// events.NewEventType()
ct := NewComponentType[T]()
var et T
name := reflect.TypeOf(et).Name()
return &EventType[T]{
name,
ct,
w,
// 获取当前协程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)
}
return n
}