2015-08-17 149 views
0

我正在模擬一個城市交通系統,並試圖提高我的Javascript和帆布技能。我在這裏提供一個最基本的版本:https://jsfiddle.net/ftmzm9vp/畫布動畫速度

兩個問題:

1)我想要的「豆莢」以均勻的速度運行。現在他們都在同一時間到達目的地,這意味着他們以不同的速度旅行。我該如何糾正?

2)顯然我需要做更多的事情 - 讓豆莢沿着現有的線路行進,找出到達目的地的最佳路徑,擴大線路和站點的數量 - 所有這些都將增加計算量高架。現在,隨着我想要使用的500個豆莢,動畫開始爬行。我重寫了所有的東西來使用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> 

回答

1

您的車輛都會同時到達目的地,因爲您正在根據百分比更改其位置。所以當pct == 1.00時,所有車輛都會同時到達自己的終點,無論他們需要前往哪裏才能到達目的地。

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

爲了使車輛到達時根據行駛距離

問題1:你可以計算出各航點(航點==獨特的像素)的車輛必須到完成它的路線。使用每個新的動畫幀將車輛前進到下一個航點。這導致每輛車根據其路線的長度而不是統一的百分比到達。

問題2:對於每輛車,如果您預先計算&將它的航點保存到一個數組中,您可以輕鬆地在每個動畫幀中獲取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>

+0

仍試圖獲得畫布的邏輯。這次真是萬分感謝! – Tyler330

+0

我試着調整你的代碼,但不能讓它畫任何東西到屏幕上。我錯過了什麼? [鏈接](https://jsfiddle.net/yL8udg9r/) – Tyler330

1

爲了使你的豆莢具有相同的速度,你可能會想使用畢達哥拉斯定理。 Hypotenuse是每次RAF出現時希望節點行進的距離。然後從中計算出你的x和y。

我不太確定我是否理解pct的功能。

爲加快皇家空軍你會想:

  1. 殺了你設定的超時
  2. 預渲染

Prerending有點更多的工作,但不是繪製每個圓圈每你有畫布不在你繪製的DOM中。然後,您基本上在可見的DOM畫布上放置「隱藏」畫布。它通過這種方式將繪圖保存在內存中。

您還在for循環的末尾繪製畫布上的每個圓。將填充方法拉到它之外,這樣畫布可以批量繪製,而不是一堆小小的調用(這可以真正殺死性能)。

每次設置字體的東西都可以刪除。

畫布非常棒,但你只需要小心,因爲一個小小的錯誤會導致巨大的瓶頸。

這是一個很好的文章:http://www.html5rocks.com/en/tutorials/canvas/performance/

還是讓我知道,如果你有任何問題。

+0

我會考慮這一點。我曾看過它,但沒有試圖實施它。 – Tyler330