最佳答案
动画基本 Action
像所有使某物看起来好像在移动的动画一样,是绘制一系列静止图像(一帧),每个图像都略有不同。如果帧率足够高(超过每秒 20 帧),人眼和大脑就会将静止图像序列视为连续运动。从第一部电影到今天的高端游戏,动画就是这样完成的。
所以对于canvas来说画一个frame的过程很简单。创建一个清除 Canvas 的函数,绘制你需要的东西,退出函数以便浏览器可以将完成的框架移动到显示器上。 (请注意,虽然在函数中在 Canvas 上绘制的任何内容都不会显示在显示屏上,但您必须退出该函数才能看到绘制的内容)
要制作动画,您必须每秒至少执行上述操作 20 次以上。为获得最佳效果,您应该以与显示硬件显示帧相同的速率执行此操作。对于始终为每秒 60 帧 (fps) 的浏览器。
浏览器中的动画
为了帮助与显示同步,您使用函数 requestAnimationFrame(myDrawFunction)
它告诉浏览器您正在制作动画,并且渲染结果应该仅在显示硬件准备就绪时显示显示一个新的完整框架,而不是在绘制函数退出时(这可能是硬件框架的一半)。
动画对象
作为一个简单的例子,让我们创建一个动画对象。
const imageSrc = "/image/C7qq2.png?s=328&g=1";
const myImage = {
posX: 0, // current position of object
posY: 0,
speed: 3, // speed in pixels per frame (1/60th second)
direction: 0, // direction of movement in radians 0 is at 3oclock
image: (() => { // create and load an image (Image will take time to load
// and may not be ready until after the code has run.
const image = new Image;
image.src = imageSrc;
})(),
绘图函数
然后是在 Canvas 上绘制对象的绘制函数
draw(ctx) {
ctx.drawImage(this.image, this.posX, this.posY);
},
更新函数
在制作动画时,我们需要每帧移动一次对象,为此我们创建了一个更新函数。
update() {
this.posX += (mx = Math.cos(this.direction)) * this.speed;
this.posY += (my = Math.sin(this.direction)) * this.speed;
}
} // end of object
每秒多次
为了制作动画,我们创建了一个主循环,它通过 requestAnimationFrame
调用每个硬件显示帧。
function mainLoop() {
// clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// update the obj
myImage.update();
// draw the object
myImage.draw(ctx);
// request the next frame
requestAnimationFrame(mainLoop);
// note all of the above code is not seen by the use until the
// next hardwares display frame. If you used setTimeout or setInterval
// then it would be displayed when this function exits (which may be
// halfway through a frame resulting in the animation being cut in two)
}
// request the first frame
requestAnimationFrame(mainLoop);
一些额外的东西
这就是最基本的动画。当然你需要获取 Canvas 上下文并等待图像加载。此外,由于图像在 Canvas 上移动,您需要检查它何时移动并停止动画。
例如停止动画是图像在屏幕外
if(myImage.posX < canvas.width){ // only render while image is on the canvas
requestAnimationFrame(mainLoop);
} else {
console.log("Animation has ended");
}
现在把它放在一起作为演示。
演示
该演示有一些额外的智能来使图像环绕,确保图像在开始之前已加载并使其从屏幕上开始,但与上面概述的基本相同。
// get the 2D context from the canvas id
const ctx = canvas.getContext("2d");
// setup the font and text rendering
ctx.font = "32px arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
// create the image object and load the image
const imageSrc = "/image/C7qq2.png?s=328&g=1";
const myImage = {
posX: 0, // current position of object
posY: 0,
speed: 3, // speed in pixels per frame (1/60th second)
direction: 0, // direction of movement in radians 0 is at 3oclock
image: (() => { // create and load an image (Image will take time to load
// and may not be ready until after the code has run.
const image = new Image;
image.src = imageSrc;
// to start move the image of the display
image.onload = function(){
const imageDiagonalSize = Math.sqrt(
image.width * image.width + image.height * image.height
)
myImage.posX = (canvas.width / 2) - imageDiagonalSize - Math.cos(myImage.direction) * imageDiagonalSize;
myImage.posX = (canvas.height / 2) - imageDiagonalSize - Math.sin(myImage.direction) * imageDiagonalSize;
}
return image;
})(),
draw(ctx) {
ctx.drawImage(this.image, this.posX, this.posY);
},
update() {
var mx,my; // get movement x and y
this.posX += (mx = Math.cos(this.direction)) * this.speed;
this.posY += (my = Math.sin(this.direction)) * this.speed;
// if the image moves of the screen move it to the other side
if(mx > 0) { // if moving right
if(this.posX > canvas.width){
this.posX = 0-this.image.width;
}
}else if(mx < 0) { // if moving left
if(this.posX + this.image.width < 0){
this.posX = canvas.width;
}
}
if(my > 0) { // if moving down
if(this.posY > canvas.height){
this.posY = 0-this.image.height;
}
}else if(my < 0) { // if moving up
if(this.posY + this.image.height < 0){
this.posY = canvas.height;
}
}
}
}
function mainLoop() {
// clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
if(myImage.image.complete) { // wait for image to load
myImage.update();
myImage.draw(ctx);
}else{ // some feedback to say the image is loading
ctx.fillText("Loading image..",canvas.width / 2, canvas.height / 2);
}
// request the next frame
requestAnimationFrame(mainLoop);
}
// request the first frame
requestAnimationFrame(mainLoop);
canvas {
border: 2px solid black;
}
<!-- id's must be unique to the page -->
<canvas id="canvas"></canvas>
- 请注意,以上代码使用 ES6,并且需要像 Babel 这样的代码预处理器才能在旧版浏览器上运行。
关于javascript - 如何在窗口 Canvas 中制作移动图像的效果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44747901/