如何在画布上实现波浪动画? 使用延迟或其他技术



我基本上是试图让几个球排在一起,让球在 Y 轴上上下移动,但每个球开始时都有一点延迟,所以最终它应该产生无限的波效果

我首先尝试增加速度,虽然它创造了我想要的效果,但它暂时做到了,因为它不断增加动画的动态。

我认为只有当我能让每个球在不同的时间开始动画时,它才能解决这个问题。 对此有什么建议吗?

查看我的代码笔上的动画 https://codepen.io/jinnn0/pen/zgRrKm?editors=0010

const canvas = document.querySelector('canvas')
const c = canvas.getContext('2d')
canvas.width = window.innerWidth
canvas.height = window.innerHeight

function Circle(x, y, radius, color, velocity, amplitude) {
  this.x = x
  this.y = y
  this.color = color
  this.radius = radius
  this.radian = 1
  this.velocity = velocity
  this.amplitude = amplitude
  this.acceleration = 0.001
  this.count = 0

  this.draw = function(){
    c.beginPath()
    c.fillStyle = color
    c.arc(this.x, this.y, this.radius, 0, Math.PI * 2)
    c.lineWidth = 3
    c.stroke()
    c.fill()
    c.closePath()
 }
 this.update = function(){
   this.draw()
   this.radian += this.velocity
   this.y = y + Math.sin(this.radian) * this.amplitude
   this.count ++
  }
}

let circleArr;
function init(){
 circleArr = []
 let radius = 25
 let x = radius
 let y = 200
 let color = "rgba(140, 140, 140)"
 let velocity = 0.05
 let amplitude = 100
 for( let i =0; i < 10; i++ ) {  
   circleArr.push(new Circle(x, y, radius, color, velocity, 
     amplitude))
   x += radius * 2
  // velocity += 0.001
  }
}

function animate(){
  c.clearRect(0, 0, canvas.width, canvas.height)
  for(let i = 0; i < circleArr.length; i++) {
    circleArr[i].update()   
  }
 requestAnimationFrame(animate)
}

init()
animate()

您可以使用Date.now()存储开始时间戳,然后将自动画开始以来的十多次时间与每个球的指定延迟(以毫秒为单位(进行比较(请注意,我还将起始弧度更改为 0,以便当动画开始时球不会"跳"到底部,以及开始 y,以便我们在片段预览中实际看到球(:

const canvas = document.querySelector('canvas')
const c = canvas.getContext('2d')
canvas.width = window.innerWidth
canvas.height = window.innerHeight
const start = Date.now();
const delay = 2000;
function Circle(x, y, radius, color, velocity, amplitude, delay) {
  this.x = x
  this.y = y
  this.color = color
  this.radius = radius
  this.radian = 0
  this.velocity = velocity
  this.amplitude = amplitude
  this.acceleration = 0.001
  this.count = 0
  this.delay = delay
  this.draw = function(){
    c.beginPath()
    c.fillStyle = color
    c.arc(this.x, this.y, this.radius, 0, Math.PI * 2)
    c.lineWidth = 3
    c.stroke()
    c.fill()
    c.closePath()
 }
 this.update = function(ellapsed){
   
   this.draw()
   if (ellapsed > this.delay) {
      this.radian += this.velocity
      this.y = y + Math.sin(this.radian) * this.amplitude
      this.count ++
   
   }
   
  }
}
let circleArr;
function init(){
 circleArr = []
 let radius = 25
 let x = radius
 let y = 130
 let color = "rgba(140, 140, 140)"
 let velocity = 0.05
 let amplitude = 100
 let delay = 0
 
 for( let i =0; i < 10; i++ ) {  
   circleArr.push(new Circle(x, y, radius, color, velocity, 
     amplitude, delay))
   x += radius * 2
   delay += 100
  // velocity += 0.001
  }
}
function animate(){
  // ellapsed time from the start (you should initialize start
  // closer to the animation start if there is a noticeably long
  // operation in between)
  const ellapsed = Date.now() - start;
  c.clearRect(0, 0, canvas.width, canvas.height)
  for(let i = 0; i < circleArr.length; i++) {
    // ellapsed is passed to the ball's update method
    circleArr[i].update(ellapsed)   
  }
  requestAnimationFrame(animate)
}
init()
animate()
<html>
  <body>
    <canvas />
  </body>
</html>

或者,您可以在我们第一次调用更新时为每个球初始化一个开始变量(这样并非所有球都依赖于全局开始,这可能对它们没有意义(

编辑: 重新阅读您的问题后,我注意到您可能会寻找另一种不涉及延迟的解决方案。实际上更容易:只需给每个球一个不同的(递增的(起始弧度。

下面我用弧度参数替换了额外的延迟参数:

    function Circle(x, y, radius, color, velocity, amplitude, radian) {
        this.x = x
        this.y = y
        this.color = color
        this.radius = radius
        this.velocity = velocity
        this.amplitude = amplitude
        this.acceleration = 0.001
        this.count = 0
        this.radian = radian
        this.draw = function(){
            c.beginPath()
            c.fillStyle = color
            c.arc(this.x, this.y, this.radius, 0, Math.PI * 2)
            c.lineWidth = 3
            c.stroke()
            c.fill()
            c.closePath()
        }
        this.update = function(){
            this.draw()
            this.radian += this.velocity
            this.y = y + Math.sin(this.radian) * this.amplitude
            this.count ++

        }
    }

然后,我没有为每个球输入经过的时间,而是用递增的弧度初始化它们:

    function init(){
        circleArr = []
        let radius = 25
        let x = radius
        let radian = 0
        let y = 130
        let color = "rgba(140, 140, 140)"
        let velocity = 0.05
        let amplitude = 100
        let delay = 0
        for( let i =0; i < 10; i++ ) {  
            circleArr.push(
                new Circle(
                    x, y,
                    radius, color,
                    velocity, amplitude, radian
                )
            )
            x += radius * 2
            radian += Math.PI / 10
            // velocity += 0.001
        }
    }

const canvas = document.querySelector('canvas')
const c = canvas.getContext('2d')
canvas.width = window.innerWidth
canvas.height = window.innerHeight
function Circle(x, y, radius, color, velocity, amplitude, startRadian) {
  this.x = x
  this.y = y
  this.color = color
  this.radius = radius
  this.velocity = velocity
  this.amplitude = amplitude
  this.acceleration = 0.001
  this.count = 0
  this.radian = startRadian
  this.draw = function(){
    c.beginPath()
    c.fillStyle = color
    c.arc(this.x, this.y, this.radius, 0, Math.PI * 2)
    c.lineWidth = 3
    c.stroke()
    c.fill()
    c.closePath()
 }
 this.update = function(){
   
   this.draw()
   this.radian += this.velocity
   this.y = y + Math.sin(this.radian) * this.amplitude
   this.count ++
   
   
  }
}
let circleArr;
function init(){
 circleArr = []
 let radius = 25
 let x = radius
 let radian = 0
 let y = 130
 let color = "rgba(140, 140, 140)"
 let velocity = 0.05
 let amplitude = 100
 let delay = 0
 for( let i =0; i < 10; i++ ) {  
   circleArr.push(new Circle(x, y, radius, color, velocity, 
     amplitude, radian))
   x += radius * 2
   radian += Math.PI / 10
  // velocity += 0.001
  }
}
function animate(){
  c.clearRect(0, 0, canvas.width, canvas.height)
  for(let i = 0; i < circleArr.length; i++) {
    circleArr[i].update()   
  }
  requestAnimationFrame(animate)
}
init()
animate()
<html>
  <body>
    <canvas/>
  </body>
</html>

它的效果更好,但会改变球的起始位置。 您可以通过结合这两种技术(弧度偏移+延迟(来实现非常酷的效果。

我让你试验不同的参数。

最新更新