ecs添加事件处理
This commit is contained in:
parent
8ffea356da
commit
0cdbe6fdd0
105
events.go
105
events.go
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
72
world.go
72
world.go
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue