游戏设计------九宫格视野控制

游戏设计------九宫格视野控制

参考网址:https://blog.csdn.net/qq_36748278/article/details/102787225

背景

玩家视野背景

AOI(Area of Interest),即感兴趣区域。可以看成在游戏中玩家在所在场景中实时看到的区域,即AOI会随着玩家的移动而改变。在游戏中,会有很多个场景(地图),每个地图中都有很多玩家或者npc,视野数据是相互的, 玩家A 可以看到 玩家B , 玩家B 同时也会看到 玩家A 。当 玩家 在地图中做一些行为操作的时候,如果想要玩家的行为被别人看到,就需要把玩家的行为广播给地图中的所有玩家。场景中玩家的行为只要有修改就广播给场景中其他所有玩家,这种方式是最优的方式呢?

  • 对于一些玩家数量较少的场景,比如组队副本等。玩家会看到地图中所有的玩家和npc,可以称之为全视野场景。这种场景中,单个玩家有操作采取广播给场景中的其他玩家的方式是可行的。
  • 对于一些大型的PVP玩法,同一个场景中有几百甚至上千人参加的时候,假设场景中共有1000人参加。任意一个玩家只要移动就要广播给剩下的999人,当1000个人同时移动的话,服务器需要处理999 * 999(百万级别)条消息,相当于 n*n 。场景中所有人移动一下就产生百万级别的数据,还没有考虑玩家的技能释放等其他的行为操作的同步,这么大数据量容易造成服务器消息的堆积,无法做到及时响应。同时,客户端每一个玩家都会处理其他1000个玩家的实时信息,容易造成客户端的卡顿,如果消息处理不过来也会出现包数据的丢失。同时发往客户端的包的数量太大,还会消耗大量的流量。这种方式肯定不是我们想要的,游戏体验会非常差。

我们可以发现,在游戏中,玩家始终会出现在屏幕的中央,随着玩家的移动,视野也会随着玩家的移动同时移动,但是始终都是以玩家为中心。玩家所能看到的就是游戏屏幕内以玩家为中心向四周360度扩展的视野信息。那么如果修改玩家的 AOI ,控制在以玩家为中心 屏幕内所有所见对象记为玩家的视野数据;当玩家有行为操作的时候,只需要通知在玩家视野中的其他用户,相对于通知场景中的全部玩家来说可以减少大量没有必要的消息的推送,同时也能节省很多流量。因为距离太远的其他用户是不在玩家当前屏幕显示范围内的,把玩家的行为操作通知给这些玩家是没有什么意义的。
但是如果该场景中所有玩家都在打一个boss,场景中玩家全部都集中在一起,那么玩家当前屏幕中的视野数据又变成场景中的全部玩家了。同时受客户端性能的限制,客户端有最大的同屏人数上限,因此我们需要限制玩家的视野上限。当场景中玩家全部集中的一起的时候按照优先级(社交关系,敌对关系,距离等)进行筛选,筛选出指定数量的对象算入玩家的视野对象。

因此,针对大型PVP玩法的活动,当场景中人数非常多的时候,玩家的视野采用限制视野上限,并且以玩家为中心360度指定范围设定为玩家视野的方式。以玩家为中心,向四周360度扩展,可以延伸出以玩家为中心的正方形区域,也可以是以玩家为中心的圆形区域。但是由于地图时正方形的,圆形并不适合进行坐标范围临界点的计算,因此最好的就是按照以玩家为中心向外360度扩展的正方形区域。我们可以发现围出来的刚好是一个以玩家为中心的正方形区域。因此可以想到按照各自划分地图区域,玩家在格子的中心,以玩家为中心的正方形区域刚好可以分成九宫格 3 * 3。并且九宫格的区域需要大于等于游戏屏幕的显示区域,根据具体情况合理设计每个地图格子的长度即可。因此玩家的视野数据可以采用九宫格存储的形式。

在这里插入图片描述

地图

地图划分格子

