返回顶部
首页 > 资讯 > 精选 >Go语言如何实现AOI区域视野管理
  • 881
分享到

Go语言如何实现AOI区域视野管理

2023-07-05 09:07:09 881人浏览 独家记忆
摘要

这篇文章主要介绍“Go语言如何实现AOI区域视野管理”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Go语言如何实现AOI区域视野管理”文章能帮助大家解决问题。优化的思路一般是: 第一个是尽量降低向客

这篇文章主要介绍“Go语言如何实现AOI区域视野管理”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Go语言如何实现AOI区域视野管理”文章能帮助大家解决问题。

优化的思路一般是: 第一个是尽量降低向客户端同步对象的数量,第二个是尽量降低单个对象向客户端同步的数据.

"九宫格"是最常见的视野管理算法了.它的优点在于原理和实现都非常简单.

// AOI 管理器type AOIManager interface {GetWidth() intGetHeight() intOnEnter(obj scene.GameObject, enterPos *geom.Vector2d) boolOnLeave(obj scene.GameObject) boolOnMove(obj scene.GameObject, movePos *geom.Vector2d) boolOnSync()}

一.定义管理器接口

进入区域

离开区域

在区域移动

同步信息

具体实现:

type TowerAOIManager struct {minX, maxX, minY, maxY float64 // 单位 mtowerRange             float64 // 格子大小towers                 [][]towerxTowerNum, yTowerNum   int}

划分格子: 按照实际情况出发,规定格子大小 towerRange. (一般 九个格子的范围需大于屏幕看到的视野范围) 这样才能保证客户端场景物体的生成和消失在玩家屏幕外.不会突然出现.

// 构造结构func NewTowerAOIManager(minX, maxX, minY, maxY float64, towerRange float64) AOIManager {mgr := &TowerAOIManager{minX: minX, maxX: maxX, minY: minY, maxY: maxY, towerRange: towerRange}mgr.init()return mgr}func (m *TowerAOIManager) init() {numXSlots := int((m.maxX-m.minX)/m.towerRange) + 1m.xTowerNum = numXSlotsnumYSlots := int((m.maxY-m.minY)/m.towerRange) + 1m.yTowerNum = numYSlotsm.towers = make([][]tower, numXSlots)for i := 0; i < numXSlots; i++ {m.towers[i] = make([]tower, numYSlots)for j := 0; j < numYSlots; j++ {key := NewKey(int64(i), int64(j))m.towers[i][j].init(int64(key))}}}

二.定义区域tower

type tower struct {towerId       int64context       *TowerSyncContextmapid2Obj     map[uint32]scene.GameObject // obj容器mapId2Watcher map[uint32]scene.GameObject // 观察集合}
func (t *tower) init(key int64) {t.towerId = keyt.context = NewTowerSyncContext() // 同步信息t.mapId2Obj = make(map[uint32]scene.GameObject)t.mapId2Watcher = make(map[uint32]scene.GameObject)}
func (t *tower) AddObj(obj scene.GameObject, fromOtherTower scene.AOITower, bExclude bool) {obj.SetAOITower(t)t.mapId2Obj[obj.GetId()] = objif fromOtherTower == nil {for watcherId, watcher := range t.mapId2Watcher {if bExclude && watcherId == obj.GetId() {continue}watcher.OnEnterAOI(obj)}} else {// obj moved from other tower to this towerfor watcherId, watcher := range fromOtherTower.GetWatchers() {if watcherId == obj.GetId() {continue}if _, ok := t.mapId2Watcher[watcherId]; ok {continue}watcher.OnLeaveAOI(obj)}for watcherId, watcher := range t.mapId2Watcher {if watcherId == obj.GetId() {continue}if _, ok := fromOtherTower.GetWatchers()[watcherId]; ok {continue}watcher.OnEnterAOI(obj)}}}func (t *tower) RemoveObj(obj scene.GameObject, notifyWatchers bool) {obj.SetAOITower(nil)delete(t.mapId2Obj, obj.GetId())if notifyWatchers {for watcherId, watcher := range t.mapId2Watcher {if watcherId == obj.GetId() {continue}watcher.OnLeaveAOI(obj)}}}func (t *tower) addWatcher(obj scene.GameObject, bExclude bool) {if bExclude {if _, ok := t.mapId2Watcher[obj.GetId()]; ok {// todo logreturn}}t.mapId2Watcher[obj.GetId()] = obj// now obj can see all objs under this towerfor neighborId, neighbor := range t.mapId2Obj {if neighborId == obj.GetId() {continue}obj.OnEnterAOI(neighbor)}}func (t *tower) removeWatcher(obj scene.GameObject) {if _, ok := t.mapId2Watcher[obj.GetId()]; !ok {// todo logreturn}delete(t.mapId2Watcher, obj.GetId())for neighborId, neighbor := range t.mapId2Obj {if neighborId == obj.GetId() {continue}obj.OnLeaveAOI(neighbor)}}func (t *tower) GetWatchers() map[uint32]scene.GameObject {return t.mapId2Watcher}func (t *tower) GetObjs() map[uint32]scene.GameObject {return t.mapId2Obj}func (t *tower) GetTowerId() int64 {return t.towerId}func (t *tower) AddSyncData(mod uint16, cmd uint16, msg protoreflect.ProtoMessage) {t.context.AddSyncData(mod, cmd, msg)}func (t *tower) Broadcast() {if len(t.context.fights) == 0 {return}// 广播协议 ....   t.context.ClearContext()}

三.AOI的具体方法实现

我们在回过头来继续说 mgr 的方法.

1.进入实现

前提:

GameObject : 一切场景物体的基础接口

type GameObject interface {}

Vector2d : X,Y 坐标

type Vector2d struct {x, y, w float64}

具体实现:

如果是从上一个区域内离开,则先走 离开上一个区域,然后计算当前进入位置坐标对应的九宫区域,

然后把obj 加入到各个区域内

func (m *TowerAOIManager) OnEnter(obj scene.GameObject, enterPos *geom.Vector2d) bool {if obj.GetAOITower() != nil {m.OnLeave(obj) // 离开上一个区域}obj.SetPosition(enterPos) // 设置当前位置    // obj 视野范围内的所有区域m.visitWatchedTowers(enterPos, obj.GetViewRange(), func(tower *tower) {tower.addWatcher(obj, false)})t := m.getTowerXY(enterPos)    // 当前位置所在的区域t.AddObj(obj, nil, false)return true}func (m *TowerAOIManager) getTowerXY(xyPos *geom.Vector2d) *tower {xi, yi := m.transXY(xyPos.GetX(), xyPos.GetY())return &m.towers[xi][yi]}

关键的方法:

计算obj当前位置中,视野内能被观察到的所有区域.

func (m *TowerAOIManager) visitWatchedTowers(xyPos *geom.Vector2d, aoiDistance float64, f func(*tower)) {ximin, ximax, yimin, yimax := m.getWatchedTowers(xyPos.GetX(), xyPos.GetY(), aoiDistance)for xi := ximin; xi <= ximax; xi++ {for yi := yimin; yi <= yimax; yi++ {tower := &m.towers[xi][yi]f(tower)}}}func (aoiman *TowerAOIManager) getWatchedTowers(x, y float64, aoiDistance float64) (int, int, int, int) {ximin, yimin := aoiman.transXY(x-aoiDistance, y-aoiDistance)ximax, yimax := aoiman.transXY(x+aoiDistance, y+aoiDistance)return ximin, ximax, yimin, yimax}func (m *TowerAOIManager) transXY(x, y float64) (int, int) {xi := int((x - m.minX) / m.towerRange)yi := int((y - m.minY) / m.towerRange)return m.nORMalizeXi(xi), m.normalizeYi(yi)}func (m *TowerAOIManager) normalizeXi(xi int) int {if xi < 0 {xi = 0} else if xi >= m.xTowerNum {xi = m.xTowerNum - 1}return xi}func (m *TowerAOIManager) normalizeYi(yi int) int {if yi < 0 {yi = 0} else if yi >= m.yTowerNum {yi = m.yTowerNum - 1}return yi}

2.离开区域

func (m *TowerAOIManager) OnLeave(obj scene.GameObject) bool {obj.GetAOITower().RemoveObj(obj, true) // 离开当前区域    // 查找视野内所有区域,然后从关注列表中移除m.visitWatchedTowers(obj.GetPosition(), obj.GetViewRange(), func(tower *tower) {tower.removeWatcher(obj)})return true}

3.移动

每帧移动坐标点 movePos

func (m *TowerAOIManager) OnMove(obj scene.GameObject, movePos *geom.Vector2d) bool {oldX, oldY := obj.GetPosition().GetX(), obj.GetPosition().GetY()obj.SetPosition(movePos) //设置当前坐标t0 := obj.GetAOITower()t1 := m.getTowerXY(movePos)    // 判断移动是否跨区域了if t0.GetTowerId() != t1.GetTowerId() {t0.RemoveObj(obj, false)t1.AddObj(obj, t0, true)}    // 计算前后变化的区域,进行移除和添加关注列表oximin, oximax, oyimin, oyimax := m.getWatchedTowers(oldX, oldY, obj.GetViewRange())ximin, ximax, yimin, yimax := m.getWatchedTowers(movePos.GetX(), movePos.GetY(), obj.GetViewRange())for xi := oximin; xi <= oximax; xi++ {for yi := oyimin; yi <= oyimax; yi++ {if xi >= ximin && xi <= ximax && yi >= yimin && yi <= yimax {continue}tower := &m.towers[xi][yi]tower.removeWatcher(obj)}}for xi := ximin; xi <= ximax; xi++ {for yi := yimin; yi <= yimax; yi++ {if xi >= oximin && xi <= oximax && yi >= oyimin && yi <= oyimax {continue}tower := &m.towers[xi][yi]tower.addWatcher(obj, true)}}return true}

4.同步

每帧同步所有区域变化的物体对象

func (m *TowerAOIManager) OnSync() {for i := 0; i < m.xTowerNum; i++ {for j := 0; j < m.yTowerNum; j++ {m.towers[i][j].Broadcast()}}}

简单的实现了 AOI 区域变化管理,当然后面还需要优化,我们知道"九宫格" 算法的缺点:

1 . 当玩家跨越格子的时候,比如说从A点到B点.瞬间会有新增格子,那其中的对象就会进入视野,与此同时,就会有消失的格子,那其中的对象就要消失视野.这个瞬间就会出现一个流量激增点,它可能会导致客户端卡顿等问题.

流量浪费.有客户端不需要的对象被同步过来了.我们知道它是基于格子来管理地图对象的.那么就会无法保证九宫区域一定刚好是视野范围.肯定是大于视野区域这样才保证同步对象正确.(如果是俯视角那种 ,视野就会是一个 梯形范围.)

Go语言如何实现AOI区域视野管理

或者你可以在服务端中,根据客户端梯形视野在作一遍初筛.

关于“Go语言如何实现AOI区域视野管理”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网精选频道,小编每天都会为大家更新不同的知识点。

--结束END--

本文标题: Go语言如何实现AOI区域视野管理

本文链接: https://lsjlt.com/news/350882.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Go语言如何实现AOI区域视野管理
    这篇文章主要介绍“Go语言如何实现AOI区域视野管理”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Go语言如何实现AOI区域视野管理”文章能帮助大家解决问题。优化的思路一般是: 第一个是尽量降低向客...
    99+
    2023-07-05
  • Go语言实现AOI区域视野管理流程详解
    目录一.定义管理器接口二.定义区域tower三.AOI的具体方法实现1.进入实现2.离开区域3.移动4.同步优化的思路一般是: 第一个是尽量降低向客户端同步对象的数量,第二个是尽量降...
    99+
    2023-03-06
    Go AOI区域视野管理 Go AOI视野管理
  • Go语言如何实现图形可视化功能
    Go语言如何实现图形可视化功能 随着计算机技术的不断进步,图形可视化已经成为了信息传递和呈现的重要方式之一。在开发应用程序时,如何利用编程语言实现图形可视化功能成为了一个重要课题。Go...
    99+
    2024-03-11
    - go - 图形 - 可视化 go语言
  • GO语言怎么实现协程池管理
    本篇内容介绍了“GO语言怎么实现协程池管理”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!使用channel实现协程池通过 Channel 实...
    99+
    2023-06-20
  • win7更改区域语言不管用如何解决
    这篇文章主要介绍“win7更改区域语言不管用如何解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“win7更改区域语言不管用如何解决”文章能帮助大家解决问题。win7更改区域语言不管用解决方法首先打...
    99+
    2023-07-01
  • Go语言如何实现大数据处理?
    随着大数据时代的到来,数据量的爆炸式增长已经成为了一个不可避免的趋势。在这种情况下,如何高效地处理大数据成为了一个急需解决的问题。Go语言作为一种编译型、静态类型的语言,具有高效、高并发等特点,因此也成为了处理大数据的一种优秀的选择。 G...
    99+
    2023-11-13
    大数据 numy spring
  • GO 语言中的自然语言处理技术如何实现?
    自然语言处理(Natural Language Processing, NLP)是计算机科学与人工智能领域的重要分支,其目的是让计算机能够理解和处理人类语言。在现代社会中,自然语言处理已经广泛应用于搜索引擎、机器翻译、智能客服、智能音箱等...
    99+
    2023-09-05
    自然语言处理 shell 对象
  • Go语言如何实现多态 
    这篇“Go语言如何实现多态 ”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Go语言如何实现多态 ”文章吧...
    99+
    2023-06-30
  • 如何用 Go 语言实现 SCP
    随着数据传输的不断增长,传输大量数据时如何确保数据安全和传输效率变得越来越重要。SCP (Secure Copy Protocol)是一种安全传输文件的协议,与SSH (Secure Shell)一起使用。本文将介绍如何用 Go 语言实现 ...
    99+
    2023-05-14
  • Go语言中锁如何实现
    今天小编给大家分享一下Go语言中锁如何实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。Lock// Lock&n...
    99+
    2023-07-05
  • C语言如何实现教务管理系统
    这篇文章主要介绍“C语言如何实现教务管理系统”,在日常操作中,相信很多人在C语言如何实现教务管理系统问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C语言如何实现教务管理系统”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-06-29
  • C语言如何实现会员管理系统
    本文小编为大家详细介绍“C语言如何实现会员管理系统”,内容详细,步骤清晰,细节处理妥当,希望这篇“C语言如何实现会员管理系统”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。会员信息包括:会员号(6位数,唯一),姓名...
    99+
    2023-06-29
  • C语言如何实现学籍管理系统
    这篇文章给大家分享的是有关C语言如何实现学籍管理系统的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。具体内容如下设计一个学籍管理系统,基本功能包括:输入学生基本信息2.查询学生信息(1.按学号2.按姓名)3.删除学...
    99+
    2023-06-29
  • C语言如何实现图书管理系统
    这篇文章将为大家详细讲解有关C语言如何实现图书管理系统,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。主要内容        开发一个图书信息管理系统,图书信息包括:...
    99+
    2023-06-28
  • C语言如何实现财务管理系统
    这篇文章将为大家详细讲解有关C语言如何实现财务管理系统,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。具体内容如下包括录入班级成员信息2.排序3.修改学生信息4.删除指定学号学生5.查找学生6.添加财务信息...
    99+
    2023-06-25
  • C语言如何实现车票管理系统
    今天小编给大家分享一下C语言如何实现车票管理系统的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、项目简介设计一个车票管理系...
    99+
    2023-06-30
  • C语言如何实现酒店管理系统
    这篇文章主要讲解了“C语言如何实现酒店管理系统”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C语言如何实现酒店管理系统”吧!系统框架:代码:#include <stdio.h...
    99+
    2023-06-30
  • C语言如何实现设备管理系统
    这篇文章主要介绍“C语言如何实现设备管理系统”,在日常操作中,相信很多人在C语言如何实现设备管理系统问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C语言如何实现设备管理系统”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-06-30
  • 如何在PHP项目中实现多语言支持和多域名管理?
    如何在PHP项目中实现多语言支持和多域名管理?随着全球化的发展,越来越多的网站和应用需要支持多语言和多域名管理。在PHP项目中实现多语言支持和多域名管理有助于提高用户体验和扩大用户群体。本文将介绍如何在PHP项目中实现这两个功能。多语言支持...
    99+
    2023-11-03
    翻译 路由 本地化 多语言支持:语言切换 多域名管理:域名解析
  • Go语言在Linux上如何实现自然语言处理并发?
    自然语言处理(NLP)是一个涉及语言学、计算机科学和人工智能的领域,它旨在使计算机能够理解人类语言并进行交互。在实现自然语言处理过程中,并发性能是一个重要的问题。在本文中,我们将探讨如何使用Go语言在Linux上实现高效的自然语言处理并发...
    99+
    2023-09-16
    自然语言处理 并发 linux
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作