【问题标题】:Multiplayer JavaScript game built with Node.JS - Separating players使用 Node.JS 构建的多人 JavaScript 游戏 - 分隔玩家
【发布时间】:2012-02-20 10:25:54
【问题描述】:

我有一个找不到答案的问题。

我正在尝试使用 Node.JS 和 Socket.IO 构建多人游戏。我已经建立了一个聊天室作为我的第一个实验,因此我可以进行广播等工作。现在我正处于想要使用 Canvas 进行某些工作的地步。

我遇到的问题是让我的头脑围绕着多个独立的玩家。我知道每个玩家都会将他们的 x,y 数据线发送到服务器,服务器会广播这些数据,但是客户端如何知道要显示多少玩家,我猜他们必须存储在某个地方的数组中。

【问题讨论】:

    标签: javascript node.js canvas socket.io


    【解决方案1】:

    我的实现将非常天真和简化,没有延迟补偿、外推等,但它应该指出节点“多人游戏”的一般概念。

    我认为最简单的方法是在客户端和服务器上都有一个包含玩家(实体)的关联数组。然后从客户端发送{action: "move", target:[32, 100]} 之类的命令,并使用服务器逻辑(运行真实游戏的位置)处理此命令。对于每个套接字on connection,您应该分配一个播放器对象或 id,以便您可以像这样访问它:

    var lastPlayerID = 0;
    var players = {};
    
    server.on("connection", function(socket) {
    
      var newcommer = new Player({id: lastPlayerID});      
      players[lastPlayerID] = newcommer;
      socket.player = newcommer; // or lastPlayerID
      lastPlayerID++;      
    
      socket.onMessage = function(message) {
        this.player.doSomething(); 
      }
    
    });
    

    然后假设每个 100 毫秒,您可以向所有连接的玩家发送快照:

    {
      timestamp: game.delta,
      players: {
        1: {x: 32, y: 100},
        2: {x: 14, y: 11}
      }
    }
    

    然后在客户端接收数据并从旧值插入到新值。

    // duration in this simplified example is snapshot sending interval in [ms]
    Player.prototype.interpolateTo = function(data, duration) {
      if(typeof data.x != "undefined") {
        // step needed to get `destination x` within `duration` miliseconds
        this.stepValues.x = Math.abs(data.x - this.x) / duration;
        this.target.x = data.x;
      } 
      // ...
    }
    
    // step you call for each game loop iteration
    Player.prototype.step = function(delta) {
      if(this.x < this.target.x) {
        this.x += delta * this.stepValues.x
      }
    }
    

    对于最多包含 20 个对象的半街机游戏来说,这是一个足够的算法。减少快照的间隔使其几乎适合具有更多对象的策略游戏。您的主要敌人是带宽使用,您可以减少带宽使用以最小化数据包的大小。例如阅读 BiSON、LZW 并不要发送自上次快照以来未更改的数据。

    我的名声不允许我发布所有链接,所以我将它们附在此处: http://pastebin.com/Kh3wvF1D

    Glenn Fiedler 对多人游戏概念的一般介绍:

    http://gafferongames.com/networking-for-game-programmers/what-every-programmer-needs-to-know-about-game-networking/

    Quake 中的一些多人游戏技巧: 这将为您提供有关插值和外推(预测)的线索

    http://fabiensanglard.net/quakeSource/quakeSourcePrediction.php

    Valve 关于延迟补偿和一般优化的文章:

    https://developer.valvesoftware.com/wiki/Latency_Compensating_Methods_in_Client/Server_In-game_Protocol_Design_and_Optimization

    帝国时代的多人游戏技巧:

    http://zoo.cs.yale.edu/classes/cs538/readings/papers/terrano_1500arch.pdf#search=%22Real%20time%20strategy%20networking%20lockstep%22

    你也可以阅读我关于优化带宽使用的文章

    http://rezoner.net/minimizing-bandwidth-usage-in-html5-games-using-websocket,299

    +1 对于 Ivo 的 Wetzel Mapple.js,这是一大堆知识。

    https://github.com/BonsaiDen/Maple.js

    【讨论】:

    • 欢迎来到 Stackoverflow!很好的答案,继续这样下去,你的缺乏代表不应该是一个很长时间的问题。 :)
    • 谢谢你这么详细的解释:)
    【解决方案2】:

    玩家不会将他们的 x,y 坐标发送到服务器,这将允许通过手动发送坐标来作弊。

    每个玩家向服务器发送“左/右/上/下移动”事件。然后服务器更新位置并定期广播所有玩家的位置(或位置的增量)。

    然后每个客户端获取所有这些播放器增量并呈现它们。在客户端实现方面,我会有某种 Board/Map 对象,它会有一个 RenderableEntities 列表。然后,我只需使用新位置更新 RenderableEntities 并定期重绘所有实体。

    我建议你看看Maple.js

    【讨论】:

    • 啊当然。感谢您的解释。因此,逻辑将位于服务器上,并向玩家广播新的位置。我会广播一个数组或对象,然后在客户端循环显示吗?我会看看 Maple.js 谢谢 :)
    • @Henryz 出于效率目的,您只广播已更改位置的对象,并且您只广播位置的实际差异而不是整个位置。数据结构由你决定,元组对象很好{ id: [x, y], otherid: [x, y] }
    • 恐怕我正试图让 Maple.js 演示运行,但它根本不起作用。在过去 3 年中没有 repo 更新。还有其他可以在客户端和服务器之间实现这种同步更新的建议吗?
    【解决方案3】:

    同步每个玩家的 X 和 Y 坐标的另一种方法是使用Lance。 它是一个开源的 JavaScript 库,可通过权威服务器处理多个玩家的位置校正。

    如果您需要同步坐标以外的其他内容,例如对象名称或头像属性,这将非常有用。或者,如果您的球员有速度。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-16
      • 1970-01-01
      相关资源
      最近更新 更多