简体   繁体   中英

Creating animations with HMTL5 canvas - Can't seem to add any objects

For a project, I need to take these two blocks of code and modify them to create a little animation. The Javascript document creates a background color and creates like white rectangles fall down, like snow. The HTML document creates the canvas.

I have worked with the HTML canvas and done some super basic animations, but I'm hitting a roadblock here. When I try to add stuff to this, it does not show up. All I want to do is add some text and then animate it going across the canvas and some other very basic stuff.

I tried adding the text to the script portion of the html document like I have done several times before, but it just didn't seem to do anything.

Any idea what I'm doing wrong?

(I'm an animation major, so I apologize in advance for my ignorance; scripting is not my forte)

html document:

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>A Basic Animation</title>
<script type="text/javascript" src="buffer-script2.js"></script>
<style type="text/css">
body,td,th {
font-family: Arial, "Franklin Gothic Book", sans-serif;
}
</style>
</head>

<body>
<h2>An Animation with Double Buffer</h2>
  <canvas id="Sky" width="600" height="300">
    Canvas not supported
  </canvas>

<script>
var canvas = document.getElementById("Sky");
var ctx = canvas.getContext("2d");
ctx.font = "30px Arial";
ctx.strokeText("Hello World",10,50);
</script>

</body>
</html>

Javascript file:

window.onload = init;

var canvas = null;
var context = null;
var bufferCanvas = null;
var bufferCanvasCtx = null;
var flakeArray = [];
var flakeTimer = null;
var maxFlakes = 200;

function Flake() {
this.x = Math.round(Math.random() * context.canvas.width);
this.y = -10;
this.drift = Math.random();
this.speed = Math.round(Math.random() * 5) + 1;
this.width = (Math.random() * 5) + 2;
this.height = this.width;
}

function init() {
canvas = document.getElementById('Sky');
context = canvas.getContext("2d");

bufferCanvas = document.createElement("canvas");
bufferCanvasCtx = bufferCanvas.getContext("2d");
bufferCanvasCtx.canvas.width = context.canvas.width;
bufferCanvasCtx.canvas.height = context.canvas.height;

// initialize the rects
flakeTimer = setInterval(addFlake, 200);

Draw();

setInterval(animate, 30);
}

function addFlake() {
flakeArray[flakeArray.length] = new Flake();
if (flakeArray.length == maxFlakes)
    clearInterval(flakeTimer);
}

function blank() {
bufferCanvasCtx.fillStyle = "#330033";
bufferCanvasCtx.fillRect(0,0,bufferCanvasCtx.canvas.width, bufferCanvasCtx.canvas.height);
}

function animate() {
Update();
Draw();
}

function Update() {
for (var i = 0; i < flakeArray.length; i++) {
    if (flakeArray[i].y < context.canvas.height) {
        flakeArray[i].y += flakeArray[i].speed;
        if (flakeArray[i].y > context.canvas.height)
            flakeArray[i].y = -5;
        flakeArray[i].x += flakeArray[i].drift;
        if (flakeArray[i].x > context.canvas.width)
            flakeArray[i].x = 0;
    }
}
}

function Draw(){
context.save();
/*
// create a clipping region
bufferCanvasCtx.beginPath();
bufferCanvasCtx.fillStyle="black";
bufferCanvasCtx.fillRect(0,0,bufferCanvas.width,bufferCanvas.height);
bufferCanvasCtx.arc(bufferCanvas.width/2,bufferCanvas.height/2,bufferCanvas.height/3,0,2*Math.PI);
bufferCanvasCtx.clip();
*/
blank();

for (var i = 0; i < flakeArray.length; i++) {
    bufferCanvasCtx.fillStyle = "white";
    bufferCanvasCtx.fillRect(flakeArray[i].x,flakeArray[i].y,flakeArray[i].width,flakeArray[i].height);
}

// copy the entire rendered image from the buffer canvas to the visible one
context.drawImage(bufferCanvas, 0,0,bufferCanvas.width, bufferCanvas.height);
context.restore();
}

I suggest...

  • Use requestAnimationFrame instead of an interval.
  • Get rid of the flakeTimer by initializing flakes at negative heights.
  • Get rid of the double buffer and render everything on one canvas.
  • Update flake positions relative to the time passed between updates.
  • Encapsulate updating and drawing of flakes, eg by introducing a Snow class.
  • Simplify iterations such as for (var i = 0; i < flakeArray.length; i++) by using eg for (let flake of flakes) .
  • Less reliance on globals, pass canvas context and dimensions as parameters.

 function Flake(x, y, drift, speed, size) { this.x = x; this.y = y; this.drift = drift; this.speed = speed; this.size = size; } class Snow { constructor() { this.flakes = []; } update(dt, width, height) { for (let flake of this.flakes) { flake.y += flake.speed * dt; if (flake.y > height) { flake.y = -flake.size; } flake.x += flake.drift * dt; if (flake.x > width) { flake.x = -flake.size; } } } draw(ctx) { ctx.fillStyle = "white"; for (let flake of this.flakes) { ctx.fillRect(flake.x, flake.y, flake.size, flake.size); } } } let canvas = document.getElementById("canvas"); let ctx = canvas.getContext("2d"); let snow = new Snow(); // Add flakes: for (let i = 0; i < 200; ++i) { snow.flakes.push(new Flake( Math.round(Math.random() * canvas.width), -i * 200, Math.random() * 0.05, Math.random() * 0.25 + 0.05, Math.random() * 5 + 2) ); } // Animate: let last = performance.now(); function frame(time) { // Clear background: ctx.fillStyle = "#330033"; ctx.fillRect(0, 0, canvas.width, canvas.height); // Update & render snow: snow.update(time - last, canvas.width, canvas.height); snow.draw(ctx); // Render text: ctx.strokeStyle = "white"; ctx.font = "30px Arial"; ctx.strokeText("Hello World", 10, 50); requestAnimationFrame(frame); last = time; } requestAnimationFrame(frame); 
 <canvas id="canvas" width="600" height="300"></canvas> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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