HTML5 Canvas 的初学者,使用图层

Beginner at HTML5 Canvas, using layers?

本文关键字:图层 初学者 Canvas HTML5      更新时间:2023-09-26

我是HTML5画布的新手,我正在尝试使用图层。我一直在寻找实现它们的方法,但没有任何帮助我正在尝试做的事情。我正在尝试制作火山喷发的动画。我想把火山和背景天蓝色放在一层上,从天而降的熔岩放在第二层,把火山灰云放在第三层。当我发现图层时,我已经对此进行了研究,所以我知道事情不合适。我的问题是,在实施这些层时,我是否走在正确的轨道上?

<body>
<div id="canvasesdiv" style="position:relative; width:400px; height:300px">
<canvas id="layer1" style="z-index: 1; position:absolute; left:0px; top:0px;" width="800" height="500"></canvas>
<canvas id="layer2" style="z-index: 2; position:absolute; left:0px; top:0px;" width="800" height="500"></canvas>
<canvas id="layer3" style="z-index: 3; position:absolute; left:0px; top:0px;" width="800" height="500"></canvas>
</div>
</body>
<script>
//var canvas = document.getElementById("myCanvas");
//var context = canvas.getContext("2d");
var layer1;
var layer2;
var layer3;
var particles;
var eruption;
var timer;
var timerRestart;
function init(){
    layer1 = document.getElementById("layer1");
    ctx1 = layer1.getContext("2d");
    layer2 = document.getElementById("layer2");
    ctx2 = layer2.getContext("2d");
    layer3 = document.getElementById("layer3");
    ctx3 = layer3.getContext("2d");
}
function animationHandler(){
    fillBackgroundColor(canvas, context);
    drawVolcano();
    drawClouds();
    eruption = setTimeout(makeParticles, 10);
}
function drawClouds(){
    ctx3.beginPath();
    ctx3.moveTo(0, 100);
    ctx3.bezierCurveTo(0, 100, 75, 200, 150, 100);
    ctx3.bezierCurveTo(150, 100, 225, 200, 300, 85);
    ctx3.bezierCurveTo(300, 85, 375, 200, 450, 75);
    ctx3.bezierCurveTo(450, 75, 525, 200, 600, 100);
    ctx3.bezierCurveTo(600, 100, 700, 200, 800, 100);
    ctx3.lineTo(800, 0);
    ctx3.lineTo(0, 0);
    ctx3.closePath();
    ctx3.fillStyle = "#6f2a2a";
    ctx3.fill();
    ctx3.lineWidth = 5;
    ctx3.strokeStyle = "#371515";
    ctx3.stroke();
}
function drawVolcano(){
    ctx1.beginPath();
    ctx1.moveTo(0, 400);
    ctx1.bezierCurveTo(0, 400, 250, 400, 325, 200);
    ctx1.lineTo(425, 200);
    ctx1.bezierCurveTo(425, 200, 450, 400, 800, 400);
    ctx1.lineTo(800, 500);
    ctx1.lineTo(0, 500);
    ctx1.closePath();
    ctx1.fillStyle = "#802b00";
    ctx1t.fill();
    ctx1.lineWidth = 5;
    ctx1.strokeStyle = "#b33c00";
    ctx1.stroke();
}
function fillBackgroundColor(canvas, context){
    ctx1.fillStyle = "#3399ff" ;
    ctx1.fillRect(0, 0, canvas.width, canvas.height);
}
function makeParticles() {
//create an array of particles for our animation
    particles = [];
    for(var i = 0; i < 100; i++)
    {
        particles.push(new Particle());
    }
}
function degreesToRadians(degrees) {
 //converts from degrees to radians and returns
    return (degrees * Math.PI)/180;
}
function Particle(){
 //the constructor for a single particle, with random starting x+y, velocity, color, and radius
 //this.x = Math.random()*canvas.width;
 //this.y = Math.random()*canvas.height;
    this.x = canvas.width/2;
    this.y = (0,0);
    this.vx = Math.random()*16-8;
    this.vy = Math.random()*10;
    var colors = ["red", "#ff6600", "yellow", "#262626"];
    this.color = colors[Math.floor(Math.random()*colors.length)];
    this.radius = 50;
}
function moveParticles() {
 //partially clear the screen to fade previous circles, and draw a new particle at each new coordinate
    ctx2.globalCompositeOperation = "source-over";
    ctx2.fillStyle = "rgba(0, 0, 0, 0.3)";
    ctx2.fillRect(0, 0, canvas.width, canvas.height);
    ctx2.globalCompositeOperation = "lighter";
    for(var i = 0; i < particles.length; i++)
    {
        var p = particles[i];
        ctx2.beginPath();
        ctx2.arc(p.x, p.y, p.radius, 0, degreesToRadians(360), true);
        ctx2.fillStyle = p.color;
        ctx2.fill();
        p.x += p.vx;
        p.y += p.vy;
        if(p.x < -50) p.x = canvas.width+50;
        if(p.y < -50) p.y = canvas.height+50;
        if(p.x > canvas.width+50) p.x = -50;
        if(p.y > canvas.height+50) p.y = -50;
        p.radius -= 1;
    }
}
function clearScreen(color) {
 //clears the screen and fills with the color of choice
    ctx2.clearRect(0, 0, canvas.width, canvas.height);
    ctx2.fillStyle = color;
    ctx2.fillRect(0, 0, canvas.width, canvas.height);
}
window.onload = function() {
    animationHandler();
    timer = setInterval(moveParticles, 60);
    //timerRestart = setInterval(makeParticles, 4000);
}

