(五) JavaScript-Canvas球球乱撞

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

效果图

(五) JavaScript-Canvas球球乱撞

JavaScript-Canvas-自由运动的球 这一节里,实现了单个球自由地在Canvas画布中运动,本节将它完善一下,创建N个球在Canvas画布中胡乱飞,见上图;这些球相互之间不会碰撞,如果需要实现这个功能,还需加点油,跟着来就对了。

  • 本节JavaScript 技术要点

    • 定义数组 和使用数组, 貌似一见到数组有些人就犯难了

    • 随机设置颜色

    • 控制一下球的运动速度(其实这算不上技术,顶多是个技巧)

1. JavaScript-Canvas-自由运动的球 最终代码如下

  • 需要在这个代码上面增加一点内容来实现 多球自由运动
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<!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>Document</title>
<style>
*{padding: 0; margin: 0;}
#canvas {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
/** @type {HTMLCanvasElement} */
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
canvas.width = window.innerWidth
canvas.height = window.innerHeight

class Circle {
constructor(x, y, dx, dy, radius) {
this.x = x
this.y = y
this.dx = dx
this.dy = dy
this.radius = radius
}
//画一个圆
draw() {
ctx.beginPath()
ctx.arc(this.x,this.y,this.radius,0,2*Math.PI, false)
//线样式
ctx.strokeStyle = 'blue'
ctx.stroke()
//填充
ctx.fill()
}

//更新圆的位置
update() {
//判断圆是否超出canvas边界,判断时需要将半径也算上
if(this.x + this.radius > canvas.width || this.x-this.radius < 0){
//如果超出x轴左右两边的边界则重新设置 dx的值
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

//调用draw()函数重新画圆
this.draw()
}
}


//创建一个圆
var circle = new Circle(200,200,3,3,30)
//调用update函数
circle.update()

//动画函数
function animate() {
//不断请求动画帧,每次请求都会重新调用一次animate,
requestAnimationFrame(animate)
ctx.clearRect(0,0,canvas.width,canvas.height)
circle.update()
}
animate()

</script>
</body>
</html>

2. Circle数组

  • 既然要有多个球,那么可以定义一个数组,数组中的元素为Circle对象, 每个圆的初始位置都随机生成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//声明一个数组
var circleArray = []
//循环50次,产生50个Circle对象
for (let i = 0; i < 50; i++) {
//自动生成x,y坐标,范围必须在Canvas画布内
let x = Math.random() * (canvas.width-radius*2) + radius
let y = Math.random() * (canvas.height-radius*2) + radius
//速度控制, dx和dy表示移动的位置,此时也随机生成
let dx = (Math.random() - 0.5) * 6
let dy = (Math.random() - 0.5) * 8
let radius = 30
//创建Circle对象,并添加到数组中
circleArray.push(new Circle(x,y,dx,dy,radius))
}

3. 动画函数中遍历数组

  • 遍历数组时不断的调用 Circle对象的update()方法
1
2
3
4
5
6
7
8
function animate() {
requestAnimationFrame(animate)
ctx.clearRect(0,0,canvas.width,canvas.height)
for (let i = 0; i < circleArray.length; i++) {
circleArray[i].update()
}
}
animate()

4. 完整代码

  • 增加了随机颜色
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
<!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>Document</title>
<style>
*{padding: 0; margin: 0;}
#canvas {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
/** @type {HTMLCanvasElement} */
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
canvas.width = window.innerWidth
canvas.height = window.innerHeight

class Circle {
constructor(x, y, dx, dy, radius) {
this.x = x
this.y = y
this.dx = dx
this.dy = dy
this.radius = radius
//增加一个颜色属性
this.color = 'hsla('+(Math.random()*360)+', 100%, 50%, 0.6)'
}
//画一个圆
draw() {
ctx.beginPath()
//设置填充颜色
ctx.fillStyle = this.color

ctx.arc(this.x,this.y,this.radius,0,2*Math.PI, false)
//线样式
//ctx.strokeStyle = 'blue'
//ctx.stroke()
//填充
ctx.fill()
}

//更新圆的位置
update() {
//判断圆是否超出canvas边界,判断时需要将半径也算上
if(this.x + this.radius > canvas.width || this.x-this.radius < 0){
//如果超出x轴左右两边的边界则重新设置 dx的值
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

//调用draw()函数重新画圆
this.draw()
}
}


//***************************************************************
//声明一个数组
var circleArray = []
//循环50次,产生50个Circle对象
for (let i = 0; i < 50; i++) {
//自动生成x,y坐标,范围必须在Canvas画布内
let x = Math.random() * (canvas.width-radius*2) + radius
let y = Math.random() * (canvas.height-radius*2) + radius
//速度控制, dx和dy表示移动的位置,此时也随机生成
let dx = (Math.random() - 0.5) * 6
let dy = (Math.random() - 0.5) * 8
let radius = 30
//创建Circle对象,并添加到数组中
circleArray.push(new Circle(x,y,dx,dy,radius))
}
//****************************************************************

//**********************动画函数**********************
function animate() {
requestAnimationFrame(animate)
ctx.clearRect(0,0,canvas.width,canvas.height)
for (let i = 0; i < circleArray.length; i++) {
circleArray[i].update()
}
}
//**********************动画函数**********************

//别忘记调用
animate()

</script>
</body>
</html>

本节中利用数组存储了多个Circle对象,在动画函数中遍历数组并调用update方法更新 Circle的位置, 后续我们增加特效,让球和球之间有连线