在 Node 服务器上运行 Matter.js [英] Running Matter.js on a Node server
问题描述
我正在尝试运行一个在服务器上运行物理模拟的服务器,并让客户端通过 websockets/socket.io 连接到该服务器.我知道我可以使用 Matter.js 将引擎与渲染分开计算.所以我的问题是,如何将引擎数据提供给客户端?
I'm trying to run a server that runs a physics simulation on a server and have clients connect to this server via websockets/socket.io. I know I can calculate the Engine separately from the rendering with Matter.js. So my question is, how do I get the engine data to the client?
我有一个 Game
类,并且在套接字连接上,我想将 World
发送到客户端进行渲染.
I have a Game
class, and on socket connection, I want to emit the World
to the client to render.
var g = new Game()
g.initEngine()
io.sockets.on('connection', function(socket) {
io.emit('gamestate', g.getGameState())
});
在游戏状态下,我真的不确定要传递什么:
In the game state, I'm not really sure what to pass:
var Game = function(Player1, Player2) {
var self = this
this.gameID = 22
this.engine = null
this.world = null
// Get game state - WHAT DO I SEND HERE!??
this.getGameState = function() {
return self.engine
}
// Create the engine
this.initEngine = function() {
self.engine = M.Engine.create();
self.world = self.engine.world;
self.world.gravity.x = 0;
self.world.gravity.y = 0;
M.Engine.update(self.engine, 122000 / 60);
}
}
当我尝试通过 self
或 self.engine
或 self.world
时,我只是使应用程序崩溃.它说已超出最大调用堆栈大小.
When I try pass self
, or self.engine
, or self.world
, I just crash the app. It says Maximum call stack size exceeded.
我需要从 self.engine
中提取哪些数据才能通过 WebSockets 整齐地发送到客户端?
What data do I need to extract from self.engine
to send to the client neatly over WebSockets?
我知道我需要身体的位置数据.但即使我尝试
I know I need position data of the bodies. But even when I try
return self.engine.world.bodies;
然后它也会崩溃.
如何在不崩溃或不超过堆栈大小的情况下简单地将引擎/世界提供给客户端?
How can I simply get the engine/world to the clients without crashing or exceeding stack size?
推荐答案
如果服务器负责运行 matter.js 引擎,那么将 matter.js 对象从服务器发送到客户端可能是不必要的,而且成本高得令人望而却步.
If the server is responsible for running the matter.js engine, it's likely unnecessary and prohibitively expensive to send matter.js objects from the server to clients.
>
一种可能的设计是让服务器发出客户端在每个刻度上呈现游戏状态所需的最少量序列化信息.这是特定于应用程序的,但可能归结为从您的 mjs 主体中挑选顶点并将玩家位置、移动、得分等通知给客户端.
One possible design is for the server to emit a minimum amount of serialized information needed by the clients to render the game state on each tick. This is application-specific, but probably boils down to picking vertices from your mjs bodies and informing the clients of player positions, moves, scores, etc.
一旦客户端收到状态,他们就负责渲染它.这可以通过 matter.js、canvas、p5.js、纯 HTML 或其他任何东西来完成.客户端还负责向服务器报告游戏相关的鼠标和键盘操作,以供游戏引擎逻辑使用.
Once the client receives state, they are responsible for rendering it. This could be done with matter.js, canvas, p5.js, plain HTML or anything else. Clients are also responsible for reporting game-relevant mouse and keyboard actions to the server to be used by the game engine logic.
这里有一个最小的、完整的例子,说明它是如何工作的:
Here's a minimal, complete example of how this might work:
{
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"express": "^4.17.1",
"matter-js": "^0.16.1",
"socketio": "^1.0.0"
},
"engines": {
"node": "12.x"
}
}
server.js
:
const express = require("express");
const Matter = require("matter-js");
const app = express();
const http = require("http").createServer(app);
const io = require("socket.io").listen(http);
const frameRate = 1000 / 30;
const canvas = {width: 300, height: 200};
const boxes = 20
const boxSize = 20
const wallThickness = 20
const entities = {
boxes: [...Array(boxes)].map(() =>
Matter.Bodies.rectangle(
Math.random() * canvas.width,
boxSize,
Math.random() * boxSize + boxSize,
Math.random() * boxSize + boxSize,
)
),
walls: [
Matter.Bodies.rectangle(
canvas.width / 2, 0,
canvas.width,
wallThickness,
{isStatic: true}
),
Matter.Bodies.rectangle(
0, canvas.height / 2,
wallThickness,
canvas.height,
{isStatic: true}
),
Matter.Bodies.rectangle(
canvas.width,
canvas.width / 2,
wallThickness,
canvas.width,
{isStatic: true}
),
Matter.Bodies.rectangle(
canvas.width / 2,
canvas.height,
canvas.width,
wallThickness,
{isStatic: true}
),
]
};
const engine = Matter.Engine.create();
Matter.World.add(engine.world, [].concat(...Object.values(entities)));
const toVertices = e => e.vertices.map(({x, y}) => ({x, y}));
setInterval(() => {
Matter.Engine.update(engine, frameRate);
io.emit("update state", {
boxes: entities.boxes.map(toVertices),
walls: entities.walls.map(toVertices),
});
}, frameRate);
io.on("connection", socket => {
socket.on("register", cb => cb({canvas: canvas}));
socket.on("player click", coordinates => {
entities.boxes.forEach(box => {
// https://stackoverflow.com/a/50472656/6243352
const force = 0.01;
const deltaVector = Matter.Vector.sub(box.position, coordinates);
const normalizedDelta = Matter.Vector.normalise(deltaVector);
const forceVector = Matter.Vector.mult(normalizedDelta, force);
Matter.Body.applyForce(box, box.position, forceVector);
});
});
});
app.use(express.static("public"));
app.get("/", (req, res) =>
res.sendFile(__dirname + "/views/index.html")
);
http.listen(process.env.PORT, () =>
console.log("http listening on " + process.env.PORT)
);
index.html
:
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script>
const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
const ctx = canvas.getContext("2d");
const socket = io();
const draw = (body, ctx) => {
ctx.beginPath();
body.forEach(e => ctx.lineTo(e.x, e.y));
ctx.closePath();
ctx.fill();
ctx.stroke();
};
socket.once("connect", () => {
socket.emit("register", res => {
canvas.width = res.canvas.width;
canvas.height = res.canvas.height;
});
});
socket.on("update state", ({boxes, walls}) => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "#111";
ctx.strokeStyle = "#111";
walls.forEach(wall => draw(wall, ctx));
ctx.fillStyle = "#aaa";
boxes.forEach(box => draw(box, ctx));
});
document.addEventListener("mousedown", e => {
socket.emit("player click", {x: e.offsetX, y: e.offsetY});
});
</script>
存在其他方法,将某些引擎逻辑转移到客户端可能具有优势,因此请将此视为概念证明.有关其他设计建议,请参阅这篇文章.
Other approaches exist and there can be advantages to shifting some of the engine logic to clients, so consider this a proof of concept. See this post for additional design suggestions.
这篇关于在 Node 服务器上运行 Matter.js的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!