编辑:所以我之前的问题以及为什么我开始尝试使用图层是因为熔岩的动画会使画布变黑。所以我想如果我把所有东西都分成不同的层,它就不会使画布变黑。我在答案中实现了 Sergio 的代码,它接近我想要实现的目标,但我仍然遇到以前的问题。我引用了一些喷发动画的代码,这就是动画本身的工作方式。我想我可能应该把它放在一个单独的问题中,但是有没有不同的方法可以让熔岩工作到它仍然具有与现在相同的效果,但也许到它的画布不透明度下降的地方,以便你可以看到下面的层?这是动画发生的地方:

function moveParticles() {
//partially clear the screen to fade previous circles, and draw a new particle at each new coordinate
ctx2.globalCompositeOperation = "source-over";
ctx2.fillStyle = "rgba(0, 0, 0, 0.3)";
ctx2.fillRect(0, 0, canvas.width, canvas.height);
ctx2.globalCompositeOperation = "lighter";

你走在正确的道路上。 但也有一些问题。首先在 windows.load 上,您首先调用 animationHandler,而不调用 init(),这会导致很多错误。然后有很多对一个名为 canvas 的变量的引用,该变量尚未定义,嗯;是的,但你把它注释掉了。并且有一个或两个键入错误(drawVolcano() 有一个键入错误),这会阻止代码执行。

修复一些错误:并在Windows.load上添加初始化,您将获得一个有效的动画:试试这个,让我知道这是否是你想要的。如果是,那么您做对了..你只是有一些小错误。

<body>
<div id="canvasesdiv" style="position:relative; width:800px; height:500px">
<canvas id="layer1" style="z-index: 1; position:absolute; left:0px; top:0px;" width="800" height="500"></canvas>
<canvas id="layer2" style="z-index: 2; position:absolute; left:0px; top:0px;" width="800" height="500"></canvas>
<canvas id="layer3" style="z-index: 3; position:absolute; left:0px; top:0px;" width="800" height="500"></canvas>
</div>
<script>
//var canvas = document.getElementById("myCanvas");
//var context = canvas.getContext("2d");
var layer1;
var layer2;
var layer3;
var particles;
var eruption;
var timer;
var timerRestart;
function init(){
    layer1 = document.getElementById("layer1");
    ctx1 = layer1.getContext("2d");
    layer2 = document.getElementById("layer2");
    ctx2 = layer2.getContext("2d");
    canvas=layer3 = document.getElementById("layer3");
    context=ctx3 = layer3.getContext("2d");
}
function animationHandler(){
    fillBackgroundColor(canvas, context);
    drawVolcano();
    drawClouds();
    eruption = setTimeout(makeParticles, 10);
}
function drawClouds(){
    ctx3.beginPath();
    ctx3.moveTo(0, 100);
    ctx3.bezierCurveTo(0, 100, 75, 200, 150, 100);
    ctx3.bezierCurveTo(150, 100, 225, 200, 300, 85);
    ctx3.bezierCurveTo(300, 85, 375, 200, 450, 75);
    ctx3.bezierCurveTo(450, 75, 525, 200, 600, 100);
    ctx3.bezierCurveTo(600, 100, 700, 200, 800, 100);
    ctx3.lineTo(800, 0);
    ctx3.lineTo(0, 0);
    ctx3.closePath();
    ctx3.fillStyle = "#6f2a2a";
    ctx3.fill();
    ctx3.lineWidth = 5;
    ctx3.strokeStyle = "#371515";
    ctx3.stroke();
}
function drawVolcano(){
    ctx1.beginPath();
    ctx1.moveTo(0, 400);
    ctx1.bezierCurveTo(0, 400, 250, 400, 325, 200);
    ctx1.lineTo(425, 200);
    ctx1.bezierCurveTo(425, 200, 450, 400, 800, 400);
    ctx1.lineTo(800, 500);
    ctx1.lineTo(0, 500);
    ctx1.closePath();
    ctx1.fillStyle = "#802b00";
    ctx1.fill();
    ctx1.lineWidth = 5;
    ctx1.strokeStyle = "#b33c00";
    ctx1.stroke();
}
function fillBackgroundColor(canvas, context){
    ctx1.fillStyle = "#3399ff" ;
    ctx1.fillRect(0, 0, canvas.width, canvas.height);
}
function makeParticles() {
//create an array of particles for our animation
    particles = [];
    for(var i = 0; i < 100; i++)
    {
        particles.push(new Particle());
    }
}
function degreesToRadians(degrees) {
 //converts from degrees to radians and returns
    return (degrees * Math.PI)/180;
}
function Particle(){
 //the constructor for a single particle, with random starting x+y, velocity, color, and radius
 //this.x = Math.random()*canvas.width;
 //this.y = Math.random()*canvas.height;
    this.x = canvas.width/2;
    this.y = (0,0);
    this.vx = Math.random()*16-8;
    this.vy = Math.random()*10;
    var colors = ["red", "#ff6600", "yellow", "#262626"];
    this.color = colors[Math.floor(Math.random()*colors.length)];
    this.radius = 50;
}
function moveParticles() {
 //partially clear the screen to fade previous circles, and draw a new particle at each new coordinate
    ctx2.globalCompositeOperation = "source-over";
    ctx2.fillStyle = "rgba(0, 0, 0, 0.3)";
    ctx2.fillRect(0, 0, canvas.width, canvas.height);
    ctx2.globalCompositeOperation = "lighter";
    for(var i = 0; i < particles.length; i++)
    {
        var p = particles[i];
        ctx2.beginPath();
        ctx2.arc(p.x, p.y, p.radius, 0, degreesToRadians(360), true);
        ctx2.fillStyle = p.color;
        ctx2.fill();
        p.x += p.vx;
        p.y += p.vy;
        if(p.x < -50) p.x = canvas.width+50;
        if(p.y < -50) p.y = canvas.height+50;
        if(p.x > canvas.width+50) p.x = -50;
        if(p.y > canvas.height+50) p.y = -50;
        p.radius -= 1;
    }
}
function clearScreen(color) {
 //clears the screen and fills with the color of choice
    ctx2.clearRect(0, 0, canvas.width, canvas.height);
    ctx2.fillStyle = color;
    ctx2.fillRect(0, 0, canvas.width, canvas.height);
}
window.onload = function() { 
    init();
    animationHandler();
    timer = setInterval(moveParticles, 60);
    //timerRestart = setInterval(makeParticles, 4000);
}
</script>
</body>

但是,在我的浏览器上,粒子从顶部移动到底部。 如果你想要火山效果。 它必须以弧形移动。 从火山上射出然后落下。 但是,您走在正确的轨道上,只需要更改代码更多一点。

几分钟前,我进一步修改了代码,以添加火球的弧形运动,并使用一些精灵。(http://www.dominicanvoice.com/test/volcano.php)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Untitled Document</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
<div id="canvasesdiv" style="position:relative; width:800px; height:500px">
<canvas id="layer1"  style="z-index: 1; position:absolute; left:0px; top:0px;" width="800" height="500"></canvas>
<canvas id="layer1f" style="z-index: 1; position:absolute; left:0px; top:0px;" width="800" height="500"></canvas>
<canvas id="layer2"  style="z-index: 2; position:absolute; left:0px; top:0px;" width="800" height="500"></canvas>
<canvas id="layer2f"  style="z-index: 2; position:absolute; left:0px; top:0px;" width="800" height="500"></canvas>
<canvas id="layer3"  style="z-index: 3; position:absolute; left:0px; top:0px;" width="800" height="500"></canvas>
</div>
<script>
//var canvas = document.getElementById("myCanvas");
//var context = canvas.getContext("2d");
var layer1;
var layer2;
var layer3;
var particles;
var eruption;
var timer;
var timerRestart;
function init(){
    layer1 = document.getElementById("layer1");
    ctx1 = layer1.getContext("2d");
    layer1f = document.getElementById("layer1f");
    f1 = layer1f.getContext("2d");
    layer2 = document.getElementById("layer2");
    ctx2 = layer2.getContext("2d");
    layer2f = document.getElementById("layer2f");
    f2 = layer2f.getContext("2d");
    canvas=layer3 = document.getElementById("layer3");
    context=ctx3 = layer3.getContext("2d");
}
function animationHandler(){
    fillBackgroundColor(canvas, context);
    drawVolcano();
    //drawClouds();
    eruption = setTimeout(makeParticles, 10);
}

var cloud = new Image();
cloud.src='http://www.dominicanvoice.com/test/volcano/cloud.png';
var fireball = new Image();
fireball.src='http://www.dominicanvoice.com/test/volcano/fireball.png';
function drawVolcano(){
    img = new Image();
    img.src='http://www.dominicanvoice.com/test/volcano/layer2.png';
    img.onload = function() { ctx1.drawImage(this,0,0);};
    img2 = new Image();
    img2.src="http://www.dominicanvoice.com/test/volcano/front.png";
    img2.onload = function() { ctx2.drawImage(this,0,0);};
}
function fillBackgroundColor(canvas, context){
    ctx1.fillStyle = "#3399ff" ;
    ctx1.fillRect(0, 0, canvas.width, canvas.height);
}
function makeParticles() {
//create an array of particles for our animation
    particles = [];
    for(var i = 0; i < 100; i++)
    {
        particles.push(new Particle());
    }
}
function degreesToRadians(degrees) {
 //converts from degrees to radians and returns
    return (degrees * Math.PI)/180;
}
function Particle(){
 //the constructor for a single particle, with random starting x+y, velocity, color, and radius
 //this.x = Math.random()*canvas.width;
 //this.y = Math.random()*canvas.height;
    this.x = canvas.width/2;
    this.y = 160;
    this.vx = Math.random()*16-8;
    this.vy = Math.random()*25;
    var colors = ["red", "#ff6600", "yellow", "#262626"];
    this.color = colors[Math.floor(Math.random()*colors.length)];
    this.radius = 50;
}
function moveParticles() {
 //partially clear the screen to fade previous circles, and draw a new particle at each new coordinate
    f1.clearRect(0, 0, canvas.width, canvas.height);
    f2.clearRect(0, 0, canvas.width, canvas.height);
    for(var i = 0; i < particles.length; i++)
    {
        var p = particles[i];
        f=(p.vy>0) ?f1:f2;
        if (p.vy>0) f.drawImage(cloud,Math.floor((25-p.vy)/2)*128,0,128,128,p.x-64,p.y,128,128) 
        else ctx3.drawImage(cloud,1536,0,128,128,p.x-Math.random()*5-64,-20+Math.random()*10,128,128);
        if (p.y<500) { 
        f.drawImage(fireball,Math.floor(-p.vy/2)*128,0,128,64,p.x-64,p.y,128,64); 
   //     f.beginPath();
    //    f.arc(p.x, p.y, p.radius, 0, degreesToRadians(360), true);
    //    f.fillStyle = p.color;
    //    f.fill();
        p.x += p.vx;
        p.y -= p.vy;
        p.vy-=1;
        if(p.x < -50) p.x = canvas.width+50;
        if(p.y < -50) p.y = canvas.height+50;
        if(p.x > canvas.width+50) p.x = -50;
        if(p.y > canvas.height+50) p.y = -50;
        p.radius -= 1;
        };
    }
}

window.onload = function() { 
    init();
    animationHandler();
    timer = setInterval(moveParticles, 60);
    //timerRestart = setInterval(makeParticles, 4000);
}
</script>
</body>

代码尚未清理或优化,但您可以查看它修改它并使用它。您可以在此处看到它的工作:http://www.dominicanvoice.com/test/volcano.php注意:我没有在Mac上测试此代码。 仅在Windows上,它工作正常。