在 HTML5 画布中沿路径旋转移动对象

Rotating a moving Object along a path in HTML5 canvas

本文关键字:旋转 移动 对象 路径 布中沿 HTML5      更新时间:2023-09-26

我在画布元素的一层中创建了一个静态背景,然后尝试移动我创建的矩形对象以穿过圆柱体,管道,然后它应该落入管道末端的小圆柱体中。我可以沿直线移动它,但我必须旋转对象(例如 -25 度),然后使其水平移动(180 度,当它在管道内沿 y 方向行进时)。代码 :

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
</head>
<body>
<section>
<div id="canvasesdiv" style="position:relative; width:650px; height:600px">
<canvas id="layer1"
style="z-index: 1;
position:absolute;
left:0px;
top:0px;
" height="600px" width="650">
</canvas>
<canvas id="layer2"
style="z-index: 2;
position:absolute;
left:0px;
top:0px;
" height="600px" width="650">
</canvas>
</div>
<button onclick="start()">Start</button>
<button onclick="stop()">Stop</button>
<script type="text/javascript">

var requestId = 0;
var animationStartTime=0;
var speed=1;
var posX=160;  //for cylinder
var posY=posX+50;  //for cylinder 
var x=160; //for packets  
var y=230; //for packetsvar time=1000;
//var time=1000;
var layer1;
var layer2;
var ctx;
var ctx2;
var pack=setInterval(drawPacket,1500);
function packet(){
layer1 = document.getElementById("layer1");
ctx = layer1.getContext("2d");
layer2 = document.getElementById("layer2");
ctx2 = layer2.getContext("2d");
window.onload=drawScreen();
}
function animate() {
ctx2.clearRect(0,0,layer2.width,layer2.height);
requestAnimationFrame = window.mozRequestAnimationFrame    ||
              window.webkitRequestAnimationFrame ||
                window.msRequestAnimationFrame     ||
                window.oRequestAnimationFrame
                ;  
requestId = window.requestAnimationFrame(animate);
anime();
}
function anime(){
if ( x>=0 || x<=445){
drawPacket();
x+=speed;
}
if( posXX==445 && posYY==230){
y+=-speed;
}}
function drawPacket(){
ctx2.beginPath();
ctx2.clearRect(0,0,layer2.width,layer2.height);
ctx2.rect(x,y, 10, 30);
ctx2.closePath();
ctx2.stroke();
ctx2.restore();
}
function redrawPacket(){
ctx2.beginPath();
ctx2.clearRect(0,0,layer2.width,layer2.height);
ctx2.rotate( (Math.PI / 180) * -25);  //rotate 25 degrees.
ctx2.rect(x,y, 10, 30);
ctx2.closePath();
ctx2.stroke();
}
function start() {
requestId = window.requestAnimationFrame(animate);
}
function stop() {
  if (requestId)
    window.cancelAnimationFrame(requestId);
  requestId = 0;
}
function  drawScreen() {
ctx.beginPath();
{
//top line
ctx.moveTo(250,215);
ctx.lineTo(390,215);

//bottom line
ctx.moveTo(250,315);
ctx.lineTo(390,315);
//front  curve
ctx.moveTo(230,230);
ctx.quadraticCurveTo(250,200,269,230);
//bottom curve
ctx.moveTo(230,300);
ctx.quadraticCurveTo(250,330,268,300);

//front arc joining top and bottom opp curve
ctx.moveTo(230,230);
ctx.quadraticCurveTo(214,265,230,300);

//front opp arc joining top and bottom opp curve
ctx.moveTo(269,230);
ctx.quadraticCurveTo(286,265,268,300);
//ctx.moveTo(230,230);
//ctx.fillRect(230,230,188.80,170);
//back small top curve
ctx.moveTo(390,215);
ctx.quadraticCurveTo(407,218,414,230);
//back small bottom curve
ctx.moveTo(390,315);
ctx.quadraticCurveTo(405,314,414,300);
//back arc
ctx.moveTo(414,230);
ctx.quadraticCurveTo(435,263,414,300);
ctx.stroke();
ctx.closePath();
}
ctx.beginPath();
{
//First Cylinder
//First cylinder 1st line of rect
ctx.moveTo(574,130);
ctx.lineTo(574,195);
//First cylinder opp line of rect
ctx.moveTo(614,130);
ctx.lineTo(614,195);
//First cylinder bottom arc
ctx.moveTo(574,195);
ctx.quadraticCurveTo(594,205,614,195);
//First cylinder top-top arc
ctx.moveTo(574,130);
ctx.quadraticCurveTo(594,119,614,130);
//First cylinder top-bottom arc
ctx.moveTo(574,130);
ctx.quadraticCurveTo(594,142,614,130);
ctx.stroke();
ctx.closePath();
}
ctx.beginPath();
{
//Second Cylinder
//Second cylinder 1st line of rect
ctx.moveTo(574,428);
ctx.lineTo(574,493);
//Second cylinder opp line of rect
ctx.moveTo(614,428);
ctx.lineTo(614,493);
//drawellipse(574,428,10,2,0.5) 
//Second cylinder bottom arc
ctx.moveTo(574,493);
ctx.quadraticCurveTo(594,503,614,493);
//Second cylinder top-top arc
ctx.moveTo(574,428);
ctx.quadraticCurveTo(594,417,614,428);
//Second cylinder top-bottom arc
ctx.moveTo(574,428);
ctx.quadraticCurveTo(594,440,614,428);       
ctx.stroke();
ctx.closePath();
}

ctx.beginPath();
{
//Pipe to cylinder 1
//top line from main cylinder
ctx.moveTo(408,222);
ctx.lineTo(436,222);
//left line from main cylinder
ctx.moveTo(436,222);
ctx.lineTo(436,32);
//bottom line from main cylinder
ctx.moveTo(423,266);
ctx.lineTo(486,266);
//right line from main cylinder
ctx.moveTo(486,266);
ctx.lineTo(486,82);
//top line from left line
ctx.moveTo(436,32);
ctx.lineTo(619,32);
//bottom line from right line
ctx.moveTo(486,82);
ctx.lineTo(566,82);
//drop line to cylinder right
ctx.moveTo(619,32);
ctx.lineTo(619,112);
//drop line to cylinder left
ctx.moveTo(566,82);
ctx.lineTo(566,112);
//closing the pipe
ctx.moveTo(566,112);
ctx.quadraticCurveTo(592,128,619,112);
ctx.moveTo(566,112);
ctx.quadraticCurveTo(592,96,619,112);
ctx.stroke();
ctx.closePath();
}
}
packet();
</script>
</body>
</html>

