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的代码:

<template>
<view>
<view>
<button @click="animateStart">开始</button>
<button @click="animateStop">停止</button>
</view>
<canvas type="2d" :style="{'width':canvasSize+'px','height':canvasSize+'px','border':'1px solid black'}"
canvas-id="game" id="game"></canvas>
</view>
</template> <script setup>
import {
ref,
onMounted
} from 'vue' import {
onReady
} from '@dcloudio/uni-app' import {
Ball
} from '@/utils/Ball.js' import {
QuadTree
} from '@/utils/QuadTree.js' console.log(uni.getSystemInfoSync().screenWidth)
console.log(uni.getSystemInfoSync().windowWidth) const canvasSize = ref((uni.getSystemInfoSync().windowWidth < uni.getSystemInfoSync().windowHeight ? uni
.getSystemInfoSync()
.windowWidth : uni.getSystemInfoSync().windowHeight) - 100) const size = canvasSize.value / 32
const ballList = [] for (let i = 0; i < 30; i++) {
let x = Math.random() * canvasSize.value,
y = Math.random() * canvasSize.value,
r = Math.random() * size / 1.5 + 10,
color = randomHexColor()
const ball = new Ball(x, y, r, Math.random() * 7 + 3, Math.random() * 5 + 5, color, i)
ballList.push(ball)
} let ctx = null onReady(() => {
ctx = uni.createCanvasContext('game')
console.log(ballList)
}) let rAF const animateStart = () => {
render(ctx)
rAF = requestAnimationFrame(() => {
animateStart()
})
} const animateStop = () =>{
cancelAnimationFrame(rAF)
} const render = (ctx) => { const quadTree = new QuadTree(0, 0, canvasSize.value, canvasSize.value, 0) for (let i = 0; i < ballList.length; i++) {
quadTree.insert(ballList[i])
} for (let q of quadTree.possibles()) {
// console.log('*', Date.now())
ctx.setFillStyle("rgba(255, 170, 80, 0.2)")
ctx.setStrokeStyle('yellow')
ctx.fillRect(q.x, q.y, q.width, q.height)
ctx.strokeRect(q.x, q.y, q.width, q.height) for (let i = 0; i < q.sprites.length - 1; i++) {
for (let j = i + 1; j < q.sprites.length; j++) {
let a = q.sprites[i]
let b = q.sprites[j]
if (a.intersectAt(b)) { // 假设半径就是重量
let v1, v2, m1 = a.r,
m2 = b.r
// 先算水平速度
v1 = a.speedX
v2 = b.speedX a.speedX = (v1 * (m1 - m2) + 2 * m2 * v2) / (m1 + m2)
b.speedX = (v2 * (m2 - m1) + 2 * m1 * v1) / (m1 + m2)
// 再算垂直速度
v1 = a.speedY
v2 = b.speedY a.speedY = (v1 * (m1 - m2) + 2 * m2 * v2) / (m1 + m2)
b.speedY = (v2 * (m2 - m1) + 2 * m1 * v1) / (m1 + m2) //发生碰撞的小球,防止穿模,多走一步
a.move(canvasSize.value, canvasSize.value)
b.move(canvasSize.value, canvasSize.value) }
}
}
}
ballList.forEach((ball) => {
ball.move(canvasSize.value, canvasSize.value)
ball.fillTo(ctx)
}) ctx.draw() } function randomHexColor() {
//生成ffffff以内16进制数
var hex = Math.floor(Math.random() * 16777216).toString(16);
//while循环判断hex位数,少于6位前面加0凑够6位
while (hex.length < 6) {
hex = '0' + hex;
}
//返回‘#'开头16进制颜色
return '#' + hex;
}
</script> <style> </style>

