【问题标题】:Node.js async setInterval game loop?Node.js 异步 setInterval 游戏循环?
【发布时间】:2012-06-12 13:29:12
【问题描述】:

我有一个多人游戏大厅,用户可以在其中创建私人聊天室并开始私人游戏。每个用户在游戏中都有一个生命条,假设它每秒缓慢地再生 x 点。

我想我需要在每个游戏开始时启动服务器端游戏循环,就像这样:

setInterval(update('gameID'),1000);

update('gameID') 增加特定游戏中所有玩家的健康变量,其中 1000 毫秒 = 1 秒。

问题:我可以假设这是异步的吗?我可能有 50 个单独的游戏正在进行,其中 50 个正在运行。主进程不会被阻塞吧?

【问题讨论】:

    标签: node.js


    【解决方案1】:

    它是异步的,但在您描述的情况下,您不需要 50 个计时器。

    1. 您可以使用单个计时器来重新生成活跃游戏中的玩家。如果您还要推送健康数据,这将非常低效。
    2. 您可以执行player.attackedTime = (new Date).getTime() 之类的操作并计算每次攻击的再生(例如player.health += x_points * ((new Date).getTime() - player.attackedTime) / 1000),但您必须在客户端上进行预测再生。

    【讨论】:

    • 多哈。是的,我可以只运行一个 setInterval(update(),1000) 并让 update() 在所有活动游戏中重新生成所有玩家的健康状况。我想我需要一个在所有与玩家健康点有关的操作上调用的“updateHealth()”函数?不仅是攻击,而且还会受到陷阱等的治疗或伤害。在客户端,只需显示一个“虚拟”预测健康值,当调用“updateHealth()”时该值与权威服务器端值同步。
    • 您如何更新健康取决于您决定如何在服务器上存储/抽象游戏状态。您将希望在无法预测的健康变化(攻击、治疗等)上更新客户端,但可以预测再生以防止频繁同步,如果您的游戏需要这种计时精度,您甚至可以考虑延迟。
    • 现在它只是 app.js 中的一个数组“var games = []”。创建游戏时会创建一个条目:例如游戏['newGameName'] = {“一个”:{健康:50}}。所以如果玩家一被治愈了 20 次,我会做一个 games['newGameName'].One.health += 20 etc.
    • 根据您的游戏节奏(以及数据对玩家的重要性)存在一些复杂性,这将影响同步策略的好坏。此外,请确保如果一次攻击耗尽了生命值,您会在诸如再生之类的错误使他活着之前杀死玩家,例如排队操作可能会导致这种情况。
    • 没问题。澄清一下,在类似于回合制游戏的游戏中,您可以同步大多数动作并适应服务器负载以及状态准确性,为频繁更改的集群保留“间隔”同步。如果您的游戏以任何方式奖励玩家(金币等),那么这些数据比聊天消息更重要,因此可以使用同步策略的组合。祝游戏好运!
    【解决方案2】:

    它是异步的。但是这样做可能会杀死您的服务器。

    我建议将这些间隔设为被动,即将游戏开始时保存在内存中并让客户端 ping 数据。当客户端 ping 服务器检查当前日期并将其与存储的日期进行比较(并在请求结束时更新存储的日期)。它可以从中评估当前的健康状况。

    此解决方案应该可以更好地扩展。

    【讨论】:

    • 拥有一个调用服务器端“updateHealth()”函数的 setInterval 客户端是否足够高效?或者我应该计算所有可能修改生命值的动作(攻击、治疗等),并确保它们在使用时调用“updateHealth()”。然后,对同一活动游戏中所有玩家(最多 4 个)的所有健康值进行客户端预测。
    • 我认为你应该解雇客户端setInterval,但不要太频繁。您可以让客户端计算健康状况,并且每 5 秒(或更少)调用一次服务器端 synchronize 函数,该函数评估真实健康状况(和其他值)并将其发送回客户端,客户端更新数据。我就是这样做的,但也许还有其他更好的方法。
    • 在攻击、治疗其他玩家等动作时必须调用同步函数对吧?服务器需要更新运行状况,然后应用更改。我想当我这样做时,我应该将重新生成间隔更改为 5 秒以帮助减少服务器负载。 :p
    • 是的,完全正确。另外,您可以在客户端缓存上次更新日期,并仅在必要时触发同步。例如:var t = setTimeout(synchronize, 5000);,当一个事件出现时(例如有人攻击你)你做clearTimeout(t); t = setTimeout(synchronize, 5000);,因为你在事件发生的同时同步。在synchronize 函数中,您再次将超时设置为相同的变量t。您不想在有操作时触发同步,这会稍微减少服务器负载。 :)
    • 啊...非常好的建议。感谢非常详细的讨论。 :)
    【解决方案3】:

    setInterval 当然是异步的。大多数接受回调的函数都是异步的。如果您有任何疑问,可以查看文档或源代码。

    【讨论】:

    • 我对 Node.js 和服务器端脚本很陌生,所以我要和你们仔细检查一下我的理解。很高兴知道我没有把这件事搞得一团糟。感谢您的快速响应。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-29
    • 2015-04-11
    • 1970-01-01
    • 1970-01-01
    • 2015-02-27
    • 2017-06-16
    相关资源
    最近更新 更多