客户端-服务器多人在线游戏中的移动“算法”?

8
我正在编写一款2D闪存多人游戏和一个套接字服务器,客户端和服务器之间的移动算法原本是这样的:
- 当玩家改变移动模式(向前移动或不移动)和转向模式(不转向、向左转或向右转)时,客户端通知服务器。 - 服务器每隔几毫秒循环所有玩家,并根据时间差计算转弯角度和移动距离。客户端也做同样的计算。
我的当前客户端计算方式(服务器中使用相同的数学公式)==> 转向:
var newTimeStamp:uint = UtilLib.getTimeStamp(); //set current timeStamp
                var rot:uint = Math.round((newTimeStamp - turningTimeStamp) / 1000 * 90); //speed = x degrees turning every 1 second
                turningTimeStamp = newTimeStamp; //update timeStamp
                if (turningMode == 1) //left
                {
                    movementAngle = fixAngle(movementAngle - rot);
                }
                else if (turningMode == 2) //right
                {
                    movementAngle = fixAngle(movementAngle + rot);
                }

private function fixAngle(angle:int):uint //fixes an angle in degrees (365 -> 5, -5 -> 355, etc.)
        {
            if (angle > 360)
            {
                angle -= (Math.round(angle / 360) * 360);
            }
            else if (angle < 0)
            {
                angle += (Math.round(Math.abs(angle) / 360) + 1) * 360;
            }
            return angle;
        }

移动

var newTimeStamp:uint = UtilLib.getTimeStamp(); //set current timeStamp
                var distance:uint = Math.round((newTimeStamp - movementTimeStamp) / 1000 * 300); //speed = x pixels forward every 1 second
                movementTimeStamp = newTimeStamp; //update old timeStamp
                var diagonalChange:Array = getDiagonalChange(movementAngle, distance); //with the current angle, howmuch is dX and dY?
                x += diagonalChange[0];
                y += diagonalChange[1];

private function getDiagonalChange(angle:uint, distance:uint):Array
        {
            var rAngle:Number = angle * Math.PI/180;
            return [Math.round(Math.sin(rAngle) * distance), Math.round((Math.cos(rAngle) * distance) * -1)];
        }

这似乎很有效。为了考虑延迟,服务器会定期通过发送数据来更正客户端的信息。

使用此系统处理移动所需的带宽非常少。但是,我的服务器和客户端的坐标和角度之间的差异太大了。我是否应该扩展我的“算法”,以考虑用户的延迟?或者有更好的方法来处理在客户端<>服务器多人游戏中的运动并保持高性能吗?

3个回答

6
我的初始设计和你的类似,但如果不起作用,也许你可以让客户端做所有的移动,只需让服务器进行一些范围检查。
因此,如果您的最后报告位置是X,则下一个位置必须在以X为中心的半径内,其中半径基于客户端发送的时间戳与x、y数据的差异。
大多数情况下,这只是为了检测作弊行为。
停止、战斗等需要发送位置以及攻击,而由位置触发的操作只有在客户端发送该位置的更新后才会触发,但是仍然由服务器控制。
不确定这是否会有太大帮助,但它可能会阻止您的初始算法中出现的抖动重新同步。
评论回复:
不,客户端仍将通知服务器其位置,但服务器不会尝试计算下一个位置。这意味着服务器(和所有其他客户端)在位置上至少落后于一个发送/接收周期。
我的意思是让客户端做所有的工作,找出角色在哪里并告诉服务器,但包括足够的信息,以便服务器可以选择性地检查有效性,以确保没有人作弊。
甚至可以关闭作弊检测以提高性能,或者随机检查。
注意:为使此方法起作用,所有可达范围内的对象的碰撞/位置信息都需要发送到客户端。

如果所有客户端都必须通知所有其他客户端其当前位置,那么服务器不是必须持续接收和重新发送大量的消息吗? - Tom
+1,我其实也想建议同样的事情。这是许多热门多人在线游戏所采用的方式。服务器定期确保每个人都同步。(我相信《雷神之锤》系列游戏就是这么做的。) - Sasha Chedygov
我的第一个问题仍然适用。客户端难道不必一直发送数千条消息,以使服务器与每一步都保持最新状态吗?接着服务器再次将这些数据发送给所有附近的玩家。 - Tom
“一直有成千上万的消息”有点夸张,但客户端每秒通知服务器其位置大约10次左右并且服务器以类似频率广播其中大部分并不罕见。 - Kylotan
如果您每秒向服务器发送10个更新,则有时会忽略/丢失一些更新也不会产生太大或没有负面影响。 - Bill K

1

我能想到两种方法来实现这个 - 让客户端向服务器发出命令,服务器将成为最终的地图管理者。

或者,将地图保存在客户端中,客户端将不得不与其他“附近”的客户端建立连接以进行移动,记录由服务器完成,并由几个同行(黑客警察)检查。

对我来说有趣的是监视同行连接的可能性,延迟超过一定阈值的同行将不会在游戏中显示。


有趣,但这种方式限制了大型战斗,因为P2P无法同时处理那么多连接 - 现在您还要依赖客户端的连接来处理其他客户端。我仍在寻找最佳的服务器<>客户端系统。 - Tom
2
为什么P2P不能处理许多连接?每当有人执行某些操作时,您需要从服务器进行重新广播,或者从对等方接收消息。我认为流量接近相同(我可能是错误的)。 - ryansstack

0

你的服务器速度太慢了,无法处理所有的移动吗?特别是在2D游戏中?通常当我制作小型2D游戏时,服务器会将我的所有移动返回给我,因此客户端不需要进行任何计算。如果服务器开始出现延迟,我只需稍微冻结一下,这通常是人们所期望的(尽管这几乎从未发生过)。

无论如何,我肯定会看看性能是否足够好,而不需要客户端自己进行任何实际计算。如果性能不够好,看看在服务器上循环遍历玩家移动是否导致了延迟(并为每个客户端启动一个不同的线程)。

如果确实存在带宽限制(移动本身传输的数据非常少),那么肯定需要找到该特定用户的平均延迟,并将其计入算法中。然而,为了持续不断地找到平均值(以获得更高的精度),您将不得不继续ping服务器以找到往返时间,这应该不会太昂贵。


这不是一个简单的2D游戏,它应该同时处理数百个玩家。我需要最优化的系统。 - Tom
在这种情况下,调整服务器以使其以足够小的间隔发送数据就可以了。当然,所有服务器都需要一定的玩家限制,但至少在客户端移动方面添加10-20ms的延迟。这几乎是不可察觉的,并且在大多数情况下应该对玩家的实际位置相对应。 - AlbertoPL

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接