javascript - 如何在窗口 Canvas 中制作移动图像的效果?

标签 javascript css html canvas

例如,我有一个有限的 Canvas ,宽度/高度小于其中上传的图像。 大佬们如何在 Canvas 窗口中制作移动图像的效果?也就是说, Canvas 窗口没有变化,我们“运行”的图片。谢谢

enter image description here

最佳答案

动画基本 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/

相关文章:

javascript - jQuery Animate 无限变换

css ie7 相关元素出现在包含元素的左侧和外部

css - 这个图像在 jQuery UI 中的作用是什么?

html - 请帮我在这个 html 导航菜单中添加一个简单的动画

javascript - 构建没有依赖项的 ember-cli 插件

javascript - Restangular 不 PUT 完整对象

javascript - 为邮政编码添加正确的空格(英国)

html - CSS - 背景位置在 Firefox 中不起作用

javascript - 将 div 向下移动一次超过某个点

javascript - 如何缩放到 Highmaps 中的特定点