uniapp中用canvas实现小球碰撞的小动画的更多相关文章

  1. HTML5 Canvas彩色小球碰撞运动特效

    脚本简介 HTML5 Canvas彩色小球碰撞运动特效是一款基于canvas加面向对象制作的运动小球动画特效.   效果展示 http://hovertree.com/texiao/html5/39/ ...

  2. Canvas+Js制作动量守恒的小球碰撞

    目的:通过js实现小球碰撞并实现动量守恒 canvas我们就不多说了,有用着呢. 我们可以通过canvas画2D图形(圆.方块.三角形等等)3D图形(球体.正方体等待). 当然这只是基础的皮毛而已,c ...

  3. canvas 模拟小球上抛运动的物理效果

    最近一直想用学的canvas做一个漂亮的小应用,但是,发现事情并不是想的那么简单.比如,游戏的逼真效果,需要自己来coding…… 所以,自己又先做了一个小demo,算是体验一下亲手打造物理引擎的感觉 ...

  4. 【h5游戏开发】egret引擎p2物理引擎 - 小球碰撞地面搞笑的物理现象

    重力的方向和地面的问题 p2中默认的方向是从上到下,如果重力默认是正数的话,物体放到世界中是会从上面往下面飘的 p2中plane地面默认的方向是y轴的方向,而在p2中y轴的方向默认是从上往下 首先来看 ...

  5. canvas动态小球重叠效果

    前面的话 在javascript运动系列中,详细介绍了各种运动,其中就包括碰壁运动.但是,如果用canvas去实现,却是另一种思路.本文将详细介绍canvas动态小球重叠效果 效果展示 静态小球 首先 ...

  6. js实现多个小球碰撞

    实现思路:小球的移动,是通过改变小球的left和top值来改变,坐标分别为(x,y)当x/y值加到最大,即加到父级的宽度或者高度时,使x值或者y值减小,同理当x值或者y值减到最小时,同样的使x值或者y ...

  7. js实现小球碰撞游戏

    效果图:  效果图消失只是截的gif图的问题 源码: <!DOCTYPE html> <html lang="en"> <head> <m ...

  8. Canvas 动态小球重叠效果

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  9. Canvas 图片绕边旋转的小动画

    /** * 图片绕边旋转的小动画 */ function initDemo10() { var canvas = document.getElementById("demo10") ...

随机推荐

  1. 好客租房55-props深入(2props校验)

    对于组件来说 props是外来的 无法保证使用者传入什么格式的数据 传入的数据格式不对 可能会导致组件内部报错 关键问题:不知道报错的具体原因 1安装包props-types 2导入props-typ ...

  2. linux篇-linux数据库mysql的安装

    1数据库文件放到opt下面 2赋予权限775 3运行脚本 4运行成功 5数据库操作 密码修改并刷新 权限修改,允许外部设备访问 6工具连接 7附录 1.显示当前数据库服务器中的数据库列表: mysql ...

  3. 技术管理进阶——空降Leader如何开展工作?

    原创不易,求分享.求一键三连 前几天有个粉丝咨询了一个的问题: 最近遇到一个空降Leader,挺苦恼的: 新Leader技术很厉害,但平时根本就不管我们,也不愿意了解业务,更像是一个技术顾问. 具体案 ...

  4. 主管发话:一周搞不定用友U8 ERP跨业务数据分析,明天就可以“毕业”了

    随着月末来临,又到了汇报总结的时刻. (图片来自网络) 到了这个特殊时期,你的老板就一定想要查看企业整体的运转情况.销售业绩.客户实况分析.客户活跃度.Top10 sales. 产品情况.订单处理情况 ...

  5. [CSP-S 2019 Day2]Emiya家今天的饭

    思路: 这种题目就考我们首先想到一个性质.这题其实容易想到:超限的菜最多只有一个,再加上这题有容斥那味,就枚举超限的菜然后dp就做完了. 推式子能力还是不行,要看题解. 式子还需要一个优化,就是废除冗 ...

  6. [XJOI3529] 左右

    题目链接:左右 Description 给你一个s数组,一个t数组,你可以对s数组执行以下两种操作 L 操作:每个数等于其左边的数加上自己 R 操作:每个数等于其右边的数加上自己 第一个数的左边是最后 ...

  7. django框架4

    内容概要 编辑删除功能编写 虚拟环境 django路由层版本区别 视图函数的返回值 JsonResponse对象 form表单上传文件 request其他方法 FBV与CBV(基于函数的视图.基于类的 ...

  8. Java泛型知识总结

    泛型 前言 在没有泛型之前,程序员必须使用Object编写适用于多种类型的代码.很繁琐,也不安全. 泛型的引入使Java有了一个很强的类型系统,允许设计者详细地描述变量和方法的类型要如何变化. 在普通 ...

  9. ER图/模型转换为关系模型

    ER图中的主要成分是实体类型和联系类型,转换规则就是如何把实体类型.联系类型转换成关系模式. 1. 二元联系转换 规则1.1(实体类型的转换):将每个实体类型转换成一个关系模式,实体的属性即为关系模式 ...

  10. WTM框架使用技巧之:CI/CD(持续集成/持续部署)

    1. 什么是WTM框架? 一个快速.灵活.社区活跃.最最最最高效的.netcore 后台管理系统.详见 https://wtmdoc.walkingtec.cn/ 欢迎大家付费支持WTMPlus,反哺 ...