请帮我解决这个问题。提前谢谢..

沿路径对对象进行动画处理的一种方法是沿该路径计算多点。

然后,对于每个动画循环,将对象前进到下一个多段。

这是一个演示:http://jsfiddle.net/m1erickson/RtXq6/

例如,圆柱-管路径可能具有如下定义的线段:

var pathArray=[]
pathArray.push({x:25, y:250});
pathArray.push({x:150,y:250});
pathArray.push({x:150,y:50});
pathArray.push({x:250,y:50});
pathArray.push({x:250,y:100});

您可以沿该系列线段计算多边形点,如下所示:

function makePolyPoints(pathArray){
    var points=[];
    for(var i=1;i<pathArray.length;i++){
        var startPt=pathArray[i-1];
        var endPt=pathArray[i];
        var dx = endPt.x-startPt.x;
        var dy = endPt.y-startPt.y;
        for(var n=0;n<=100;n++){
            var x= startPt.x + dx * n/100;
            var y= startPt.y + dy * n/100;
            points.push({x:x,y:y});
        }
    }
    return(points);
}

然后,您可以沿着路径的每个多段对对象进行动画处理,如下所示:

        var width=15;
        var height=30;
        var position=0;
        var speed=2;
        var rotation=0;
        var rotationSpeed=Math.PI/60;
        animate();
        var fps = 60;
        function animate() {
            setTimeout(function() {
                requestAnimFrame(animate);
                // calc new position
                position+=speed;
                if(position>polypoints.length-1){
                    return;
                }
                var pt=polypoints[position];
                rotation+=rotationSpeed;
                // draw
                ctx.clearRect(0,0,canvas.width,canvas.height);
                ctx.save();
                ctx.beginPath();
                ctx.translate(pt.x,pt.y);
                ctx.rotate(rotation);
                ctx.rect(-width/2,-height/2,15,30);
                ctx.fill();
                ctx.stroke();        
                ctx.restore();
            }, 1000 / fps);
        }

本示例沿 5 条线段中的每一条线段创建 100 个多段。 由于每个线段的长度不同,因此对于较长的线段,动画会更快,对于较短的线段,动画会变慢。

如果需要节奏更均匀的动画,则可以在较短的线段上计算少于 100 个多角(最长的线将有 100 个多角点 - 较短的线将按比例减少多点)您可以通过取任何较短的线与最长线的长度比来确定每行有多少个多点。