canvas数字时钟之Ball对象及如何模拟物理效果

前言

Canvas案例-炫酷的数字时钟中,展现了案例的最终效果,并简单介绍了案例用到的知识点和案例中的对象,如今先介绍Ball对象,代码有什么问题欢迎你们指出。javascript

效果以下 java


Ball的属性

跟个前面的效果,下面是我列举的关键属性bash

  • posX, posY, vx, vy, gravity, bounce, canMove 对象位置、运动参数dom

  • alive, birth, life 对象生命参数ide

  • light, color, radius 对象状态参数函数

// 给出代码
function Ball(data) {
  this.posX = data.posX || 0;
  this.posY = data.posY || 0;
  this.radius = data.radius || 10;
  this.vx = data.vx || Math.random() - 0.5;
  this.vy = data.vy || Math.random() - 0.5;
  this.alive = true;
  this.canMove = false;
  this.birth = null;
  this.light = false;
  this.color = data.color || `#${Math.random().toString(16).substr(3, 6)}`;
}
Ball.prototype = {
  init(data) {
    this.initData(data);
    this.blender();
    return this;
  },
  initData(data) {
    this.WIDTH = data.WIDTH;
    this.HEIGHT = data.HEIGHT;
    this.ctx = data.ctx;
    this.life = 1000 * 15;
    this.gravity = 0.08;
    this.bounce = -0.7;
  },
}
复制代码

先说说几个简单的

这里说一下为何把参数分两部分,initData里的属性全部Ball实例都同样,没有必要单独设置,放到原型上,算是优化吧,减小没必要要的开销。post

值得注意的是颜色的随机使用了截取Math.random()的16进制串,想当年仍是傻傻的用学习

Math.ceil(Math.random() * 255)复制代码

这里的canMove用了控制Ball是否能够移动,light控制是否启用颜色,还记得数字时钟的数字先后没有改变的时候是固定不动的吗,并且仍是没有颜色优化

关于为啥设置生命参数

固然是清除无用的对象,释放内存了。好比那些小球出了画布已经没有做用了,就能够清除了,这里使用alive标记,这样能够很方便的清除这些无用对象。其实这里面还有一些对象的vx可能特别小,若是等这些对象移出画布等待的事件会很长,因此这里设置了life来记录小球的生命,生命到期就会被标记ui

具体实现以下:

// 标记生命到期的对象
if (new Date() - this.birth > this.life) {
	this.alive = false;
}
// 标记移出画布的对象
if (this.posX - this.radius <= 0 || this.posX >= WIDTH) {
	this.alive = false;
}复制代码

下面是模拟物理属性

回想高中咱们学习的物理知识—抛物线运动

v = at v = v0 + at h = 1/2 * at^2

然而实际却没法用这些,由于这里咱们拿不到时间t,那么咱们就要换个思路了

匀速运动

好比x方向作匀速运动,那么vx势必是定值,而后每次跟新把当前的posX = posX + vx,这样


就能够实现匀速运动了

加速运动

同理,y方向作加速运动,那么vy势必是变值,不只每次跟新把当前的posY = posY + vy,还要把这个重力加速度vy = gravity + vy ,这样就能够实现加速运动了

阻力呢?

为了达到每次弹跳有衰减,这里引入bounce参数,经过把这个参数设置一个(-1~0)便可实现反弹和衰减,一箭双雕。

// collide函数中
if (this.posY - this.radius <= 0 || this.posY + this.radius >= HEIGHT) {
    // 这里的min max是碰撞检测一个经典的作法
    this.posY = Math.min(this.posY, HEIGHT - this.radius);
    this.posY = Math.max(this.posY, 0);
    this.vy *= this.bounce;
}
// update函数中
if (this.canMove) {
    this.posX += this.vx;
    this.posY += this.vy;
    this.collide();
    this.vy += this.gravity;
}复制代码

小结

好了,至此咱们已经完成了Ball对象的构建,使用这个对象已经能够完成一些基本效果,好比下图这些。有什么问题能够留言交流,下期是Tile对象的构建。