| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- package aoiGrid
- import (
- //"f1-game/internal/algorithm/aoi"
- "f1-game/internal/types"
- "math"
- clog "github.com/cherry-game/cherry/logger"
- )
- type (
- Config struct {
- Width int32 // 地图宽(x)
- Height int32 // 地图高(y)
- GridWidth int32 // 网格宽(x)
- GridHeight int32 // 网格高(y)
- }
- AOI struct {
- EventBase
- config Config
- gridNumX int32 // x轴的格子数量
- gridNumY int32 // y轴的格子数量
- grids map[int32]*Grid // 所有格子数 key:id,value:*Grid
- objects Objects // 所有对象 key:ObjectID, value:*aoi.Object
- }
- )
- func New(config Config) *AOI {
- gridAOI := &AOI{
- EventBase: EventBase{},
- config: config,
- grids: make(map[int32]*Grid),
- objects: Objects{},
- }
- gridAOI.init()
- return gridAOI
- }
- func (p *AOI) init() {
- if p.config.Width < 1 || p.config.Height < 1 {
- clog.Panicf("Config params error. %v", p)
- }
- if p.config.GridWidth < 1 /*|| p.config.GridWidth > p.config.Width*/ {
- clog.Panicf("Config params error. %v", p)
- }
- if p.config.GridHeight < 1 /*|| p.config.GridHeight > p.config.Height*/ {
- clog.Panicf("Config params error. %v", p)
- }
- p.gridNumX = int32(math.Ceil(float64(p.config.Width) / float64(p.config.GridWidth)))
- p.gridNumY = int32(math.Ceil(float64(p.config.Height) / float64(p.config.GridHeight)))
- for y := range p.gridNumY {
- for x := range p.gridNumX {
- grid := p.newGrid(x, y)
- p.grids[grid.id] = grid
- }
- }
- }
- func (p *AOI) Get(objectID int64) *Object {
- return p.objects.Get(objectID)
- }
- func (p *AOI) Enter(object Object) bool {
- gridID := p.GetGridID(object.Point.X, object.Point.Y)
- grid, found := p.grids[gridID]
- if !found {
- clog.Warnf("[Enter] gridID not found. %s", object.Info())
- return false
- }
- // add object
- p.objects.Add(&object)
- if object.IsWatcher() {
- grid.AddWatcher(&object)
- if p.WatcherEnterFunc != nil {
- markers := p.Get9GridMarkers(gridID)
- if !markers.IsEmpty() {
- p.WatcherEnterFunc(&object, markers)
- }
- }
- }
- if object.IsMarker() {
- grid.AddMarker(&object)
- if p.MarkerEnterFunc != nil {
- watchers := p.Get9GridWatchers(gridID)
- p.MarkerEnterFunc(&object, watchers)
- }
- }
- return true
- }
- func (p *AOI) Leave(objectID int64) {
- object := p.objects.Get(objectID)
- if object == nil {
- clog.Warnf("[Leave] objectID = %d not found.", objectID)
- return
- }
- // remove object
- p.objects.Remove(objectID)
- gridID := p.GetGridID(object.Point.X, object.Point.Y)
- grid, found := p.grids[gridID]
- if !found {
- clog.Warnf("[Leave] gridID not found. %s", object.Info())
- return
- }
- if object.IsWatcher() {
- grid.DelWatcher(object)
- }
- if object.IsMarker() {
- grid.DelMarker(object)
- if p.MarkerLeaveFunc != nil {
- delWatchers := p.Get9GridWatchers(gridID)
- if !delWatchers.IsEmpty() {
- p.MarkerLeaveFunc(object, delWatchers)
- }
- }
- }
- }
- func (p *AOI) Move(objectID int64, x, y int32) bool {
- object := p.objects.Get(objectID)
- if object == nil {
- return false
- }
- if object.Point.X == x && object.Point.Y == y {
- return false
- }
- if !p.CheckPoint(x, y) {
- clog.Warnf("[Move] check point error. %s", object.Info())
- return false
- }
- oldGridID := p.GetGridID(object.Point.X, object.Point.Y)
- newGridID := p.GetGridID(x, y)
- oldMapGrid := p.grids[oldGridID]
- newMapGrid := p.grids[newGridID]
- if oldMapGrid == nil || newMapGrid == nil {
- clog.Warnf("[Move] Get map grid error. %s", object.Info())
- return false
- }
- // set new point
- object.SetPoint(x, y)
- if object.IsWatcher() {
- if oldGridID != newGridID {
- oldMapGrid.DelWatcher(object)
- newMapGrid.AddWatcher(object)
- if p.WatcherMoveFunc != nil {
- old9Grids := p.Get9Grids(oldGridID)
- new9Grids := p.Get9Grids(newGridID)
- addMarkers, _ := p.GetDiffMarkers(old9Grids, new9Grids)
- if !addMarkers.IsEmpty() {
- p.WatcherMoveFunc(object, addMarkers)
- }
- }
- }
- }
- if object.IsMarker() {
- if oldGridID != newGridID {
- oldMapGrid.DelMarker(object)
- newMapGrid.AddMarker(object)
- }
- if p.MarkerMoveFunc != nil {
- viewWatchers := p.Get9GridWatchers(newGridID)
- if !viewWatchers.IsEmpty() {
- p.MarkerMoveFunc(object, viewWatchers)
- }
- }
- }
- return true
- }
- func (p *AOI) GetWatcherOwners(objectID int64) types.Set[int64] {
- owners := types.NewSet[int64]()
- object := p.objects.Get(objectID)
- if object == nil {
- return owners
- }
- if object.IsWatcher() {
- clog.Warnf("[GetWatchers] objectID = {%s} is a watcher. get fail.%s", object.Info())
- return owners
- }
- gridID := p.GetGridID(object.Point.X, object.Point.Y)
- mapGrid := p.grids[gridID]
- if mapGrid == nil {
- clog.Warnf("[GetWatchers] objectID = {%s}, old tower not found. %s", object.Info())
- return owners
- }
- for _, watcher := range mapGrid.watchers {
- owners.Add(watcher.OwnerID())
- }
- return owners
- }
- func (p *AOI) newGrid(x, y int32) *Grid {
- var (
- id = y*p.gridNumX + x // 0开头
- minX = x * p.config.GridWidth
- minY = y * p.config.GridHeight
- maxX = (x + 1) * p.config.GridWidth
- maxY = (y + 1) * p.config.GridHeight
- )
- grid := &Grid{
- id: id,
- minX: minX,
- minY: minY,
- maxX: maxX,
- maxY: maxY,
- markers: Objects{},
- watchers: Objects{},
- }
- return grid
- }
- func (p *AOI) GetGridID(x, y int32) int32 {
- if x >= p.config.Width {
- x = x - 1
- }
- if y >= p.config.Height {
- y = y - 1
- }
- // y / 格子高度 * x轴格子数量 + x / y轴格子数量
- return y/p.config.GridHeight*p.gridNumX + x/p.gridNumY
- }
- func (p *AOI) GetDiffMarkers(oldGrids MapGrid, newGrids MapGrid) (addObjects, delObjects Objects) {
- bothGridIDMap := map[int32]struct{}{}
- for _, newGrid := range newGrids {
- if !oldGrids.Contains(newGrid) {
- addObjects.Adds(newGrid.markers)
- } else {
- bothGridIDMap[newGrid.id] = struct{}{}
- }
- }
- for _, oldGrid := range oldGrids {
- if _, ok := bothGridIDMap[oldGrid.id]; !ok {
- delObjects.Adds(oldGrid.markers)
- }
- }
- return
- }
- func (p *AOI) Get9GridMarkers(gridID int32) Objects {
- return p.get9GridObjects(gridID, true)
- }
- func (p *AOI) Get9GridWatchers(gridID int32) Objects {
- return p.get9GridObjects(gridID, false)
- }
- func (p *AOI) get9GridObjects(gridID int32, getMarker bool) Objects {
- var (
- grids = p.Get9Grids(gridID)
- retObjects = Objects{}
- )
- for _, grid := range grids {
- if getMarker {
- retObjects.Adds(grid.markers)
- } else {
- retObjects.Adds(grid.watchers)
- }
- }
- return retObjects
- }
- func (p *AOI) Get9Grids(gridID int32) MapGrid {
- var (
- mapGrid = make(MapGrid, 9)
- ix = gridID % p.gridNumX
- iy = gridID / p.gridNumX
- )
- // 中心格子
- mapGrid.Add(p.grids[gridID])
- // 左
- if ix-1 >= 0 {
- mapGrid.Add(p.grids[gridID-1])
- if iy-1 >= 0 {
- mapGrid.Add(p.grids[gridID-1-p.gridNumX])
- }
- if iy+1 < p.gridNumY {
- mapGrid.Add(p.grids[gridID-1+p.gridNumX])
- }
- }
- // 右
- if ix+1 < p.gridNumX {
- mapGrid.Add(p.grids[gridID+1])
- if iy-1 >= 0 {
- mapGrid.Add(p.grids[gridID+1-p.gridNumX])
- }
- if iy+1 < p.gridNumY {
- mapGrid.Add(p.grids[gridID+1+p.gridNumX])
- }
- }
- // 下
- if iy-1 >= 0 {
- mapGrid.Add(p.grids[gridID-p.gridNumX])
- }
- // 上
- if iy+1 < p.gridNumY {
- mapGrid.Add(p.grids[gridID+p.gridNumX])
- }
- return mapGrid
- }
- // CheckPoint 坐标是否合法
- func (p *AOI) CheckPoint(x, y int32) bool {
- return x >= 0 && y >= 0 && x < p.config.Width && y < p.config.Height
- }
|