JavaScript-Canvas 浮动的球(2)

JavaScript 是前端核心, 掌握这门语言是步入前端高手行列必经之路,噢,别忘了还有TypeScript, 学习它还需要OOP知识, 底层的浏览器原理、HTTP协议也必不可少, 此系列文章记录使用JavaScript和Canvas进行游戏开发, 有游戏才有趣!!!

很多彩色随机飘动的球

很多个浮动的球

在Canvas画布上绘制圆形,画多个不同大小的圆

1. 给一个模板页面

  • 模板页面中一点点的CSS样式,主要定义Canvas宽和高以及position
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>漂浮的球</title>
<style>
*{ padding: 0; margin: 0;}
body {
overflow: hidden;
}
#myCanvas {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
background-color: black;
}

</style>
</head>
<body>
<canvas id="myCanvas"></canvas>
<script>
</script>
</body>

2. 上一篇的JS代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
function Ball(x, y, radius, dx, dy) {
//x,y坐标
this.x = x
this.y = y

//移动的位置属性
this.dx = dx
this.dy = dy

//半径
this.radius = radius
//画圆的方法
this.draw = function() {
//这行必须的,为了不影响每个圆的绘制
ctx.beginPath()
//画圆, 需要坐标位置和半径大小,从0到360度, 最后一个参数表示是不是逆时针方向
ctx.arc(this.x,this.y,this.radius, 0, 2*Math.PI, false)
//颜色设置
ctx.strokeStyle = 'blue'
ctx.stroke()
//填充
ctx.fill()
}

this.update = function() {
//更新时判断是否超过左边和右边
if(this.x + this.radius > canvas.width || this.x-this.radius < 0) {
this.dx = -this.dx
}
//更新时判断是否超过上边和下边
if(this.y+this.radius > canvas.height || this.y-this.radius < 0) {
this.dy = -this.dy
}
//更改x和y的值
this.x += this.dx
this.y += this.dy

//调用画圆的方法
this.draw()
}
}

var ball = new Ball(200,200,3,3,30)

function animate() {
requestAnimationFrame(animate)
//清除画布上的所有内容
ctx.clearRect(0,0,canvas.width,canvas.height)
//更新位置
ball.update()
}

//调用动画函数
animate()

3. 换一种写法,使用ES6的语法定义类, 让坐标和颜色随机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Ball {
constructor() {
//随机坐标, 必须在Canvas宽度和高度范围内
this.x = Math.random() * canvas.width
this.y = Math.random() * canvas.height
//半径随机
this.radius = Math.random() * 15 + 1
//随机位置
this.dx = Math.random() * 3 - 1.5
this.dy = Math.random() * 3 - 1.5
//颜色使用hsla
this.color = 'hsla('+(Math.random()*360)+', 100%, 50%, 0.6)'
}

//画圆函数
draw() {
ctx.fillStyle = this.color
ctx.beginPath()
ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false)
ctx.fill()
}

//更新位置函数
update() {
if(this.x + this.radius > canvas.width || this.x - this.radius < 0) {
this.dx = -this.dx
}
if(this.y + this.radius > canvas.height || this.y - this.radius < 0) {
this.dy = -this.dy
}
this.x += this.dx
this.y += this.dy
}
}

4. 增加动画函数

1
2
3
4
5
6
7
8
9
10
11
//创建Ball对象
var ball = new Ball()

//动画函数
function animate() {
requestAnimationFrame(animate)
ctx.clearRect(0,0,canvas.width,canvas.height)
ball.draw()
ball.update()
}
animate()

单个球的实现效果

5. 多个球实现效果

  • 仅需要添加一个Ball数组,并且在动画函数中遍历并不断调用draw和update方法
1
2
3
4
5
6
7
8
//创建一个数组,用于存储多个球对象
let balls = []
function initBalls() {
for (let i = 0; i < 100; i++) {
balls.push(new Ball())
}
}
initBalls()
1
2
3
4
5
6
7
8
9
function animate() {
requestAnimationFrame(animate)
ctx.clearRect(0,0,canvas.width,canvas.height)
for (let i = 0; i < balls.length; i++) {
balls[i].draw()
balls[i].update()
}
}
animate()

6. 来点有意思的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function animate() {
requestAnimationFrame(animate)
ctx.clearRect(0,0,canvas.width,canvas.height)
for (let i = 0; i < balls.length; i++) {
balls[i].draw()
balls[i].update()
for (let j = i+1; j < balls.length; j++) {
//计算两点之间的距离
const dx = balls[i].x - balls[j].x
const dy = balls[i].y - balls[j].y
let distance = Math.sqrt(dx*dx + dy*dy)
//当粒子和粒子之间的距离小于200时画线
if(distance < 100) {
ctx.beginPath()
ctx.strokeStyle = balls[i].color
ctx.lineWidth = 1
ctx.moveTo(balls[i].x, balls[i].y)
ctx.lineTo(balls[j].x, balls[j].y)
ctx.stroke()
}
}
}
}
animate()

效果如图,知道这是什么原理吧