这一节来创建一个运动、交互的例子。代码及效果: JSFiddle
在前面的 Ticker 中, 定义了 on(callback, scope) 方法, 注册一个自定义事件到每帧回调之中。通过这个处理中心, 每帧改变显示对象的坐标属性(或者其他可用的变形属性), 让显示对象各自做一系列规律的运动。由于每个物体的运动和其他物体无关, 所以我们可以把各自的运动放在类定义中。
注册点
默认的, 显示对象的注册点(RegisterPoint)在图片自身的左上角。很多时候这不利于定位以及边距检测。所以给 DisplayObject 加入了两个属性 regX, regY, 分别代表绘图时自己的注册点偏移。 相应的, 显示对象 draw 的时候要把这部分偏移算上去。以下把默认的注册中心设置为图片中心点处:
var DisplayObject = function (img) {
this.img = img
this.x = 0
this.y = 0
this.regX = img.width / 2
this.regY = img.height / 2
this.draw = function () {
ctx.drawImage(this.img, this.x - this.regX, this.y - this.regY)
}
}
应用了以上的居中设置注册点之后, 之前的点击检测也相应的调整一下, 无需再计算半宽、半高的偏差了。
速度
为了让显示对象动起来, 给它设置一个每帧的位置偏移量(即水平/垂直速度) vx, vy. 然后给它定义一个移动的方法, 每当调用时, 原位置累加一次位置偏移量。 这里 vx, vy 在创建显示对象的时候, 随机取区间 [-2, 2] 内的值:
var DisplayObject = function (img) {
this.img = img
this.x = 0
this.y = 0
this.regX = img.width / 2
this.regY = img.height / 2
// 每帧改变量
this.vx = 0
this.vy = 0
this.canMove = true
this.draw = function () {
ctx.drawImage(this.img, this.x - this.regX, this.y - this.regY)
}
this.move = function () {
this.x += this.vx
this.y += this.vy
}
}
边界检测
运行之后, 物体可能会位移至离开画布范围, 因此我们加入简单的边界检测。当超过边界的时候, 对该方向每帧位移量取反(速度反向), 起到反向回弹的效果:
this.move = function () {
this.x += this.vx
this.y += this.vy
if (this.x <= this.regX || this.x >= canvas.width - this.regX) {
this.vx *= -1
}
if (this.y <= this.regY || this.y >= canvas.height - this.regY) {
this.vy *= -1
}
}
点击交互
为了结合前面例子中的点击判定, 加入以下控制: 当点击画布时, 如果有触碰到物体, 若物体处于运动状态则静止下来; 若物体处于运动状态则给它随机速度开始运动。同时,如果点击到多个物体, 只取最上面的那个:
if(hits.length){
var hit = hits.pop()
if (hit.canMove) {
hit.canMove = false
children.splice(children.indexOf(hit), 1)
children.push(hit)
} else {
hit.canMove = true
hit.vx = 4 * Math.random() - 2
hit.vy = 4 * Math.random() - 2
}
}
最后, 再注册一个帧回调, 每帧调用各自的 move() 方法, 累加改变量:
Ticker.on(() => {
children.forEach(child => {
child.move()
})
})
完整的代码和演示效果如下: jsfiddle