mirror of
https://github.com/knight0zh/aoi.git
synced 2026-02-04 08:41:36 +08:00
133 lines
2.9 KiB
Go
133 lines
2.9 KiB
Go
package aoi
|
||
|
||
import "sync"
|
||
|
||
var (
|
||
// 分别将这8个方向的方向向量按顺序写入x, y的分量数组
|
||
dx = []int{-1, -1, -1, 0, 0, 1, 1, 1}
|
||
dy = []int{-1, 0, 1, -1, 1, -1, 0, 1}
|
||
)
|
||
|
||
// Grid 格子
|
||
type Grid struct {
|
||
GID int //格子ID
|
||
Entities sync.Map //当前格子内的实体
|
||
}
|
||
|
||
// GridManger AOI九宫格实现矩形
|
||
type GridManger struct {
|
||
StartX int // X区域左边界坐标
|
||
StartY int // Y区域上边界坐标
|
||
AreaWidth int // 格子宽度(长=宽)
|
||
GridCount int // 格子数量
|
||
grids map[int]*Grid
|
||
pool sync.Pool
|
||
}
|
||
|
||
func NewGrid(gid int) *Grid {
|
||
return &Grid{
|
||
GID: gid,
|
||
}
|
||
}
|
||
|
||
func NewGridManger(startX, startY, areaWidth, gridCount int) AOI {
|
||
manager := &GridManger{
|
||
StartX: startX,
|
||
StartY: startY,
|
||
AreaWidth: areaWidth,
|
||
GridCount: gridCount,
|
||
grids: make(map[int]*Grid),
|
||
}
|
||
manager.pool.New = func() interface{} {
|
||
return make([]*Grid, 0, 9)
|
||
}
|
||
|
||
for y := 0; y < gridCount; y++ {
|
||
for x := 0; x < gridCount; x++ {
|
||
//格子编号:ID = IDy *nx + IDx (利用格子坐标得到格子编号)
|
||
gID := y*gridCount + x
|
||
manager.grids[gID] = NewGrid(gID)
|
||
}
|
||
}
|
||
|
||
return manager
|
||
}
|
||
|
||
func (g *GridManger) gridWidth() int {
|
||
return g.AreaWidth / g.GridCount
|
||
}
|
||
|
||
// getGIDByPos 通过横纵坐标获取对应的格子ID
|
||
func (g *GridManger) getGIDByPos(x, y float64) int {
|
||
gx := (int(x) - g.StartX) / g.gridWidth()
|
||
gy := (int(y) - g.StartY) / g.gridWidth()
|
||
|
||
return gy*g.GridCount + gx
|
||
}
|
||
|
||
// getSurroundGrids 根据格子的gID得到当前周边的九宫格信息
|
||
func (g *GridManger) getSurroundGrids(gID int) []*Grid {
|
||
grids := g.pool.Get().([]*Grid)
|
||
defer func() {
|
||
grids = grids[:0]
|
||
g.pool.Put(grids)
|
||
}()
|
||
|
||
if _, ok := g.grids[gID]; !ok {
|
||
return grids
|
||
}
|
||
grids = append(grids, g.grids[gID])
|
||
// 根据gID, 得到格子所在的坐标
|
||
x, y := gID%g.GridCount, gID/g.GridCount
|
||
|
||
for i := 0; i < 8; i++ {
|
||
newX := x + dx[i]
|
||
newY := y + dy[i]
|
||
|
||
if newX >= 0 && newX < g.GridCount && newY >= 0 && newY < g.GridCount {
|
||
grids = append(grids, g.grids[newY*g.GridCount+newX])
|
||
}
|
||
}
|
||
|
||
return grids
|
||
}
|
||
|
||
func (g *GridManger) Add(x, y float64, key string) {
|
||
entity := entityPool.Get().(*Entity)
|
||
entity.X = x
|
||
entity.Y = y
|
||
entity.Key = key
|
||
|
||
ID := g.getGIDByPos(x, y)
|
||
grid := g.grids[ID]
|
||
grid.Entities.Store(key, entity)
|
||
}
|
||
|
||
func (g *GridManger) Delete(x, y float64, key string) {
|
||
ID := g.getGIDByPos(x, y)
|
||
grid := g.grids[ID]
|
||
|
||
if entity, ok := grid.Entities.Load(key); ok {
|
||
grid.Entities.Delete(key)
|
||
entityPool.Put(entity)
|
||
}
|
||
}
|
||
|
||
func (g *GridManger) Search(x, y float64) []string {
|
||
result := resultPool.Get().([]string)
|
||
defer func() {
|
||
result = result[:0]
|
||
resultPool.Put(result)
|
||
}()
|
||
ID := g.getGIDByPos(x, y)
|
||
grids := g.getSurroundGrids(ID)
|
||
for _, grid := range grids {
|
||
grid.Entities.Range(func(_, value interface{}) bool {
|
||
result = append(result, value.(*Entity).Key)
|
||
return true
|
||
})
|
||
}
|
||
|
||
return result
|
||
}
|