简体   繁体   English

HTM5画布,有关更改动画效果的建议

[英]HTM5 Canvas, suggestions for changing animation effect

So I'm new to canvas, and am still figuring out how things work. 因此,我是新手,仍然在弄清楚事物的工作原理。 I am trying to make an animation of a volcano eruption. 我正在尝试制作火山喷发的动画。 I separated the volcano and sky onto one layer, the eruption on the second layer, and the ash cloud on the third. 我将火山和天空分为一层,第二层是火山喷发,第三层是灰云。 I was referencing an example for the eruption animation, and in the way it is written, it blacks out the canvas. 我参考了喷发动画的一个示例,在编写时,它使画布变黑。 Is there a different way of achieving the same effect it already makes, but so that the opacity of the layer is all the way down so you can see the volcano and sky underneath the eruption? 是否有其他方法可以实现已经产生的相同效果,但是该层的不透明度完全降低,因此您可以看到喷发下面的火山和天空? Here's my code: 这是我的代码:

<!doctype html>
<html lang='en'>
<head>
<style>
body {
 font-family: Verdana, Helvetica, sans-serif;
}
canvas {
 border: 1px solid black;;
}
</style>
</head>


<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>
<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>
</html>

This is where the animation happens: 这是动画发生的地方:

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";

It looks like the previously drawn particles are "dimmed" by overwriting the entire canvas with a low-alpha fill. 看起来以前绘制的粒子是通过用低alpha填充覆盖整个画布来“变暗”的。 But, this also undesirably causes the underlying volcano to be "dimmed". 但是,这也不利地导致下面的火山“变暗”。

Instead of repeatedly "dimming" by filling the whole canvas with rgba(0,0,0,0.3) , you could reduce each individual particle's alpha with each new frame. 不必通过用rgba(0,0,0,0.3)填充整个画布来反复“变暗”,而可以通过每个新帧减少每个单独粒子的alpha。

This can be done at the particle level by changing each particle's rgba fill. 通过更改每个粒子的rgba填充,可以在粒子级别完成此操作。

Example: 例:

 var canvas=document.getElementById("canvas"); var ctx=canvas.getContext("2d"); var cw=canvas.width; var ch=canvas.height; var particle={ // start with red base color // use a token (here @) which will be replaced with alpha baseColor:'rgba(255,0,0,@)', // start with the particle at full alpha // this alpha will be incrementally reduced currentAlpha:1.00, }; requestAnimationFrame(animate); function animate(time){ ctx.clearRect(0,0,cw,ch); ctx.beginPath(); ctx.arc(150,50,20,0,Math.PI*2); // change this particle's alpha var fill=particle.baseColor.replace('@',particle.currentAlpha); particle.currentAlpha-=.01; if(particle.currentAlpha<=0){particle.currentAlpha=0;} ctx.fillStyle=fill; ctx.fill(); requestAnimationFrame(animate); } 
 body{ background-color: ivory; } #canvas{border:1px solid red;} 
 <h4>A particle with reducing rgba alpha</h4> <canvas id="canvas" width=300 height=300></canvas> 

For better performance, you could draw all particles with the same alpha value in a batch. 为了获得更好的性能,可以批量绘制具有相同alpha值的所有粒子。 This method would use context.globalAlpha to draw a batch of particles rather than changing each particle's rgba . 此方法将使用context.globalAlpha绘制一批粒子,而不是更改每个粒子的rgba

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM