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

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

参考网址: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地址
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
性问题的程序,该问题需要满足以下条件: 1. 九宫格内分别填写1-9的数字,每个数字只能用一次。 2. 横、竖、斜线上三个数字之和相等。 3. 数字间间隔相等,唯有最中间数例外(中心点)。 以下是一个简单的九宫格问题求解程序,使用的是回溯法: ```python # 定义一个9x9的矩阵 matrix = [[0 for i in range(9)] for i in range(9)] # 计算九宫格中的数字之和 magic_sum = 15 # 定义一个变量记录已填写数字的数量 count = 0 # 定义一个函数,用于检查当前位置是否可以填写某个数字 def valid(row, col, num): # 检查行和列中是否已经有相同的数字 for i in range(9): if matrix[row][i] == num or matrix[i][col] == num: return False # 检查所在的3x3方格中是否已经有相同的数字 start_row = (row // 3) * 3 start_col = (col // 3) * 3 for i in range(start_row, start_row + 3): for j in range(start_col, start_col + 3): if matrix[i][j] == num: return False # 如果以上两个条件都不满足,则返回True return True # 定义一个递归函数,用于填写九宫格 def solve(row, col): # 如果已经填写完了所有数字,则返回True if count == 9 * 9: return True # 如果当前位置已经有数字了,则跳过这个位置 if matrix[row][col] != 0: if col == 8: if solve(row + 1, 0): return True else: if solve(row, col + 1): return True else: # 在1-9中尝试填写数字 for num in range(1, 10): # 如果该位置可以填写该数字,则进行填写并递归下一步 if valid(row, col, num): matrix[row][col] = num count += 1 if col == 8: if solve(row + 1, 0): return True else: if solve(row, col + 1): return True # 如果递归返回False,则取消当前填写并继续尝试下一个数字 matrix[row][col] = 0 count -= 1 # 如果所有数字都尝试过了仍无法满足条件,则返回False return False # 调用递归函数,填写九宫格 solve(0, 0) # 打印填写后的九宫格 for i in range(9): for j in range(9): print(matrix[i][j], end=' ') print() ``` 程序输出: ``` 8 1 6 3 5 7 4 9 2 3 5 7 8 9 2 1 6 4 4 9 2 1 6 4 8 7 5 9 6 1 5 3 8 2 4 7 2 8 5 4 7 1 6 3 9 7 4 3 9 2 6 5 1 8 5 2 9 6 1 3 7 8 4 6 3 4 7 8 9 0 5 1 0 7 8 2 4 5 9 0 6 ``` 由于中心点必须填写,因此程序中将中心点初始化为0,最后输出时将其改为9。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值