在游戏中,地图大小都是正方形,并且是以 X 轴, Z 轴为水平面的(游戏中都以cm为单位)。把地图按照指定的大小分成若干个格子,如以 7m(需要根据实际的地图大小设置单个格子的长度大小) 为单位划分块。当地图被划分为多个地图块之后,通过玩家的坐标点可以计算出玩家哪个地图块中。
在 X 轴方向进行划分,X轴地图总长度为256m,假设每个块的大小为7m,那么在X 轴,共有多少个格子呢? 256 / 7 = 36.57142857142857,不满足一个格子的直接按照 1 个格子来计算,即X 轴上共有36 + 1 = 37块格子,Z轴同理。假设每个块的大小为8m,256 / 8 = 32,刚好可以划分为32个块。当地图大小固定的时候,不同大小的块,会得到不用的格子数,有的可以整除,有的不能整除(不能整除的不满足 1 块大小算作 1 块),即向上取整。为了避免进行是否能够整除的条件判断,统一采用加 1,即采用 地图长度 / 每个格子长度 + 1 来计算划分的格子数。因此我们划分的总格子数总是会比场景中的地图要大的。假设地图大小是256m * 256m,每个格子的大小是7m * 7m,下面都是按照这个大小进行讨论。

  • X 轴的总格子数 X_AREA_NUM_PER_MAP = X轴地图长度 / X轴每个格子长度 + 1
  • Z 轴的总格子数 Z_AREA_NUM_PER_MAP = Z轴地图长度 / Z轴每个格子长度 + 1
  • 整个地图共有的格子数 MAX_DYN_AREA_NUM = X_AREA_NUM_PER_MAP * Z_AREA_NUM_PER_MAP + 1(此处加 1 个格子是为了安全起见)

游戏中可以采用一维数组的方式进行存储地图中所有的格子。格子数 - 1 = 数组下标,通过下标进而得到数组中存储的对应共享内存ID,从而可以得到对应的视野块对象(1个格子可以视作一个视野块对象)。

地图的视野块(格子)和数组下标的关系如下:
在这里插入图片描述

坐标点定位玩家所在地图块

如何根据具体的坐标点找到玩家所处于哪个格子中呢?
X轴列方向:第一个格子的范围 [0,7),第二个格子范围 [7,14),第三个格子范围[14,21)…
Z轴行方向:第一个格子的范围 [0,7),第二个格子范围 [7,14),第三个格子范围[14,21)…

已知玩家的坐标pos(8, 100, 15),假设地图大小为256m * 256m,格子的大小为7m * 7m。
可以先按照二维数组下标分析:
在 X 轴,X 所在格子数为 X = 8 / 7 = 1,即在X轴上第2列格子中(如图),X轴数组下标为1
在 Z 轴,Z 所在格子数为 Z = 15 / 7 = 2,即在Z轴上第3层格子中(如图),Z轴数组下标为2
按照二维数组计算下标的方式,玩家所在数组的下标为: Z * X_AREA_NUM_PER_MAP + X = 2 * 37 + 1 = 75
在这里插入图片描述

地图、视野块、玩家的关系

在这里插入图片描述
一个游戏会有很多个场景;
每个场景对应一个地图资源;
每个地图上会分为多个格子,每个格子都是一个视野块对象;
每个视野块上会有很多个玩家或者npc。

玩家视野

玩家视野变动会有下面两种情况

  • 主动:玩家操作引起的视野刷新:
    玩家进入地图,会搜索玩家的视野信息。
    玩家移动,从一个视野块移动到另一个视野块(如果在同一个格子中移动,不会刷新视野)。
  • 被动:其他原因造成玩家视野的变动:
    其他玩家进入/离开视野,会引起自身视野的变动。

玩家移动引起视野刷新的可能情况

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码实现

涉及到具体的玩家视野更新逻辑,请参考上面给出的参考网址

github地址

发布了155 篇原创文章 · 获赞 15 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/wangdamingll/article/details/105207975