pixiJS 和 socket.io 如何协同工作?(一般问题) [英] How pixiJS and socket.io can work togheter? (General question)

查看:20
本文介绍了pixiJS 和 socket.io 如何协同工作?(一般问题)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从 pixiJS 开始,遵循这本书:学习 Pixi.js为游戏和网络创建出色的交互式图形"- 雷克斯范德斯皮.我了解基本游戏的以下一般结构是如何工作的,

I am starting with pixiJS, following the book: "Learn Pixi.js Create Great Interactive Graphics for Games and the Web" - Rex van der Spuy . I understand how the following general structure of a basic game works,

let state = play;

function gameLoop() {
  requestAnimationFrame(gameLoop);
  state();
  renderer.render(stage);
}
function play() {
//Do something
}

我不知道如何修改上述内容以包含客户端-服务器通信.我想为此使用 soket.io 库.我想通过与用户的交互来改变游戏的状态.用户按下按钮,向服务器发出请求,服务器接收它并发送一些数据作为响应,客户端接收该数据并继续游戏.但是 socket.io 通信是一个异步过程.如果我等待在 gameLoop 中接收到数据,那么在它从服务器到达之前,每当我想使用它时,游戏肯定会崩溃.我应该如何与 gameLoop 一起实现套接字通信,以便使用来自服务器的数据正确更新游戏状态?谢谢,感谢您提出任何有用的意见.

What I don't know is how to modify the above to include client-server communications. I want to use the soket.io library for this purpose. I want to change the state of the game through interaction with the user. The user presses a button, a request is fired to the server, the server receives it and sends some data in response, the client receives that data and the game continues. But socket.io communication is an asynchronous process. If I wait for the data to be received within the gameLoop, the game will surely crash whenever I want to use it before it arrives from the server. How should I implement socket communication together with the gameLoop so that the state of the game is correctly updated with the data that comes from the server? Thanks, I appreciate any helpful comments.

推荐答案

我在这里看到两个问题:

I see two problems here:

在您粘贴到问题中的代码片段中,您的游戏逻辑(state()"调用)与渲染逻辑/动画相关联.这样游戏逻辑更新(状态)需要等待渲染,渲染需要等待游戏逻辑更新.还有如果例如:游戏逻辑更新"非常繁重,应该每 0.2 秒调用一次 - 所以不像每秒发生约 60 次(60 FPS)的渲染那样频繁?

In the code snippet which you pasted in your question your game logic ("state()" call) is tied to rendering logic / animation. This way the game logic update (state) needs to wait for rendering, and rendering needs to wait for game logic update. Also what if for example: the "game logic update" is very heavy and should be called every 0.2 seconds - so not so often as rendering which happens ~60 times per seconds (60 FPS)?

可以帮助解决这个问题的是有 2 个独立的循环 - 让我们称之为:游戏逻辑循环";和动画循环".

What can help to solve this issue is to have 2 independent loops - lets call them: "game logic loop" and "animation loop".

function gameLogicLoop() 
  updateState();
  setTimeout(function () { gameLogicLoop(); },  200); // ms
}

function animationLoop() {
  prepareStageFromState();
  requestAnimationFrame(gameLoop);
  renderer.render(stage);
}

// start both loops:
gameLogicLoop();
animationLoop();

这样 animationLoop() 每秒调用 60 次,gameLogicLoop() 每秒调用 5 次(每 0.2 秒).

This way the animationLoop() is called ~60 times per second, and gameLogicLoop() 5 times per second (every 0.2 seconds).

当你使用这种方法时,你应该遵守以下规则:

