首先我们来讨论下游戏开发中的几个坐标系,为了方便解释,我截取了灯塔AOI DEMO当NPC数目为0时候的样子(代码地址觉得有帮助的童鞋记得给我代码点个星_

先对这张图简单说明下:

  • 蓝色的坐标轴表示是灯塔AOI坐标系,绿色的坐标轴表示的是游戏坐标系,向左为X轴正方向,向上为Y轴正方向(这个坐标是我自己后面画上去的)
  • 深蓝色的点表示灯塔AOI坐标,左下的表示(0,0),右上表示(1,1)
  • 深绿色的点表示游戏坐标,左下表示(0,0),右上表示(1,1)
  • 每个灰色的小格子代表一个游戏坐标(边长为15像素)
  • 每个黄灰的大格子代表一个灯塔AOI坐标(边长为11个灰色小格子)
  • 瓦片地图大小为宽:100个灰色小格子 高:70个灰色小格子
  • 深蓝色的方块为玩家,大红色方框为玩家在游戏坐标系中的视野(视野半径为10个灰色小格子),兰色方框表示玩家在灯塔坐标系中的视野

像素

这个是客户端图形实际显示要用到的坐标(和游戏逻辑无关),每个图片长宽各多少像素,描点在什么位置,但是在游戏中直接使用像素作为计量单位(坐标点)十分不方便,比如物体的移动,况且移动也不会一个像素一个像素移动,所以我们做了一层抽象(格子),游戏相关的贴图(地图/人物/道具)必须是格子的整数倍,这样游戏中所有的物体才能被正常显示,而不会产生偏差。

格子/瓦片(游戏坐标系)

什么是格子?格子是游戏逻辑使用的最小单位,代表游戏坐标系的点,它的单位为像素(DEMO中15*15像素为一格),游戏中所有设定都必须是格子的整数倍,所以不会出现有物体在两个格子之间,导致坐标不确定的情况,物体的移动的步长单位也变成多少格,而不是像素了,即如果使用像素作为坐标点,从(0,0)移动到(0,1),则移动了1个像素,现在用格子作为坐标点,从(0,0)移动到(0,1),则移动了15个像素。

什么是瓦片?一张大的世界地图或者背景图可以由几种地形来表示,每种地形对应一张小的的图片,我们称这些小的地形图片为瓦片。把这些瓦片拼接在一起,一个完整的地图就组合出来了,这就是瓦片地图。

在DEMO中,为了简化逻辑,我将瓦片设置为一倍格子大小,玩家和NPC的大小也设置为一倍格子大小。

灯塔AOI坐标系

为什么需要灯塔AOI?假设我们想知道某点周围10格内有哪些对象,在没有灯塔AOI的情况下,我们需要遍历所有的对象计算其是否在范围内,随着地图内的对象越来越多,查找的效率也会越来越差,所以我们需要一种方法来过滤那些明显不需要参与计算的对象,所以我们将地图分割成一个个区域,在其中心放置一个假想的"灯塔",每个"灯塔"都会保存区域内的对象,这样当我们需要知道某点周围10格内有哪些对象时,我们只需要计算出范围内有哪些"灯塔",然后获取这些"灯塔"保存的对象列表,针对这些对象进行计算就能节省大量计算。为了方便表示和管理这些"灯塔",我们为其分配了新坐标(左下为(0,0)),这个新的坐标系即灯塔AOI坐标系(这个坐标系是用来做碰撞检测的)

灯塔视野和玩家视野

"灯塔"的视野越小,在碰撞检测时能过滤的无效对象就越多,但是整张地图"灯塔"的数目也就越多,消耗的内存就越大,而且对象进出灯塔的计算量就越多

"灯塔"的视野越大,在碰撞检测时能过滤的无效对象就越少,碰撞检测的计算量就越大,想象下只有一个"灯塔"的情况,即退回了没有灯塔AOI系统的情况

由于玩家的视野一般是固定的(屏幕显示区域大小一般固定),所以灯塔视野大小一般是玩家视野的1/2或1/3比较合适

灯塔坐标的计算

假设要计算游戏中某点所处的灯塔坐标(详细逻辑见代码注释):

### 将游戏坐标系和灯塔AOI坐标系对齐,然后除以灯塔边长(两倍视野内包含的格子数 + 自身坐标格子)
static_cast<int>(std::floor(static_cast<float>(游戏X坐标 - 游戏地图左下角原点X坐标) / (2 * "灯塔"视野 + 1))
static_cast<int>(std::floor(static_cast<float>(游戏Y坐标 - 游戏地图左下角原点Y坐标) / (2 * "灯塔"视野 + 1))

灯塔AOI逻辑

对象进入(角色登入、生成怪物):

  • 根据对象坐标计算对象所属灯塔,将对象添加到灯塔的对象列表,如果灯塔上绑定了观察者,则通知观察者有对象进入
  • 找出对象视野范围的灯塔,将自身绑定为其观察者,绑定灯塔会将自身现有对象列表发送给对象

对象离开(角色登出、怪物被杀死):

  • 根据对象坐标计算对象所属灯塔,将对象从灯塔的对象列表中移除,如果灯塔上绑定了观察者,则通知观察者有对象离开
  • 找出对象视野范围的灯塔,解除其观察者绑定,解除绑定灯塔会将自身现有对象列表发送给对象

对象移动

  • 如果对象所属灯塔没变,则不做任何操作
  • 如果对象所属灯塔改变,则对旧灯塔执行对象离开逻辑,对新灯塔执行对象进入逻辑,但是要注意的是对视野的处理,前后视野交集内的灯塔不需要执行解绑和绑定操作

灯塔AOI简易实现的更多相关文章

  1. [game]十字链表的AOI算法实现

    AOI主要有九宫格.灯塔和十字链表的算法实现.本文阐述十字链表的实现和尝试. 1. 基本原理 根据二维地图,将其分成x轴和y轴两个链表.如果是三维地图,则还需要维护多一个z轴的链表.将对象的坐标值按照 ...

  2. AOI自动光学检测机技术在电路板检查中的应用

    1.简述 AOI技术在许多不同的制造业领域使用,自从电子影像技术开始发展,就被各种人利用在不同的应用领域.大家最熟悉的数字相机.数字摄影机是大家生活中最常用到的器材之一,而工业产品的生产也大量使用这些 ...

  3. 解码mmo游戏服务器三:大地图同步(aoi)

    问题引入:aoi(area of interest).在大地图中,玩家只需要关心自己周围的对象变化,而不需要关心距离较远的对象的变化.所以大地图中的数据不需要全部广播,只要同步玩家自己视野范围的消息即 ...

  4. AOI 设计

    http://blog.csdn.net/zhanghefu/article/details/25833535 云风的Blog 并进行整理而写. AOI(Area Of Interest),中文就是感 ...

  5. .NET里简易实现AOP

    .NET里简易实现AOP 前言 在MVC的过滤器章节中对于过滤器的使用就是AOP的一个实现了吧,时常在工作学习中遇到AOP对于它的运用可以说是很熟练了,就是没想过如果自己来实现的话是怎么实现的,性子比 ...

  6. 在.Net中实现自己的简易AOP

    RealProxy基本代理类 RealProxy类提供代理的基本功能.这个类中有一个GetTransparentProxy方法,此方法返回当前代理实例的透明代理.这是我们AOP实现的主要依赖. 新建一 ...

  7. .NET Core的文件系统[5]:扩展文件系统构建一个简易版“云盘”

    FileProvider构建了一个抽象文件系统,作为它的两个具体实现,PhysicalFileProvider和EmbeddedFileProvider则分别为我们构建了一个物理文件系统和程序集内嵌文 ...

  8. 自己来实现一个简易的OCR

    来做个简易的字符识别 ,既然是简易的 那么我们就不能用任何的第三方库 .啥谷歌的 tesseract-ocr, opencv 之类的 那些玩意是叼 至少图像处理 机器视觉这类课题对我这种高中没毕业的人 ...

  9. php+websocket搭建简易聊天室实践

    1.前言 公司游戏里面有个简单的聊天室,了解了之后才知道是node+websocket做的,想想php也来做个简单的聊天室.于是搜集各种资料看文档.找实例自己也写了个简单的聊天室. http连接分为短 ...

随机推荐

  1. thinkphp线上自动加载异常与修复

    项目遇到一个奇怪的问题,本地代码正常,服务器上却不正常. 经过测试,应该是自动加载出了问题,尝试了各种方法, 1.手动加载,发现好麻烦,没完没了. 2.自己写自动加载,写不出来,尴尬. 3.修改配置, ...

  2. html5移动开发的几大特性

    html5移动开发的出现让移动平台的竞争由系统平台转向了浏览器之间:移动端的IE.Chrome.FireFox.Safari,亦或是新出现的浏览器,谁能达到在移动端对HTML5更好的支持,谁就能在以后 ...

  3. Linux学习笔记 -- Shell 数组

    定义 在Shell的世界里,我们只能定义一维数组. 定义数组的时候不需要指定长度,数组的下标从0开始; Shell 数组用括号来表示,元素用"空格"符号分割开,语法格式如下: sh ...

  4. Linux - 创建用户的相关文件

    创建一个用户会与 6 个文件相关 /etc/passwd 储存了所有用户的相关信息 第一行中,从左往右 root 为用户名,: 为分隔符,x 为密码,0 为 uid,0 为 gid,root 为用户的 ...

  5. 用yum下载rpm包(不安装)到指定目录

    用yum下载rpm包(不安装)到制定目录    用yum下载rpm包   1.安装yum-downloadonly   # yum install yum-downloadonly -y     2. ...

  6. Pandas:表计算与数据分析

    目录 Pandas之Series Pandas之DataFrame 一.pandas简单介绍 1.pandas是一个强大的Python数据分析的工具包.2.pandas是基于NumPy构建的. 3.p ...

  7. Oracle行转列LISTAGG函数

    工作过程中需要将查询的数据分组并显示在一行.以往的工作经验,在sql server中可以用for xml path来实现. 现提供Oracle数据库的行转列方式 oracle11g官方文档简介如下: ...

  8. Python基础学习三 字典、元组

    一.元组 元组,提示别人,这个值是不能被改变的,元组的定义方式是用(),小括号: 元组只有两个方法,那就是count和index mysql1 = ('127.0.0.1',3306,'my','ro ...

  9. LINUX的SSH下FTP到远程服务器Entering Passive Mode失败解决

    LINUX 系统FTP连接远程服务器经常出现在传输文件或者发出 ls命令时候出现 "Entering Passive Mode "然后就再也无法运作了.该工作主要是因为LINUX的 ...

  10. OK6410&nbsp;linux系统遇到的BUG总结

    经过一段时间使用OK6410 256M RAM 2G nand Flash碰见了不少问题. 所以特意开本贴一起交流.大家有什么BUG解决的可以跟上本帖.求助的请另开贴.勿跟本帖.谢谢.请谅解!!! 希 ...