客户端-服务器游戏算法
对于独立游戏,基本的游戏循环是(来源:维基百科)
while( user doesn't exit )
check for user input
run AI
move enemies
resolve collisions
draw graphics
play sounds
end while
但是,如果我开发类似客户端服务器的游戏,例如 Quake、Ragnarock、Trackmania 等,
游戏的客户端和服务器部分的循环/算法是什么?
For stand alone games, the basic game loop is (source: wikipedia)
while( user doesn't exit )
check for user input
run AI
move enemies
resolve collisions
draw graphics
play sounds
end while
But what if I develop client-server-like games, like Quake, Ragnarock, Trackmania, etc,
What the Loop/Algorithm for client and the server parts of the game?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
类似于
客户端:
服务器:
It would be something like
Client:
Server:
客户端:
服务器:
对客户端命令和世界数据进行健全性检查,以消除因故意作弊(移动太快、穿墙等)或滞后(穿过客户端认为打开的门,但服务器知道已关闭,等等)。
为了处理客户端和服务器之间的延迟,客户端必须对接下来会发生的情况做出最佳猜测(使用当前的世界数据和客户端命令) - 然后客户端将必须处理它预测会发生的情况之间的任何差异服务器后来告诉它确实发生了。 通常情况下,这将足够接近,玩家不会注意到差异 - 但如果延迟很大,或者客户端和服务器不同步(例如由于作弊),那么客户端将需要在以下情况下进行突然纠正:它接收从服务器返回的数据。
将这些进程的各个部分拆分为单独的线程以优化响应时间也存在很多问题。
最好的开始方法之一是从拥有活跃模组社区的游戏中获取 SDK - 深入研究其工作原理将为您提供一个关于如何完成它的良好概述。
Client:
Server:
The sanity checks on the client commands and world data are to remove any 'impossible' situations caused either by deliberate cheating (moving too fast, through walls etc) or lag (going through a door that the client thinks is open, but the server knows is closed, etc).
In order to handle lag between the client and server the client has to make a best guess about what will happen next (using it's current world data and the client commands) - the client will then have to handle any discrepancies between what it predicted would happen and what the server later tells it actually happened. Normally this will be close enough that the player doesn't notice the difference - but if lag is significant, or the client and server are out of synch (for example due to cheating), then the client will need to make an abrupt correction when it receives data back from the server.
There are also lots of issues regarding splitting sections of these processes out into separate threads to optimise response times.
One of the best ways to start is to grab an SDK from one of the games that has an active modding community - delving into how that works will provide a good overview of how it should be done.
这确实不是一个简单的问题。 在最基本的层面上,您可以说网络提供的数据与原始循环的 MoveEnemies 部分提供的数据相同。 因此,您可以简单地将循环替换为:
但是,您需要考虑延迟,因此您实际上不想通过调用网络来暂停主循环。 为了克服这个问题,网络引擎坐在第二个线程上,尽快从服务器轮询数据并将对象的新位置放入共享内存空间中并不罕见:
那么您的主循环将如下所示:
此方法的优点是您的游戏循环将尽可能快地运行,但来自服务器的信息只有在完成与服务器之间的完整发布后才会更新。 当然,您现在遇到了跨线程共享对象以及随之而来的锁等乐趣的问题。
在服务器端,循环大致相同,每个玩家有一个连接(通常每个玩家也在一个单独的线程上,这样一个玩家的延迟不会影响其他玩家)对于每个连接,它将运行一个循环,例如
当客户端计算机请求敌人的位置时,服务器从共享内存块中读取所有其他玩家的位置并将其发回。
这是一个非常简化的概述,还有更多的调整可以提高性能(例如,服务器将敌人位置发送给客户端而不是客户端请求它们可能是值得的),并且您需要决定在哪里做出某些逻辑决策(客户端是否因为自己拥有最新的位置而决定自己是否被射击,或者服务器停止作弊)
It really isn't a simple problem. At a most basic level you could say that the network provides the same data that the MoveEnemies part of the original loop did. So you could simply replace your loop with:
However you need to take into account latency so you don't really want to pause your main loop with calls to the network. To overcome this it is not unusual to see the networking engine sitting on a second thread, polling for data from the server as quickly as it can and placing the new locations of objects into a shared memory space:
Then your main loop would look like:
The advantage of this method is that your game loop will run as fast as it can, but the information from the server will only be updated when a full post to and from the server has been completed. Of course, you now have issues with sharing objects across threads and the fun with locks etc that comes with it.
On the server side the loop is much the same, there is one connection per player (quite often each player is also on a separate thread so that the latency of one won't affect the others) for each connection it will run a loop like
When the client machine requests the locations of enemies the server reads all the other players locations from the shared block of memory and sends it back.
This is a hugely simplified overview and there are many more tweaks that will improve performance (for instance it may be worth the server sending the enemy positions to the client rather than the client requesting them) and you need to decide where certain logically decisions are made (does the client decide whether he has been shot because he has the most up to date position for himself, or the server to stop cheating)
客户端部分基本相同,除了替换
为
而服务器只是这样做:
The client part is basically the same, except replace
with
And the server just does:
您可以使用几乎相同的东西,但大部分逻辑都在服务器上,您可以将计时器、声音、图形和其他 UI 组件放在客户端应用程序上。
任何业务规则(人工智能、动作)都位于服务器端。
You can use almost the same thing, but the most of you logic would be on the server, you can put timers, sounds, grafics, and other UI components on the client app.
Any business rule (AI,Movements) goes in the server side.
一篇非常有用且我认为值得阅读的相关论文是:客户端-服务器架构
我读了它并从中学到了很多东西,得到了很多意义。 通过将游戏分成战略性定义的组件或层,您可以创建更易于维护的架构。 该程序比您所描述的传统线性程序模型更容易编码,并且更健壮。
这个思想过程出现在之前的一篇文章中,内容是关于使用“共享内存”在程序的不同部分之间进行通信,从而克服单线程和逐步游戏逻辑的限制。
您可能会花几个月的时间来研究完美的架构和程序流程,读完一篇论文后就会意识到您找错了方向。
太棒了; 阅读。
A very useful and I would argue pertinent paper to read is this one: Client-Server Architectures
I gave it a read and learned a lot from it, a lot of sense was made. By separating out your game into strategically defined components or layers, you can create a more maintainable architecture. The program is easier to code, and more robust than a conventional linear program model like the one you've described.
That thought process came out in a previous post here about using a "Shared Memory" to talk between different parts of the program, and so overcoming the limitations of having a single thread and step-followed-step game logic.
You can spend months working on the perfect architecture and program flow, read a single paper and realise you've been barking up the wrong tree.
tldr; read it.