javascript - Canvas 动画速度

标签 javascript html canvas

我正在构建一个城市交通系统的模拟,并试图提高我的 Javascript 和 Canvas 技能。我在这里提供了一个简单的版本:https://jsfiddle.net/ftmzm9vp/

两个问题:

1) 我希望“pod”以统一的速率运行。现在他们都同时到达目的地,这意味着他们以不同的速度行驶。我该如何纠正这个问题?

2)显然我还有更多要做的事——让 pods 沿着现有线路行驶,找出到达目的地的最佳路径,扩大线路和车站的数量——所有这些都会增加计算开销。现在,有了我想要使用的 500 个 Pod,动画就开始爬行了。我重写了整个过程以使用 requestAnimFrame,因为我认为它会更快,但它似乎并没有应有的顺利。我可以做些什么来改善这一点? 谢谢!

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<title>Pod Stations Lines Test</title>
<body>
    <canvas id="layer1" style="z-index: 2;  
                position:absolute;
                left:0px;
                top:0px;
                " height="600px" width="1000">This text is displayed if your browser does not support HTML5 Canvas.</canvas>
    <canvas id="layer2" style="z-index: 3;
                position:absolute;
                left:0px;
                top:0px;
                " height="600px" width="1000">This text is displayed if your browser does not support HTML5 Canvas.</canvas>
    <canvas id="layer3" style="z-index: 1;
                position:absolute;
                left:0px;
                top:0px;
                " height="600px" width="1000">This text is displayed if your browser does not support HTML5 Canvas.</canvas>
    <script>
        //Modified Source: http://jsfiddle.net/m1erickson/HAbfm/
        //
        layer1 = document.getElementById("layer1");
        ctx1 = layer1.getContext("2d");
        layer2 = document.getElementById("layer2");
        ctx2 = layer2.getContext("2d");
        layer3 = document.getElementById("layer3");
        ctx3 = layer3.getContext("2d");

        window.requestAnimFrame = (function(callback) {
            return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) {
                window.setTimeout(callback, 1000 / 60);
            };
        })();

        //STATION LIST
        var station = [
            ['A', 100, 50],
            ['B', 300, 50],
            ['C', 200, 150],
            ['D', 100, 250],
            ['E', 300, 250],
            ['F', 400, 250]
        ];


        //DRAW LINES
        function drawLines() {

            ctx1.clearRect(0, 0, layer3.width, layer3.height);

            var linkAB = ctx1.beginPath();
            ctx1.moveTo(station[0][1], station[0][2]);
            ctx1.lineTo(station[1][1], station[1][2]);
            ctx1.stroke();
            var linkBC = ctx1.beginPath();
            ctx1.moveTo(station[1][1], station[1][2]);
            ctx1.lineTo(station[2][1], station[2][2]);
            ctx1.stroke();
            var linkCD = ctx1.beginPath();
            ctx1.moveTo(station[2][1], station[2][2]);
            ctx1.lineTo(station[3][1], station[3][2]);
            ctx1.stroke();
            var linkDE = ctx1.beginPath();
            ctx1.moveTo(station[3][1], station[3][2]);
            ctx1.lineTo(station[4][1], station[4][2]);
            ctx1.stroke();
            var linkCE = ctx1.beginPath();
            ctx1.moveTo(station[2][1], station[2][2]);
            ctx1.lineTo(station[4][1], station[4][2]);
            ctx1.stroke();
            var linkEF = ctx1.beginPath();
            ctx1.moveTo(station[4][1], station[4][2]);
            ctx1.lineTo(station[5][1], station[5][2]);
            ctx1.stroke();

        }


        //CREATE PODS

        var podArray = [];

        function Pod(startX, startY, endX, endY, riders, color) {
            this.startX = startX;
            this.startY = startY;
            this.endX = endX;
            this.endY = endY;
            this.riders = riders;
            this.color = color;
        }

        var colorArray = ["gold", "orange", "red", "green", "blue", "black"];

        function randomPass() {
            occ = 1 + Math.floor(Math.random() * 6);
            return occ;
            console.log("Riders " + occ);
        }


        for (i = 0; i < 500; i++) {
            var origNum = Math.floor(Math.random() * station.length);
            var origin = {
                x: station[origNum][1],
                y: station[origNum][2]
            }
            var destNum = Math.floor(Math.random() * station.length);
            while (origNum == destNum) {
                destNum = Math.floor(Math.random() * station.length);
            }
            var destination = {
                x: station[destNum][1],
                y: station[destNum][2]
            }

            podArray.push(new Pod(
            startX = origin.x,
            startY = origin.y,
            endX = destination.x,
            endY = destination.y,
            riders = randomPass(),
            color = colorArray[riders - 1]

            ));
        }

        var pct = 0.00;
        var fps = 60;

        //CALL DRAWING AND ANIMATION
        drawLines();
        animate();

        function animate() {
            setTimeout(function() {

                if (pct <= 1.00) {
                    requestAnimFrame(animate)
                };

                // increment the percent (from 0.00 to 1.00)
                pct += .01;

                // clear the canvas
                ctx3.clearRect(0, 0, layer3.width, layer3.height);

                // draw all podArray
                for (var i = 0; i < podArray.length; i++) {

                    // get reference to next aPod
                    var aPod = podArray[i];

                    var dx = aPod.endX - aPod.startX;
                    var dy = aPod.endY - aPod.startY;
                    var nextX = aPod.startX + dx * pct;
                    var nextY = aPod.startY + dy * pct;

                    //create pod on screen
                    ctx3.fillStyle = aPod.color;
                    ctx3.beginPath();
                    ctx3.arc(nextX, nextY, 5, 0, Math.PI * 2, true);
                    ctx3.fillStyle = aPod.color;
                    ctx3.fill();
                    ctx3.closePath();

                    //STATION LETTERS

                    for (s = 0; s < station.length; s++) {
                        ctx2.font = '12pt Calibri';
                        ctx2.fillStyle = 'red';
                        ctx2.textAlign = 'center';
                        ctx2.fillText(station[s][0], station[s][1], (station[s][2]) + 4);
                    }

                }

            }, 1000 / fps);
        }
    </script>
