画布动画循环

时间:2015-09-27 00:58:38

标签: javascript animation canvas

我正在继续制作运输系统模型的动画。代码构建工作站,用线连接它们,构建“pods”以沿着它们运行,然后计算随机起始站和终端站之间的最短路径。

jsfiddle

The problems I am having are 
a) the pods are traveling one at a time, rather than simultaneously.
b) the pod color is supposed to be related to the number of passengers, but this is clearly not happening.
c) I suspect I am producing a bottleneck in calculating the animation points, as it seems to run more hesitantly than it should.

我还希望能够标记每个吊舱的到来,以便重新加载,并开始新的旅程。

动画部分出了问题,但我无法解决问题。任何帮助将不胜感激!

animate();

var lastTime = 0;
var speed = 1; // higher is slower

function animate(time) {
    for (var i = 0; i < podArray.length; i++) {
        var aPod = podArray[i];
        // calculate incremental points along the path
        var points = calcWaypoints(aPod.wayStations);

        // return if the desired time hasn't elapsed
        if ((time - lastTime) < speed) {
            requestAnimationFrame(animate);
            return;
        }
        lastTime = time;

        //function animate(){
        ctx3.clearRect(0, 0, layer3.width, layer3.height);
        if (t < points.length - 1) {
            requestAnimationFrame(animate);
        }
        // draw pod from the last waypoint to the current waypoint

        ctx3.beginPath();
        ctx3.moveTo(aPod.startX, aPod.startY); //(points[t - 1].x, points[t - 1].y);
        ctx3.arc(points[t].x, points[t].y, 4, 0, Math.PI * 2, true);
        ctx3.fillStyle = aPod.color;
        ctx3.fill();
        t++;
    }

}

1 个答案:

答案 0 :(得分:2)

  • a)您的calcWaypoints函数采用的是一个参数,这是一个Waystation列表,然后您忽略该参数并计算所有pod的所有点。这是创建所有点的一个大数组,从第一个pod点开始,然后是第二个点,等等。这就是为什么它从第一个开始,然后是第二个,然后是第三个。

    function calcWaypoints(nextArray) {
        var frams = 100;
        var waypoints = [];
    
        for (var i = 1; i < nextArray.length; i++) {
            var pt0 = nextArray[i - 1];
            var pt1 = nextArray[i];
            var dx = pt1[0] - pt0[0];
            var dy = pt1[1] - pt0[1];
    
            for (var j = 0; j < frams; j++) {
                var x = pt0[0] + dx * j / frams //+ dxOff;
                var y = pt0[1] + dy * j / frams //+ dyOff;
                waypoints.push({
                    x: x,
                    y: y
                });
            };
        }
    
        return waypoints;
    }
    
  • b)这与前一个原因相同,因为您对每个窗格使用相同的点,所以窗格会相互叠加。此外,您正在清除每个点之间的画布。这个明确应该移出循环。 ctx3.clearRect(0, 0, layer3.width, layer3.height);

  • c)由于某种原因,您每次调用动画时都会重新计算所有点数。你应该先计算一次,然后不要动画。您还在循环中创建了对requestAnimationFrame的过多调用。

我在上面修改了一些上述更改并且正在运行。你还应该把它清理得更多:

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);
    };
})();

//STATIONS*************************************
var station = [
    ['A', 150, 100],
    ['B', 300, 100],
    ['C', 200, 175],
    ['D', 100, 250],
    ['E', 300, 250],
    ['G', 400, 250],
    ['F', 350, 200],
    ['Airport', 500, 200],
    ['Central', 500, 350]
];

function draw2() {
    for (var i = 0; i < station.length; i++) {
        var radius = 10;
        ctx2.beginPath();
        ctx2.arc(station[i][1], station[i][2], radius, 0, 2 * Math.PI);
        ctx2.stroke();
        ctx2.fillStyle = 'yellow';
        ctx2.fill();
        //ADD STATION LETTERS
        ctx2.font = '10pt Calibri';
        ctx2.fillStyle = 'black';
        ctx2.textAlign = 'center';
        ctx2.fillText(station[i][0], station[i][1], (station[i][2]) + 4);

    }
}
draw2();

//END STATIONS*************************************	
//START LINES**************************************
var lineArray = [
    ['A', 'B', ],
    ['B', 'A', 'C'],
    ['C', 'B', 'D', 'E'],
    ['D', 'C', 'E'],
    ['E', 'D', 'F', 'G', 'Central'],
    ['F', 'E', 'G'],
    ['G', 'F', 'E', 'Airport'],
    ['Airport', 'G', 'Central'],
    ['Central', 'E', 'Airport']
];


function drawLines() {
        for (m = 0; m < lineArray.length; m++) {
        ctx1.lineWidth = 1;
        ctx1.beginPath();
        for (p = 1; p < lineArray[m].length; p++) {
            var startStat = lineArray[m][0];
            var stat = lookUp(startStat);
            var beginX = station[stat][1];
            var beginY = station[stat][2];
            ctx1.moveTo(beginX, beginY);

            var endStat = lineArray[m][p];
            var endSt = lookUp(endStat);
            var closeX = station[endSt][1];
            var closeY = station[endSt][2];
            ctx1.lineTo(closeX, closeY);
        }

        ctx1.stroke();
    }
}
drawLines();
//END LINES*************************************

