uniapp 我就不想喷了,踩了很多坑,把代码贡献出来让大家少踩些坑。
实现的功能:
- 生成n个球在canvas中运动,相互碰撞后会反弹,反弹后的速度计算我研究过了,可以参考代码直接用
- 防止球出边框
- 防止小球之间碰撞过度,或者说“穿模”。采用的方法是碰撞后让两个小球都多走一帧。其实这样并不能完全防止“穿模”,但可以防止小球粘在一起不停的穿模
- uniapp中的requestAnimationFrame的使用,包括开始与停止动画
- 利用四叉树优化了碰撞检测,网上有些示例是直接让区域内所有的小球之间进行一次碰撞检测
代码是vue3写的。uniapp官方说做动画推荐用什么renderjs,不知道直接这样写还会有什么坑,目前在h5中测试没问题。
四叉树类的代码见我上一篇文章
ball类的代码:
export class Ball { // 提供圆心坐标和半径 constructor(x, y, r, speedX, speedY, color, index) { this.centerX = x this.centerY = y this.r = r this.x = x - r this.y = y - r this.width = 2 * r this.height = 2 * r this.color = color this.speedX = speedX this.speedY = speedY this.index = index // 索引 } // 将球填充到canvas context fillTo(ctx) { ctx.beginPath() ctx.arc(this.centerX, this.centerY, this.r, 0, 2 * Math.PI) ctx.setFillStyle(this.color) ctx.closePath() ctx.fill() } // 判断是否与另一个球相交 intersectAt(ball2) { let dx = this.centerX - ball2.centerX let dy = this.centerY - ball2.centerY let distance = Math.sqrt(dx * dx + dy * dy) return this.r + ball2.r >= distance } // 移动 width height 是canvas的宽高 move(width, height) { this.centerX += this.speedX if (this.centerX - this.r <= 0) { this.centerX = this.r this.speedX = -this.speedX } if (this.r + this.centerX >= width) { this.centerX = width - this.r this.speedX = -this.speedX } this.centerY += this.speedY if (this.centerY - this.r <= 0) { this.centerY = this.r this.speedY = -this.speedY } if (this.centerY + this.r >= height) { this.centerY = height - this.r this.speedY = -this.speedY } this.x = this.centerX - this.r this.y = this.centerY - this.r } }
page的代码: