实时策略游戏如何在PHP中运作?

15

一些实时策略网络游戏(例如Travian或oGame)是用PHP编写的。

您能简要解释一下这样一个游戏在幕后是如何工作的吗?游戏如何进行实时数据库更新而无需玩家请求?

另外,如果运行诸如Travian之类的实时策略游戏并有1000个活跃玩家,需要预期什么样的服务器负载/带宽?


8
即使可以做到,我也不会用PHP编写这个代码,我会使用NodeJS来编写。 - AlienWebguy
2
嗯,我也是这么想的,但Travian和oGame相当“有名”,它们都是PHP编写的。我并不是说这是正确的方法,但似乎是可行的。 - conradkleinespel
3
OGame是多年前由一名普通私人开发者作为业余项目编写的(相信我,您不希望看到任何早期的OGame代码,这些代码现在应该已经被替换了)。当时,node.js甚至还不存在,而且Python在Web应用程序中并不普及。因此,除非您想使用Perl、Java或ASP,否则PHP几乎是唯一的解决方案。 - ThiefMaster
@AlienWebguy,您能否告诉我为什么在像Travian这样的项目中,您更喜欢使用NodeJS而不是PHP - Accountant م
5个回答

11
尽管这个话题已经很老了,但我认为我可以给出比“更新由cronjobs完成”的含糊答案更好的答案(如果我可以这么说的话)。
通过使用javascript,Travian让你产生了实时的错觉。实际上,在后台发生的是以下情况:
玩家A向玩家B发起攻击。在MySQL数据库中,记录了此事务到达的时间戳。每当玩家A更改或刷新页面时,一个脚本就会启动(通过包含方式),以检查与该玩家相关的任何活动(援军抵达,攻击目标等)。该脚本显然会检查当前时间,并查看所有时间戳小于当前时间戳的活动。这意味着该操作应该已经发生。在这一瞬间,实际上会处理该操作。
这也意味着,如果玩家A和玩家B都不再登录,那么攻击将永远不会被计算,除非其他人也攻击玩家B-然后将处理玩家B和攻击者的所有活动。

谢谢。这正是我在更深思熟虑后所想到的 :) - conradkleinespel
1
唯一的问题是,当攻击影响高分或像Ogame一样在战场周围创建一些碎片时。因此,即使两个玩家都没有登录(在高分情况下可能每小时完成一次..对于碎片可能更频繁),服务器也必须处理这些战斗。此外,尽可能利用空闲的CPU时间来计算这些更新将是很好的选择..所以想象一下,在晚上每个人都执行自己的操作并退出登录..而在早上,服务器需要为每个人计算 :) - balrok
1
那么他们如何计算储存中的大米、木材等物品增加了呢?非常有趣。有关于此的文档吗? - Lazaro Fernandes Lima Suleiman
你所描述的是“懒惰更新数据”,但在现代 OGame 中似乎并不是这样工作的,例如战斗结果将在撞击时间计算,即使两个玩家都已注销。它仍然可以懒惰地计算,例如只有当玩家打开星系菜单或打开统计信息时才进行计算。但这可能会失控,我们没有证据表明他们使用了这种方法。 - Antoine Weber

11
通常有两部分:Web界面和后台守护进程(通常称为“事件处理器”)。
Web界面执行所有只读操作和无害的操作,其中竞态条件根本不是问题 - 如更改密码、重命名等。
更重要的事情,如建造单位或与其他玩家战斗,则提交给事件处理程序,在那里将进行检查、验证,然后存储,直到达到执行时间。在此处执行检查而不是在Web界面中具有优势,因为您完全消除了竞态条件的风险(例如,在启动包含所有行星上可用单位的船只的同时建造某些昂贵的东西会导致基本上复制该播放器的可用单位)只要您确保在给定时间内仅运行一个操作/事件(例如,没有多线程、多处理等)。
如果您的应用程序不是完全实时的,而使用“滴答声”(例如,每隔x分钟才发生一次操作),则当然可以使用cronjob而不是后台守护程序 - 但是,您需要使用其他方式来避免竞态条件。
在我的游戏中,我有一个具有类似于RPC的接口的后台守护进程,因此在Web界面中,我只需调用函数syncCall('someFunction',....);,然后通过套接字连接到后台守护进程并执行给定的函数,返回该函数返回的任何内容。
然而,如果我现在编写一个新游戏,我肯定会使用异步解决方案,例如node.js或其中一个异步python框架。它消除了需要具有两个不同部分的需求 - 但对于某些部分,您必须注意锁定,因为每当从被节点本身调用的函数返回时,另一个事件的回调可能会被执行。

1
那么事件处理程序不是用PHP编写的,或者很可能不是,对吧? - conradkleinespel
2
如果您为所有内容都使用相同的技术,通常很容易,所以在我的情况下它是用PHP编写的。这样做有优点,我可以包含相同的函数库,而且不必用两种语言编写相同的内容。 - ThiefMaster
非常感谢您提供这个出色的答案。您所说的“我有一个后台守护进程”是指这个吗? - Accountant م
1
@Accountantم:我曾在“screen”会话中运行它(因此技术上不是守护程序);现在我可能会使用docker容器或systemd服务来运行它。最重要的是,我肯定不会再使用PHP了 ;) - ThiefMaster

4
更新很可能是通过cron作业完成的,或者另一个可能是在登录/任何页面更改时完成。带宽可能会有很大差异,这取决于用户活跃程度、可能性有多少等等因素。我认为你应该使用示例请求在localhost/test hist上进行测量,因为这非常取决于项目。
另外,如果将有相当数量的玩家等等,我建议不要使用PHP+MySQL编码,而是使用Python&PostgreSQL、甚至Java、或其他系统。

Cron 任务?这是否意味着他们必须每秒执行一次 Cron?因为它实际上是实时的。即使您不在线,其他玩家也可以实时看到其他玩家行动的结果。 - conradkleinespel
1
我认为这些是半实时的,可能每分钟左右更新一次。 - axiomer
当你对其他人的攻击“命中”时,你可以看到结果,所以它必须被存储在数据库中,并且立即执行,对吧?人们可以在攻击之前从一个账户向另一个账户派遣部队,因此它必须是实时的,或者至少他们的后端必须每秒检查一次变化,甚至更频繁。我说得对吗? - conradkleinespel
1
我从未玩过这些游戏,但我确信只有定时操作(攻击、部署等)使用 cron/event handler(由 ThiefMaster 提到),其他操作(开始攻击、部署)是通过点击本身完成的。至于定时操作,我不知道哪种更好,你需要决定是否必须是100%实时的。 - axiomer
2
为什么选择Python/PostgreSQL而不是PHP/MySQL?速度吗? - conradkleinespel
越快,语言更为简洁,如果以后想使用 Java(也更快),那么连接就更容易。负面的是 PHP 有更好的框架和更多的开发人员 - 如果是一个大项目(像这个一样),不管你有多么优秀,你可能会开发它,但 bugfixes 等不能在合理的时间内由一个人处理。 - axiomer

1

正如user1842120所说的那样:翁牛特实时是一种幻觉..

我将简单解释Web游戏中“实时”是如何工作的...

想象有3个玩家,其中2个在线..,P1攻击P3,当重新加载页面或更改页面时,脚本将被激活并攻击P3..

P3离线,他看不到攻击,但攻击正在发生。当P3上线时,P3会看到他/她的村庄正在被攻击,简单地说:

您只需要一个客户端(在线用户/浏览器在页面上)来运行游戏....


-3

我认为我会使用iframes和javascript来更新它们。就像一个隐藏的信息iFrame和输出iFrames,它们的url指向php并且一直在更新。


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