javascript - Nodejs - 防止 socket.io 降低帧速率

标签 javascript html node.js animation html5-canvas

我正在尝试在 html5 canvas 中编写一些动画。我需要在连接到我的服务器的任何其他客户端上重现动画。所以我要做的就是以字符串形式发送要调用的函数和参数,并在客户端调用 eval() 。这样,动画逻辑只需在一个 Canvas 上完成,而实际渲染内容的函数调用则由所有客户端执行。

但是,当我这样做时,我的帧速率急剧下降。我使用 socket.emit() 向服务器发送信号,服务器又调用 socket.broadcast.emit() 将字符串发送给所有客户端。这是渲染循环:

var rf = function()
{
   // clear background
   context.fillStyle = "#000";
   context.fillRect(0, 0, width, height);
   socket.emit('action', 'clearScreen', "{}");
   // mouse position to head towards
   var cx = (mousex - width / 2) + (width / 2),
       cy = (mousey - height / 2) + (height / 2);

   // update all stars
   var sat = Floor(Z * 500);       // Z range 0.01 -> 0.5
   if (sat > 100) sat = 100;
   for (var i=0; i<units; i++)
   {
      var n = stars[i],            // the star
          xx = n.x / n.z,          // star position
          yy = n.y / n.z,
          e = (1.0 / n.z + 1) * 2;   // size i.e. z

      if (n.px !== 0)
      {
         // hsl colour from a sine wave
         context.strokeStyle = "hsl(" + ((cycle * i) % 360) + "," + sat + "%,80%)";
         context.lineWidth = e;
         context.beginPath();
         socket.emit('action', 'context.beginPath', "{}");
         context.moveTo(xx + cx, yy + cy);
         socket.emit('action', 'context.moveTo', "{\"a\": [" + (xx + cx) + "," + (yy + cy) + "]}");
         context.lineTo(n.px + cx, n.py + cy);
         socket.emit('action', 'context.lineTo', "{\"a\": [" + (n.px + cx) + "," + (n.py + cy) + "]}");
         context.stroke();
         socket.emit('action', 'context.stroke', "{}");
      }

      // update star position values with new settings
      n.px = xx;
      n.py = yy;
      n.z -= Z;

      // reset when star is out of the view field
      if (n.z < Z || n.px > width || n.py > height)
      {
         // reset star
         resetstar(n);
      }
   }

   // colour cycle sinewave rotation
   cycle += 0.01;

   requestAnimFrame(rf);
};
requestAnimFrame(rf);

以上代码片段取自here .

您能提出防止帧速率下降的方法吗?我想如果 socket.emit 是非阻塞的,这是可以完成的。 发送再现帧的字符串是实现我想要的最简单的方法。发送像素就更重了。当框架易于绘制时,发送字符串效果很好 - 例如,上下移动的简单圆圈渲染效果很好。

最佳答案

我一直在走你现在正在走的路。这是一条有趣又有趣的路,但有时也是一条令人沮丧的路。 玩得开心并保持耐心!

好的...这里有一些提示:

  1. 所有绘图命令都必须是原子的。发送到任何客户端的每个命令都必须定义完整的绘图操作(从 beginPath 到描边的完整路径操作)。

  2. 让您的客户端变得聪明。为每个客户端提供至少足够的 JavaScript 智能,以便在给出基本体定义后绘制每个基本体形状。客户端函数:drawLine()、drawRect()、drawCircle()、drawBCurve()、drawQCurve()、drawText()等。

  3. 发射可能会丢失。这就是为什么仅发送原始上下文命令不是一个好主意的原因。在每个命令对象中包含一个序列索引#,并在处理每个命令数组后,将该新数组附加到主数组(主数组包含所有收到的数组)。这样客户端就可以识别并请求替换丢失的数据包。提示:您甚至可以使用这个主数组来重播整个动画;-)

以下是一些扩展我的提示的示例片段(未完成或未测试!):

在发出绘图命令的计算机上

// emits can be lost
// include an index# with each command so clients
// can request replacements for lost commands
var nextCommand=1;

// an array to hold all commands to be sent with the next emit
var commands=[];

// Example: push 1 atomic line command into the commands array
commands.push({
        op:'line',
        x0:xx+cx,
        y0:yy+cy,
        x1:n.px+cx,
        y1:n.py+cy,
        stroke:"hsl("+((cycle*i)%360)+","+sat+"%,80%)",
        fill:null,
        index:(nextCommand++),   
});

// Continue adding commands to be sent in this emit
// Push any more atomic drawing commands into commands[]
// You will probably generate many commands through a loop

// serialize the commands array and emit it
socket.emit(JSON.stringify(commands));

在每个客户端上

// context color changes are expensive
// Don't change the color if the context is already that color
// These vars hold the current context color for comparison
var currentStroke='';
var currentFill='';

// deserialize the incoming commands back into an array of JS command objects
var commands=JSON.parse(receivedCommands);

// process each command in the array
for(var i=0;i<commands.length;i++){

    var cmd=commands[i];

    // execute each command's atomic drawing based on op-type
    switch(cmd.op){
        case 'line':
            drawLine(cmd);
            break;
        // ... also 'circle','rect',etc.
    }

}

// draw a line defined by an atomic line drawing command
function drawLine(cmd){

    if(stroke){

        // execute primitive line commands
        context.beginPath();
        context.moveTo(cmd.x0,cmd.y0);
        context.lineTo(cmd.x1,cmd.y1);

        // Don't change the color if the context is already that color
        if(stroke!==currentStroke){
            context.strokeStyle=stroke;
            currentStroke=stroke;
        }

        // stroke the line (this completes an atomic line draw--beginPath thru stroke)
        context.stroke();
    } 

}

关于javascript - Nodejs - 防止 socket.io 降低帧速率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27757824/

相关文章:

html - 导航栏干扰标题 HTML/CSS

javascript - node.js 集群客户端能否在 fork 环境中接收深层对象或数组?

Node.js AWS-SDK SQS 内存泄漏

javascript - Google map 正在更改 map 中心

javascript - 多次单击可调用多个功能的按钮

html - 在 css 中连续居中 2 个图像

javascript - Firebase错误:Internal Given While Testing Callable Firebase Cloud Functions with Node Script

javascript - 前导下划线在 es6 类中转译错误

javascript - 为什么有两种不同的方法 slice() 和 substring()?

html - translateX 覆盖 translateY