aoi.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. package aoiGrid
  2. import (
  3. //"f1-game/internal/algorithm/aoi"
  4. "f1-game/internal/types"
  5. "math"
  6. clog "github.com/cherry-game/cherry/logger"
  7. )
  8. type (
  9. Config struct {
  10. Width int32 // 地图宽(x)
  11. Height int32 // 地图高(y)
  12. GridWidth int32 // 网格宽(x)
  13. GridHeight int32 // 网格高(y)
  14. }
  15. AOI struct {
  16. EventBase
  17. config Config
  18. gridNumX int32 // x轴的格子数量
  19. gridNumY int32 // y轴的格子数量
  20. grids map[int32]*Grid // 所有格子数 key:id,value:*Grid
  21. objects Objects // 所有对象 key:ObjectID, value:*aoi.Object
  22. }
  23. )
  24. func New(config Config) *AOI {
  25. gridAOI := &AOI{
  26. EventBase: EventBase{},
  27. config: config,
  28. grids: make(map[int32]*Grid),
  29. objects: Objects{},
  30. }
  31. gridAOI.init()
  32. return gridAOI
  33. }
  34. func (p *AOI) init() {
  35. if p.config.Width < 1 || p.config.Height < 1 {
  36. clog.Panicf("Config params error. %v", p)
  37. }
  38. if p.config.GridWidth < 1 /*|| p.config.GridWidth > p.config.Width*/ {
  39. clog.Panicf("Config params error. %v", p)
  40. }
  41. if p.config.GridHeight < 1 /*|| p.config.GridHeight > p.config.Height*/ {
  42. clog.Panicf("Config params error. %v", p)
  43. }
  44. p.gridNumX = int32(math.Ceil(float64(p.config.Width) / float64(p.config.GridWidth)))
  45. p.gridNumY = int32(math.Ceil(float64(p.config.Height) / float64(p.config.GridHeight)))
  46. for y := range p.gridNumY {
  47. for x := range p.gridNumX {
  48. grid := p.newGrid(x, y)
  49. p.grids[grid.id] = grid
  50. }
  51. }
  52. }
  53. func (p *AOI) Get(objectID int64) *Object {
  54. return p.objects.Get(objectID)
  55. }
  56. func (p *AOI) Enter(object Object) bool {
  57. gridID := p.GetGridID(object.Point.X, object.Point.Y)
  58. grid, found := p.grids[gridID]
  59. if !found {
  60. clog.Warnf("[Enter] gridID not found. %s", object.Info())
  61. return false
  62. }
  63. // add object
  64. p.objects.Add(&object)
  65. if object.IsWatcher() {
  66. grid.AddWatcher(&object)
  67. if p.WatcherEnterFunc != nil {
  68. markers := p.Get9GridMarkers(gridID)
  69. if !markers.IsEmpty() {
  70. p.WatcherEnterFunc(&object, markers)
  71. }
  72. }
  73. }
  74. if object.IsMarker() {
  75. grid.AddMarker(&object)
  76. if p.MarkerEnterFunc != nil {
  77. watchers := p.Get9GridWatchers(gridID)
  78. p.MarkerEnterFunc(&object, watchers)
  79. }
  80. }
  81. return true
  82. }
  83. func (p *AOI) Leave(objectID int64) {
  84. object := p.objects.Get(objectID)
  85. if object == nil {
  86. clog.Warnf("[Leave] objectID = %d not found.", objectID)
  87. return
  88. }
  89. // remove object
  90. p.objects.Remove(objectID)
  91. gridID := p.GetGridID(object.Point.X, object.Point.Y)
  92. grid, found := p.grids[gridID]
  93. if !found {
  94. clog.Warnf("[Leave] gridID not found. %s", object.Info())
  95. return
  96. }
  97. if object.IsWatcher() {
  98. grid.DelWatcher(object)
  99. }
  100. if object.IsMarker() {
  101. grid.DelMarker(object)
  102. if p.MarkerLeaveFunc != nil {
  103. delWatchers := p.Get9GridWatchers(gridID)
  104. if !delWatchers.IsEmpty() {
  105. p.MarkerLeaveFunc(object, delWatchers)
  106. }
  107. }
  108. }
  109. }
  110. func (p *AOI) Move(objectID int64, x, y int32) bool {
  111. object := p.objects.Get(objectID)
  112. if object == nil {
  113. return false
  114. }
  115. if object.Point.X == x && object.Point.Y == y {
  116. return false
  117. }
  118. if !p.CheckPoint(x, y) {
  119. clog.Warnf("[Move] check point error. %s", object.Info())
  120. return false
  121. }
  122. oldGridID := p.GetGridID(object.Point.X, object.Point.Y)
  123. newGridID := p.GetGridID(x, y)
  124. oldMapGrid := p.grids[oldGridID]
  125. newMapGrid := p.grids[newGridID]
  126. if oldMapGrid == nil || newMapGrid == nil {
  127. clog.Warnf("[Move] Get map grid error. %s", object.Info())
  128. return false
  129. }
  130. // set new point
  131. object.SetPoint(x, y)
  132. if object.IsWatcher() {
  133. if oldGridID != newGridID {
  134. oldMapGrid.DelWatcher(object)
  135. newMapGrid.AddWatcher(object)
  136. if p.WatcherMoveFunc != nil {
  137. old9Grids := p.Get9Grids(oldGridID)
  138. new9Grids := p.Get9Grids(newGridID)
  139. addMarkers, _ := p.GetDiffMarkers(old9Grids, new9Grids)
  140. if !addMarkers.IsEmpty() {
  141. p.WatcherMoveFunc(object, addMarkers)
  142. }
  143. }
  144. }
  145. }
  146. if object.IsMarker() {
  147. if oldGridID != newGridID {
  148. oldMapGrid.DelMarker(object)
  149. newMapGrid.AddMarker(object)
  150. }
  151. if p.MarkerMoveFunc != nil {
  152. viewWatchers := p.Get9GridWatchers(newGridID)
  153. if !viewWatchers.IsEmpty() {
  154. p.MarkerMoveFunc(object, viewWatchers)
  155. }
  156. }
  157. }
  158. return true
  159. }
  160. func (p *AOI) GetWatcherOwners(objectID int64) types.Set[int64] {
  161. owners := types.NewSet[int64]()
  162. object := p.objects.Get(objectID)
  163. if object == nil {
  164. return owners
  165. }
  166. if object.IsWatcher() {
  167. clog.Warnf("[GetWatchers] objectID = {%s} is a watcher. get fail.%s", object.Info())
  168. return owners
  169. }
  170. gridID := p.GetGridID(object.Point.X, object.Point.Y)
  171. mapGrid := p.grids[gridID]
  172. if mapGrid == nil {
  173. clog.Warnf("[GetWatchers] objectID = {%s}, old tower not found. %s", object.Info())
  174. return owners
  175. }
  176. for _, watcher := range mapGrid.watchers {
  177. owners.Add(watcher.OwnerID())
  178. }
  179. return owners
  180. }
  181. func (p *AOI) newGrid(x, y int32) *Grid {
  182. var (
  183. id = y*p.gridNumX + x // 0开头
  184. minX = x * p.config.GridWidth
  185. minY = y * p.config.GridHeight
  186. maxX = (x + 1) * p.config.GridWidth
  187. maxY = (y + 1) * p.config.GridHeight
  188. )
  189. grid := &Grid{
  190. id: id,
  191. minX: minX,
  192. minY: minY,
  193. maxX: maxX,
  194. maxY: maxY,
  195. markers: Objects{},
  196. watchers: Objects{},
  197. }
  198. return grid
  199. }
  200. func (p *AOI) GetGridID(x, y int32) int32 {
  201. if x >= p.config.Width {
  202. x = x - 1
  203. }
  204. if y >= p.config.Height {
  205. y = y - 1
  206. }
  207. // y / 格子高度 * x轴格子数量 + x / y轴格子数量
  208. return y/p.config.GridHeight*p.gridNumX + x/p.gridNumY
  209. }
  210. func (p *AOI) GetDiffMarkers(oldGrids MapGrid, newGrids MapGrid) (addObjects, delObjects Objects) {
  211. bothGridIDMap := map[int32]struct{}{}
  212. for _, newGrid := range newGrids {
  213. if !oldGrids.Contains(newGrid) {
  214. addObjects.Adds(newGrid.markers)
  215. } else {
  216. bothGridIDMap[newGrid.id] = struct{}{}
  217. }
  218. }
  219. for _, oldGrid := range oldGrids {
  220. if _, ok := bothGridIDMap[oldGrid.id]; !ok {
  221. delObjects.Adds(oldGrid.markers)
  222. }
  223. }
  224. return
  225. }
  226. func (p *AOI) Get9GridMarkers(gridID int32) Objects {
  227. return p.get9GridObjects(gridID, true)
  228. }
  229. func (p *AOI) Get9GridWatchers(gridID int32) Objects {
  230. return p.get9GridObjects(gridID, false)
  231. }
  232. func (p *AOI) get9GridObjects(gridID int32, getMarker bool) Objects {
  233. var (
  234. grids = p.Get9Grids(gridID)
  235. retObjects = Objects{}
  236. )
  237. for _, grid := range grids {
  238. if getMarker {
  239. retObjects.Adds(grid.markers)
  240. } else {
  241. retObjects.Adds(grid.watchers)
  242. }
  243. }
  244. return retObjects
  245. }
  246. func (p *AOI) Get9Grids(gridID int32) MapGrid {
  247. var (
  248. mapGrid = make(MapGrid, 9)
  249. ix = gridID % p.gridNumX
  250. iy = gridID / p.gridNumX
  251. )
  252. // 中心格子
  253. mapGrid.Add(p.grids[gridID])
  254. // 左
  255. if ix-1 >= 0 {
  256. mapGrid.Add(p.grids[gridID-1])
  257. if iy-1 >= 0 {
  258. mapGrid.Add(p.grids[gridID-1-p.gridNumX])
  259. }
  260. if iy+1 < p.gridNumY {
  261. mapGrid.Add(p.grids[gridID-1+p.gridNumX])
  262. }
  263. }
  264. // 右
  265. if ix+1 < p.gridNumX {
  266. mapGrid.Add(p.grids[gridID+1])
  267. if iy-1 >= 0 {
  268. mapGrid.Add(p.grids[gridID+1-p.gridNumX])
  269. }
  270. if iy+1 < p.gridNumY {
  271. mapGrid.Add(p.grids[gridID+1+p.gridNumX])
  272. }
  273. }
  274. // 下
  275. if iy-1 >= 0 {
  276. mapGrid.Add(p.grids[gridID-p.gridNumX])
  277. }
  278. // 上
  279. if iy+1 < p.gridNumY {
  280. mapGrid.Add(p.grids[gridID+p.gridNumX])
  281. }
  282. return mapGrid
  283. }
  284. // CheckPoint 坐标是否合法
  285. func (p *AOI) CheckPoint(x, y int32) bool {
  286. return x >= 0 && y >= 0 && x < p.config.Width && y < p.config.Height
  287. }