</body>

最佳答案

您的车辆全部同时到达目的地,因为您根据百分比更改它们的位置。因此,当 pct==1.00 时,所有车辆同时到达自己的端点,无论它们需要行驶多远才能到达那里。

// increment the percent (from 0.00 to 1.00)
pct += .01;

根据行驶距离让车辆到达

问题#1:您可以计算车辆完成其路线所必须行驶的每个航点(航点==唯一像素)。使用每个新的动画帧将车辆推进到下一个路径点。这导致每辆车根据其路线长度而不是统一的百分比到达。

问题#2:对于每辆车,如果您预先计算其路径点并将其保存到数组中,则可以轻松地在每个动画帧期间在 Canvas 上绘制 500 辆车。

这里有注释和演示:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

ctx.lineWidth=2;

// define routes
var routes=[];
routes.push({
  points:linePoints({x:10,y:10},{x:150,y:10}),
  currentPoint:0,
  color:'red',
});
routes.push({
  points:linePoints({x:10,y:50},{x:250,y:65}),
  currentPoint:0,
  color:'green',
});
routes.push({
  points:linePoints({x:10,y:90},{x:325,y:105}),
  currentPoint:0,
  color:'blue',
});

// animation related vars
var lastTime=0;
var delay=1000/60*5;

// start animating
requestAnimationFrame(animate);

function animate(time){
  // return if the desired time hasn't elapsed
  if(time<lastTime){requestAnimationFrame(animate);return;}
  // redraw each route
  ctx.clearRect(0,0,cw,ch);
  // var used to stop animating if all routes are completed
  var isComplete=true;
  for(var i=0;i<routes.length;i++){
    var r=routes[i];
    // increase the currentPoint, but not beyond points.length-1
    if((r.currentPoint+1)<r.points.length-1){
      isComplete=false;
      r.currentPoint++;
    }
    // draw the route to its current point
    ctx.strokeStyle=r.color;
    ctx.beginPath();
    ctx.moveTo(r.points[0].x,r.points[0].y);
    ctx.lineTo(r.points[r.currentPoint].x,r.points[r.currentPoint].y);
    ctx.stroke();
    ctx.fillStyle=r.color;
    ctx.beginPath();
    ctx.arc(r.points[r.currentPoint].x,r.points[r.currentPoint].y,5,0,Math.PI*2);
    ctx.fill();
  }
  // request another frame unless all routes are completed
  if(!isComplete){
    requestAnimationFrame(animate);
  }
}

function linePoints(p1,p2){
  // start building a points array with the starting point
  var points=[p1];
  var dx=p2.x-p1.x;
  var dy=p2.y-p1.y;
  var count=Math.sqrt(dx*dx+dy*dy)*3;
  for(var pct=0;pct<count;pct++){
    // calc next waypoint on the line
    var x=p1.x+dx*pct/count;
    var y=p1.y+dy*pct/count;
    var lastPt=points[points.length-1];
    // add new waypoint if the its integer pixel value has
    // changed from last waypoint
    if(parseInt(x)!==parseInt(lastPt.x) || parseInt(y)!==parseInt(lastPt.y)){
      points.push({x:x,y:y});
    }
  }
  // force the last point to be the ending point
  points[points.length-1]=p2;
  // return a unique points[] forming a line from p1 to p2
  return(points);
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=350 height=300></canvas>

关于javascript - Canvas 动画速度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32054032/

相关文章:

javascript - 如何在 JavaScript 中迭代 map 数组列表?

javascript - 向内螺旋旋转矩阵

javascript - 通过 $POST 从 javascript 向 php 发送值

javascript - 是否可以创建一个 promise 循环,直到以 Angular 拒绝

javascript - 如何使用键盘向左/右/上/下移动球?

HTML – 悬停时显示菜单

javascript - node.js 的 raw_input 替代方案

html - 导航栏固定在 div 的顶部

javascript - 在通过 JavaScript 的 Canvas 中,如何获取对象的坐标,然后将该对象移动到不同的坐标?

android - 如果 Canvas 旋转,Canvas.getClipBounds() 会返回什么?