//SHORTEST PATH*********************************
function Graph() {
    var neighbors = this.neighbors = {}; // Key = vertex, value = array of neighbors.

    this.addEdge = function (u, v) {
        if (neighbors[u] === undefined) { // Add the edge u -> v.
            neighbors[u] = [];
        }
        neighbors[u].push(v);
        if (neighbors[v] === undefined) { // Also add the edge v -> u in order
            neighbors[v] = []; // to implement an undirected graph.
        } // For a directed graph, delete
        neighbors[v].push(u); // these four lines.
    };

    return this;
}


function shortestPath(graph, source, target) {
    var stationPath = [];
    var coordPath = [];
    if (source == target) { // Delete these four lines if
        print(source); // you want to look for a cycle
        return; // when the source is equal to
    } // the target.
    var queue = [source],
        visited = {
            source: true
        },
        predecessor = {},
        tail = 0;
    while (tail < queue.length) {
        var u = queue[tail++], // Pop a vertex off the queue.
            neighbors = graph.neighbors[u];
        for (var i = 0; i < neighbors.length; ++i) {
            var v = neighbors[i];
            if (visited[v]) {
                continue;
            }
            visited[v] = true;
            if (v === target) { // Check if the path is complete.
                var path = [v]; // If so, backtrack through the path.
                while (u !== source) {
                    path.push(u);
                    u = predecessor[u];
                }
                path.push(u);
                path.reverse();
                print(path.join(' &rarr; '));
                //console.log('Path: ' + path);

                for (s = 1; s < path.length; s++) {
                    stationPath.push(path[s]);
                }
                //console.log('Waypoints: ' + stationPath);
                for (t = 0; t < stationPath.length; t++) {
                    staCo = lookUp(stationPath[t]);
                    staCoX = station[staCo][1];
                    staCoY = station[staCo][2];
                    coordPath.push([staCoX, staCoY]);
                }
                //console.log(coordPath);
                return coordPath;
            }
            predecessor[v] = u;
            queue.push(v);
        }

    }
    print('there is no path from ' + source + ' to ' + target);
}

function print(s) { // A quick and dirty way to display output.
    s = s || '';
    document.getElementById('display').innerHTML += s + '<br>';
}

function findShortestPath(s1, s2) {
    var graph = new Graph();
    for (w = 0; w < lineArray.length; w++) {
        var baseStation = lineArray[w][0];
        for (z = 1; z < lineArray[w].length; z++) {
            graph.addEdge(baseStation, lineArray[w][z]);
        }
    }
    return (shortestPath(graph, s1, s2));
};


function lookUp(sta) {
    //console.log(sta);
    for (n = 0; n < station.length; n++) {
        if (sta == station[n][0]) {
            return n;

            break;
        }
    }
}

//BUILD PODS*************************************
var podArray = [];

function Pod(startX, startY, wayStations, riders, color) {
    this.startX = startX;
    this.startY = startY;
    this.wayStations = wayStations;
    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;
}

//PROGRAM PODS*********************************************	
for (i = 0; i < 3; i++) { //NUMBER OF PODS
    //Start Station
    var startOff = Math.floor(Math.random() * station.length);
    var begSta = station[startOff][0];
    var fromX = station[startOff][1];
    var fromY = station[startOff][2];
    //END STATION	
    var destNum = Math.floor(Math.random() * station.length);
    while (startOff == destNum) {
        destNum = Math.floor(Math.random() * station.length);
    }
    var endSta = station[destNum][0];

    function getWayStations(beg, end) {
        var fsp = findShortestPath(beg, end);
        var nextArray = [];
        nextArray.push([fromX, fromY]);
        for (var f = 0; f < fsp.length; f++) {
            nextArray.push(fsp[f]);
        }
        return nextArray;
    }

    //LOAD POD DATA
    podArray.push(new Pod(
    startX = fromX,
    startY = fromY,
    wayStations = getWayStations(begSta, endSta),
    riders = randomPass(),
    color = colorArray[riders - 1]))
}

//END PROGRAM PODS*********************************************	

// calc waypoints traveling along nextArray
function calcWaypoints(nextArray) {
    var frams = 100;
    var waypoints = [];

    for (var i = 1; i < nextArray.length; i++) {
        var pt0 = nextArray[i - 1];
        var pt1 = nextArray[i];
        var dx = pt1[0] - pt0[0];
        var dy = pt1[1] - pt0[1];

        for (var j = 0; j < frams; j++) {
            var x = pt0[0] + dx * j / frams //+ dxOff;
            var y = pt0[1] + dy * j / frams //+ dyOff;
            waypoints.push({
                x: x,
                y: y
            });
        };
    }

    return (waypoints);
}


animate();

var lastTime = 0;
var speed = 1; // higher is slower

function animate(time) {
    // return if the desired time hasn't elapsed
    if ((time - lastTime) < speed) {
        requestAnimationFrame(animate);
        return;
    }
    lastTime = time;
  
    ctx3.clearRect(0, 0, layer3.width, layer3.height);
    
    var callAgain = false;
    
    for (var i = 0; i < podArray.length; i++) {
        var aPod = podArray[i];
        // calculate incremental points along the path
        var points = calcWaypoints(aPod.wayStations);

        if (t < points.length - 1) {
            callAgain = true;
        }
        
      // draw pod from the last waypoint to the current waypoint
        if(points.length > t){
            ctx3.beginPath();
            ctx3.moveTo(aPod.startX, aPod.startY); //(points[t - 1].x, points[t - 1].y);
            ctx3.fillStyle = aPod.color;
            ctx3.arc(points[t].x, points[t].y, 4, 0, Math.PI * 2, true);
            ctx3.fill();
        }
       
    }
	t++;
    
    if(callAgain) requestAnimationFrame(animate);
}
<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>
<div id="display">
    </id>