最近做游戏需要用到刷新视野范围内的活动。服务器端会记录玩家的视野范围,如果视野范围内有变化,会推送给客户端。对于客户端来说有两个消息可以用:
1 刷新某个区域,发送给服务器后,服务器会把这个区域内的所有信息推送给客户端
2 设定视野范围,发送给服务器后,服务器会记录玩家的视野范围,如果视野范围内有变化会推送给客户端。
这连个消息应该很好理解,组合起来客户端就能很容易刷新显示区域的内容,并实时获得变化。但是如何设定视野范围却需要好好思考,否则会出现浪费流量的问题,比如按照最简单的做法会在移动屏幕时不停的刷新区域,这样照成很大的浪费。下面以几种情况来说明如何做一个比较合理的视野范围,和适时的刷新不至于浪费流量。
方法一:
简单粗暴,不可取。
这个方法很简单,也是最容易想到的,就是在屏幕显示范围每次发生移动时刷新一次区域,如下图
----------------------------------------
| 视野范围 |
| ------------------------ |
| | 屏幕显示范围 | |
| ------------------------ |
| |
----------------------------------------
为什么要把视野范围设定大于屏幕范围呢?这是一个小的细节,因为有的对象可能再屏幕边上,在屏幕内可以看到该对象的一部分,但是该对象的坐标点在屏幕外,如果设定的超出范围合理就能很好的处理这种压边的情况。
这个方法很简单,都能想得到,但是每移动一个像素都刷新视野很蛋疼。所以想想看能否隔一段刷新一下,于是很容易就想到了下面这个方法。
方法二:
比方法一的优化点在于不需要每移动一个像素都刷新视野范围,而是在移动一段距离之后再刷新,所以很容易想到把地图划分成等大小的格子,比如把地图划分成和屏幕一样大小的小格子。如下图:
-------------------------------------------------
| | |
-------------------------------------------------
| | |
--------------------------------------------------
一个屏幕范围最多跨越4个格子,一般状态下也是跨越四个格子,所以可以把视野范围设定在这四个格子内,再加上压边的范围即可,什么时候刷新格子呢?就是在屏幕的中心点所在的格子坐标变化时刷新,这个方法看起来很不错,如果朝着一个方向移动每隔一个屏幕才刷新一次,very good! But,图样图森破,如果我的屏幕中心刚好在格子边界,并且左右晃动,就会发生这样的事(1,1) -> (2,1) ->(1,1)->(2,1) 还是会不停的刷新,也就是这种处理方式存在边界情况。
方法三:
忘掉地图划分格子这中思考方式吧,把焦点重新转移到我们的屏幕视野上,其实肯定可以做到走一段距离才刷新的,对不对,并且不存在边界,对不对?只是我们一下子可能想不清楚怎么做,那就慢慢来,从已知条件一步步往结果推,于是:
1. 首先我们有一个屏幕视野范围,如下
------------------------
| 屏幕视野范围 |
------------------------
2. 其次需要移动范围后才刷新视野区域,如下:
---------------------------------------------------------
| 可移动范围 |
| ------------------------ |
| | 屏幕视野范围 | |
| ------------------------ |
| |
---------------------------------------------------------
可移动范围是指我们在这个范围内移动都不会重新刷新区域。
3. 那么在什么时候刷新视野区域呢,很简单了,就是在移出可移动范围时刷新即可?没错,就这么简单。现在的视野范围等于可移动范围。
4. 如果加上压边的情况,比如考虑屏幕移到最右边时视野范围需要扩大多少:
--------------------------------------------------------- |
| 可移动范围 | |
| ------------------------ |
| | 屏幕视野范围 | |
| ------------------------ |
| | |
--------------------------------------------------------- |
5. 那么视野范围就是:
---------------------------------------------------------------------------------------
| --------------------------------------------------------- |
| | 可移动范围 | |
| | ------------------------ | |
| | | 屏幕视野范围 | | |
| | ------------------------ | |
| | | |
| --------------------------------------------------------- |
---------------------------------------------------------------------------------------最外圈这么大。每次刷新视野之后屏幕都在中心,刷新之后再看之后的屏幕范围有没有移出“可移动范围”即可,如果移出了再刷新一次视野范围即可。
这样360度无死角的视野刷新算法就完成了。