refactor: 从 builtin 包中单独抽离到 aoi 包,更名为 TwoDimensional
This commit is contained in:
parent
c8f181f63e
commit
bca8a98463
|
@ -1,24 +1,25 @@
|
|||
package builtin
|
||||
package aoi
|
||||
|
||||
import (
|
||||
"github.com/kercylan98/minotaur/game"
|
||||
"github.com/kercylan98/minotaur/utils/geometry"
|
||||
"github.com/kercylan98/minotaur/utils/hash"
|
||||
"math"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func NewAOI2D(width, height, areaWidth, areaHeight int) *AOI2D {
|
||||
aoi := &AOI2D{
|
||||
func NewTwoDimensional[E TwoDimensionalEntity](width, height, areaWidth, areaHeight int) *TwoDimensional[E] {
|
||||
aoi := &TwoDimensional[E]{
|
||||
event: new(event[E]),
|
||||
width: float64(width),
|
||||
height: float64(height),
|
||||
focus: map[int64]map[int64]game.AOIEntity2D{},
|
||||
focus: map[int64]map[int64]E{},
|
||||
}
|
||||
aoi.SetAreaSize(areaWidth, areaHeight)
|
||||
return aoi
|
||||
}
|
||||
|
||||
type AOI2D struct {
|
||||
type TwoDimensional[E TwoDimensionalEntity] struct {
|
||||
*event[E]
|
||||
rw sync.RWMutex
|
||||
width float64
|
||||
height float64
|
||||
|
@ -26,39 +27,36 @@ type AOI2D struct {
|
|||
areaHeight float64
|
||||
areaWidthLimit int
|
||||
areaHeightLimit int
|
||||
areas [][]map[int64]game.AOIEntity2D
|
||||
focus map[int64]map[int64]game.AOIEntity2D
|
||||
areas [][]map[int64]E
|
||||
focus map[int64]map[int64]E
|
||||
repartitionQueue []func()
|
||||
|
||||
entityJoinVisionEventHandles []game.EntityJoinVisionEventHandle
|
||||
entityLeaveVisionEventHandles []game.EntityLeaveVisionEventHandle
|
||||
}
|
||||
|
||||
func (slf *AOI2D) AddEntity(entity game.AOIEntity2D) {
|
||||
func (slf *TwoDimensional[E]) AddEntity(entity E) {
|
||||
slf.rw.Lock()
|
||||
slf.addEntity(entity)
|
||||
slf.rw.Unlock()
|
||||
}
|
||||
|
||||
func (slf *AOI2D) DeleteEntity(entity game.AOIEntity2D) {
|
||||
func (slf *TwoDimensional[E]) DeleteEntity(entity E) {
|
||||
slf.rw.Lock()
|
||||
slf.deleteEntity(entity)
|
||||
slf.rw.Unlock()
|
||||
}
|
||||
|
||||
func (slf *AOI2D) Refresh(entity game.AOIEntity2D) {
|
||||
func (slf *TwoDimensional[E]) Refresh(entity E) {
|
||||
slf.rw.Lock()
|
||||
defer slf.rw.Unlock()
|
||||
slf.refresh(entity)
|
||||
}
|
||||
|
||||
func (slf *AOI2D) GetFocus(guid int64) map[int64]game.AOIEntity2D {
|
||||
func (slf *TwoDimensional[E]) GetFocus(guid int64) map[int64]E {
|
||||
slf.rw.RLock()
|
||||
defer slf.rw.RUnlock()
|
||||
return hash.Copy(slf.focus[guid])
|
||||
}
|
||||
|
||||
func (slf *AOI2D) SetSize(width, height int) {
|
||||
func (slf *TwoDimensional[E]) SetSize(width, height int) {
|
||||
fw, fh := float64(width), float64(height)
|
||||
if fw == slf.width && fh == slf.height {
|
||||
return
|
||||
|
@ -70,7 +68,7 @@ func (slf *AOI2D) SetSize(width, height int) {
|
|||
slf.setAreaSize(int(slf.areaWidth), int(slf.areaHeight))
|
||||
}
|
||||
|
||||
func (slf *AOI2D) SetAreaSize(width, height int) {
|
||||
func (slf *TwoDimensional[E]) SetAreaSize(width, height int) {
|
||||
fw, fh := float64(width), float64(height)
|
||||
if fw == slf.areaWidth && fh == slf.areaHeight {
|
||||
return
|
||||
|
@ -80,35 +78,15 @@ func (slf *AOI2D) SetAreaSize(width, height int) {
|
|||
slf.setAreaSize(width, height)
|
||||
}
|
||||
|
||||
func (slf *AOI2D) RegEntityJoinVisionEvent(handle game.EntityJoinVisionEventHandle) {
|
||||
slf.entityJoinVisionEventHandles = append(slf.entityJoinVisionEventHandles, handle)
|
||||
}
|
||||
|
||||
func (slf *AOI2D) OnEntityJoinVisionEvent(entity, target game.AOIEntity2D) {
|
||||
for _, handle := range slf.entityJoinVisionEventHandles {
|
||||
handle(entity, target)
|
||||
}
|
||||
}
|
||||
|
||||
func (slf *AOI2D) RegEntityLeaveVisionEvent(handle game.EntityLeaveVisionEventHandle) {
|
||||
slf.entityLeaveVisionEventHandles = append(slf.entityLeaveVisionEventHandles, handle)
|
||||
}
|
||||
|
||||
func (slf *AOI2D) OnEntityLeaveVisionEvent(entity, target game.AOIEntity2D) {
|
||||
for _, handle := range slf.entityLeaveVisionEventHandles {
|
||||
handle(entity, target)
|
||||
}
|
||||
}
|
||||
|
||||
func (slf *AOI2D) setAreaSize(width, height int) {
|
||||
func (slf *TwoDimensional[E]) setAreaSize(width, height int) {
|
||||
|
||||
// 旧分区备份
|
||||
var oldAreas = make([][]map[int64]game.AOIEntity2D, len(slf.areas))
|
||||
var oldAreas = make([][]map[int64]E, len(slf.areas))
|
||||
for w := 0; w < len(slf.areas); w++ {
|
||||
hs := slf.areas[w]
|
||||
ohs := make([]map[int64]game.AOIEntity2D, len(hs))
|
||||
ohs := make([]map[int64]E, len(hs))
|
||||
for h := 0; h < len(hs); h++ {
|
||||
es := map[int64]game.AOIEntity2D{}
|
||||
es := map[int64]E{}
|
||||
for g, e := range hs[h] {
|
||||
es[g] = e
|
||||
}
|
||||
|
@ -133,11 +111,11 @@ func (slf *AOI2D) setAreaSize(width, height int) {
|
|||
slf.areaHeight = float64(height)
|
||||
slf.areaWidthLimit = int(math.Ceil(slf.width / slf.areaWidth))
|
||||
slf.areaHeightLimit = int(math.Ceil(slf.height / slf.areaHeight))
|
||||
areas := make([][]map[int64]game.AOIEntity2D, slf.areaWidthLimit+1)
|
||||
areas := make([][]map[int64]E, slf.areaWidthLimit+1)
|
||||
for i := 0; i < len(areas); i++ {
|
||||
entities := make([]map[int64]game.AOIEntity2D, slf.areaHeightLimit+1)
|
||||
entities := make([]map[int64]E, slf.areaHeightLimit+1)
|
||||
for e := 0; e < len(entities); e++ {
|
||||
entities[e] = map[int64]game.AOIEntity2D{}
|
||||
entities[e] = map[int64]E{}
|
||||
}
|
||||
areas[i] = entities
|
||||
}
|
||||
|
@ -155,22 +133,22 @@ func (slf *AOI2D) setAreaSize(width, height int) {
|
|||
}
|
||||
}
|
||||
|
||||
func (slf *AOI2D) addEntity(entity game.AOIEntity2D) {
|
||||
func (slf *TwoDimensional[E]) addEntity(entity E) {
|
||||
x, y := entity.GetPosition()
|
||||
widthArea := int(x / slf.areaWidth)
|
||||
heightArea := int(y / slf.areaHeight)
|
||||
guid := entity.GetGuid()
|
||||
slf.areas[widthArea][heightArea][guid] = entity
|
||||
focus := map[int64]game.AOIEntity2D{}
|
||||
focus := map[int64]E{}
|
||||
slf.focus[guid] = focus
|
||||
slf.rangeVisionAreaEntities(entity, func(eg int64, e game.AOIEntity2D) {
|
||||
slf.rangeVisionAreaEntities(entity, func(eg int64, e E) {
|
||||
focus[eg] = e
|
||||
slf.OnEntityJoinVisionEvent(entity, e)
|
||||
slf.refresh(e)
|
||||
})
|
||||
}
|
||||
|
||||
func (slf *AOI2D) refresh(entity game.AOIEntity2D) {
|
||||
func (slf *TwoDimensional[E]) refresh(entity E) {
|
||||
x, y := entity.GetPosition()
|
||||
vision := entity.GetVision()
|
||||
guid := entity.GetGuid()
|
||||
|
@ -183,7 +161,7 @@ func (slf *AOI2D) refresh(entity game.AOIEntity2D) {
|
|||
}
|
||||
}
|
||||
|
||||
slf.rangeVisionAreaEntities(entity, func(guid int64, e game.AOIEntity2D) {
|
||||
slf.rangeVisionAreaEntities(entity, func(guid int64, e E) {
|
||||
if _, exist := focus[guid]; !exist {
|
||||
focus[guid] = e
|
||||
slf.OnEntityJoinVisionEvent(entity, e)
|
||||
|
@ -191,7 +169,7 @@ func (slf *AOI2D) refresh(entity game.AOIEntity2D) {
|
|||
})
|
||||
}
|
||||
|
||||
func (slf *AOI2D) rangeVisionAreaEntities(entity game.AOIEntity2D, handle func(guid int64, entity game.AOIEntity2D)) {
|
||||
func (slf *TwoDimensional[E]) rangeVisionAreaEntities(entity E, handle func(guid int64, entity E)) {
|
||||
x, y := entity.GetPosition()
|
||||
widthArea := int(x / slf.areaWidth)
|
||||
heightArea := int(y / slf.areaHeight)
|
||||
|
@ -259,7 +237,7 @@ func (slf *AOI2D) rangeVisionAreaEntities(entity game.AOIEntity2D, handle func(g
|
|||
}
|
||||
}
|
||||
|
||||
func (slf *AOI2D) deleteEntity(entity game.AOIEntity2D) {
|
||||
func (slf *TwoDimensional[E]) deleteEntity(entity E) {
|
||||
x, y := entity.GetPosition()
|
||||
widthArea := int(x / slf.areaWidth)
|
||||
heightArea := int(y / slf.areaHeight)
|
|
@ -0,0 +1,12 @@
|
|||
package aoi
|
||||
|
||||
import "github.com/kercylan98/minotaur/game"
|
||||
|
||||
// TwoDimensionalEntity 基于2D定义的AOI对象功能接口
|
||||
// - AOI 对象提供了 AOI 系统中常用的属性,诸如位置坐标和视野范围等
|
||||
type TwoDimensionalEntity interface {
|
||||
game.Actor
|
||||
game.Position2D
|
||||
// GetVision 获取视距
|
||||
GetVision() float64
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package aoi
|
||||
|
||||
type (
|
||||
EntityJoinVisionEventHandle[E TwoDimensionalEntity] func(entity, target E)
|
||||
EntityLeaveVisionEventHandle[E TwoDimensionalEntity] func(entity, target E)
|
||||
)
|
||||
|
||||
type event[E TwoDimensionalEntity] struct {
|
||||
entityJoinVisionEventHandles []EntityJoinVisionEventHandle[E]
|
||||
entityLeaveVisionEventHandles []EntityLeaveVisionEventHandle[E]
|
||||
}
|
||||
|
||||
// RegEntityJoinVisionEvent 在新对象进入视野时将会立刻执行被注册的事件处理函数
|
||||
func (slf *event[E]) RegEntityJoinVisionEvent(handle EntityJoinVisionEventHandle[E]) {
|
||||
slf.entityJoinVisionEventHandles = append(slf.entityJoinVisionEventHandles, handle)
|
||||
}
|
||||
|
||||
// OnEntityJoinVisionEvent 在新对象进入视野时将会立刻执行被注册的事件处理函数
|
||||
func (slf *event[E]) OnEntityJoinVisionEvent(entity, target E) {
|
||||
for _, handle := range slf.entityJoinVisionEventHandles {
|
||||
handle(entity, target)
|
||||
}
|
||||
}
|
||||
|
||||
// RegEntityLeaveVisionEvent 在新对象离开视野时将会立刻执行被注册的事件处理函数
|
||||
func (slf *event[E]) RegEntityLeaveVisionEvent(handle EntityLeaveVisionEventHandle[E]) {
|
||||
slf.entityLeaveVisionEventHandles = append(slf.entityLeaveVisionEventHandles, handle)
|
||||
}
|
||||
|
||||
// OnEntityLeaveVisionEvent 在新对象离开视野时将会立刻执行被注册的事件处理函数
|
||||
func (slf *event[E]) OnEntityLeaveVisionEvent(entity, target E) {
|
||||
for _, handle := range slf.entityLeaveVisionEventHandles {
|
||||
handle(entity, target)
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
package builtin_test
|
||||
package aoi_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kercylan98/minotaur/game/builtin"
|
||||
"github.com/kercylan98/minotaur/game/aoi"
|
||||
"github.com/kercylan98/minotaur/utils/random"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -29,12 +29,12 @@ func (slf *Ent) GetVision() float64 {
|
|||
return slf.vision
|
||||
}
|
||||
|
||||
func TestNewAOI2D(t *testing.T) {
|
||||
aoi := builtin.NewAOI2D(10000, 10000, 100, 100)
|
||||
func TestNewTwoDimensional(t *testing.T) {
|
||||
aoiTW := aoi.NewTwoDimensional[*Ent](10000, 10000, 100, 100)
|
||||
|
||||
start := time.Now()
|
||||
for i := 0; i < 50000; i++ {
|
||||
aoi.AddEntity(&Ent{
|
||||
aoiTW.AddEntity(&Ent{
|
||||
guid: int64(i),
|
||||
x: float64(random.Int(0, 10000)),
|
||||
y: float64(random.Int(0, 10000)),
|
||||
|
@ -44,9 +44,9 @@ func TestNewAOI2D(t *testing.T) {
|
|||
fmt.Println("添加耗时:", time.Since(start))
|
||||
|
||||
//start = time.Now()
|
||||
//aoi.SetAreaSize(1000, 1000)
|
||||
//aoiTW.SetAreaSize(1000, 1000)
|
||||
//fmt.Println("重设区域大小耗时:", time.Since(start))
|
||||
start = time.Now()
|
||||
aoi.SetSize(10100, 10100)
|
||||
aoiTW.SetSize(10100, 10100)
|
||||
fmt.Println("重设大小耗时:", time.Since(start))
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package game
|
||||
|
||||
// AOI2D 基于2D定义的AOI功能接口
|
||||
// - AOI(Area Of Interest)翻译过来叫感兴趣的区域,是大型多人在线的游戏服务器中一个非常重要的基础模块,用于游戏对象在场景中的视野管理
|
||||
// - 透过 AOI 系统可以在其他玩家或怪物进入视野时得到感知,从而进行相应处理
|
||||
// - 内置实现:builtin.AOI2D
|
||||
// - 构建函数:builtin.NewAOI2D
|
||||
type AOI2D interface {
|
||||
// AddEntity 添加对象
|
||||
AddEntity(entity AOIEntity2D)
|
||||
// DeleteEntity 移除对象
|
||||
DeleteEntity(entity AOIEntity2D)
|
||||
// Refresh 刷新对象焦点
|
||||
Refresh(entity AOIEntity2D)
|
||||
// GetFocus 获取对象焦点列表
|
||||
GetFocus(guid int64) map[int64]AOIEntity2D
|
||||
// SetSize 设置总区域大小
|
||||
// - 将会导致区域的重新划分
|
||||
SetSize(width, height int)
|
||||
// SetAreaSize 设置区域大小
|
||||
// - 将会导致区域的重新划分
|
||||
SetAreaSize(width, height int)
|
||||
|
||||
// RegEntityJoinVisionEvent 在新对象进入视野时将会立刻执行被注册的事件处理函数
|
||||
RegEntityJoinVisionEvent(handle EntityJoinVisionEventHandle)
|
||||
OnEntityJoinVisionEvent(entity, target AOIEntity2D)
|
||||
// RegEntityLeaveVisionEvent 在对象离开视野时将会立刻执行被注册的事件处理函数
|
||||
RegEntityLeaveVisionEvent(handle EntityLeaveVisionEventHandle)
|
||||
OnEntityLeaveVisionEvent(entity, target AOIEntity2D)
|
||||
}
|
||||
|
||||
type (
|
||||
EntityJoinVisionEventHandle func(entity, target AOIEntity2D)
|
||||
EntityLeaveVisionEventHandle func(entity, target AOIEntity2D)
|
||||
)
|
|
@ -1,10 +0,0 @@
|
|||
package game
|
||||
|
||||
// AOIEntity2D 基于2D定义的AOI对象功能接口
|
||||
// - AOI 对象提供了 AOI 系统中常用的属性,诸如位置坐标和视野范围等
|
||||
type AOIEntity2D interface {
|
||||
Actor
|
||||
Position2D
|
||||
// GetVision 获取视距
|
||||
GetVision() float64
|
||||
}
|
Loading…
Reference in New Issue