When you use such approach then you should respect following rules:

  • gameLogicLoop() 中发生的任何事情都不应修改渲染/动画/图形.例如,您可以在这里:
    • 改变玩家的金币数量
    • 改变玩家在游戏地图中的位置(例如:从 D3 块移动到 D4 块" - 而不是屏幕上的像素 x/y")
    • 在地图等上创建新的怪物
    • whatever happens in gameLogicLoop() should not modify rendering / animation / graphics. Here you can for example:
      • change gold amount of player
      • change position of player in game map (like: "moving from tile D3 to tile D4" - not "pixel x/y" on screen)
      • create new monsters on map etc.
      • 在屏幕上绘制金币计数器(您从游戏状态数据中获取金币数量)
      • 动画玩家从 D3 到 D4 的移动(您可以从游戏状态数据中的图块计算像素 x/y)
      • 在地图上显示新怪物(可能带有一些动画).

      作为一个例子,请检查这个简单的脚本:https://jsfiddle.net/urvdhw8b/

      As an example please check this simple script: https://jsfiddle.net/urvdhw8b/

      • 注意 gameLogicLoop 函数 - 处理游戏状态数据的更新(每 1 秒).
      • 注意 animationLoopprepareStageFromState 函数 - 处理渲染 (~60 FPS).
      • 另外,游戏状态数据通过以下方式修改:
      • notice gameLogicLoop function - handles update of game state data (every 1 second).
      • notice animationLoop and prepareStageFromState functions - handles rendering (~60 FPS).
      • additionally game state data is modified by:
          // Click on circle should increase number of lumberjack huts:
          circle.on('click', function(event) {
              lumberjackHutCount++;
          });
      

      点击"单击圆圈时增加伐木工人小屋数量的事件正在外面"发生两个循环 - 因为是独立的异步事件(鼠标单击).我们也可以将其归类为游戏逻辑.

      The "on click" event which increases number of lumberjack huts when circle is clicked is happening "outside" of both loops - because is independent asynchronous event (mouse click). We can classify this as game logic too.

      用户按下一个按钮,一个请求被发送到服务器,服务器接收它并发送一些数据作为响应,客户端接收该数据并且游戏继续.但是socket.io通信是一个异步过程.

      The user presses a button, a request is fired to the server, the server receives it and sends some data in response, the client receives that data and the game continues. But socket.io communication is an asynchronous process.

      您可以使用事件(类似于上面的circle.on('click'...)和gameLogicLoop() 来处理这个问题.animationLoop() 不应处理任何客户端/服务器通信或调用socket.io"等中的任何内容 - 它应该仅根据游戏状态数据在屏幕上呈现内容.

      You can handle this using events (similar as circle.on('click'... above) and in gameLogicLoop(). The animationLoop() should not handle any client/server communication or call anything in "socket.io" etc - it should just render things on screen basing on game state data.

      我们可以为伐木工人"创建以下事件:上面的脚本:

      We could create following event for the "lumberjack" script above:

      // on client side:
      socket.on("lumberjack_huts_updated", (data) => {
        lumberjackHutCount = data.newLumberjackHutCount;
      });
      
      
      // on server side:
      hutCount++;
      ...
      socket.emit("lumberjack_huts_updated", { newLumberjackHutCount: hutCount });
      

      这样客户端会收到lumberjack_huts_updated"来自服务器的消息,然后它将更新游戏状态数据(lumberjackHutCount 变量).这将异步发生 - 独立于 animationLoop().

      This way when client will receive "lumberjack_huts_updated" message from server then it will update game state data (lumberjackHutCount variable). This will happen asynchronously - independent from animationLoop().

      当然,这只是一个简单的例子,随着您的进步,您肯定会找到改进和优化它的新方法.例如:在客户端,您可以考虑对来自服务器的传入消息进行排队(将它们存储在某个数组中),然后在 gameLogicLoop() 中处理它们.

      Of course this is just simple example and for sure you will find new ways to improve and optimize it as you progress. For example: in the client you can consider queueing incoming messages from server (store them in some array), and then process them inside gameLogicLoop().

      这里有一些与此主题和多人游戏"相关的教程/文档/项目.- 这是利用客户端/服务器通信的游戏最流行的用例:

      Here you have few tutorials/docs/projects related to this topic and to "multiplayer" - which is most popular use case for games that utilize client/server communication:

      • 如何构建多人浏览器游戏"作者:Alvin Lin - (也是关于 socket.io):
      • "How To Build A Multiplayer Browser Game" by Alvin Lin - (is also about socket.io):
      1. 第 1 部分:https://hackernoon.com/how-to-build-a-multiplayer-browser-game-4a793818c29b
      2. 第 2 部分:https://medium.com/hackernoon/how-to-build-a-multiplayer-browser-game-part-2-2edd112aabdf

    • (也是 socket.io)https://github.com/huytd/agar.io-clone/wiki/Game-Architecture
    • https://github.com/adityaravishankar/last-colony
    • 在 Node.js 中编写多人文本冒险引擎":

    • (also socket.io) https://github.com/huytd/agar.io-clone/wiki/Game-Architecture
    • https://github.com/adityaravishankar/last-colony
    • "Writing A Multiplayer Text Adventure Engine In Node.js":

      1. https://www.smashingmagazine.com/2018/12/multiplayer-text-adventure-engine-node-js/
      2. https://www.smashingmagazine.com/2019/10/multiplayer-text-adventure-engine-node-js-part-2/?utm_source=gamedevjsweekly&utm_medium=email
      3. https://www.smashingmagazine.com/2019/10/multiplayer-text-adventure-engine-node-js-part-3/

    • https://github.com/js13kGames/js13kserver
查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