(六) JavaScript-Canvas-星座

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

最终效果图

(六) JavaScript-Canvas-星座

(五) JavaScript-Canvas球球乱撞的基础上增加一些小小的特效,简单的平面几何的应用-勾股定理,两个点之间画一条线

1. 上一篇 的最终代码

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>

2. 增加新的功能

  • 球和球之间画一条线,要实现此功能需要用到毕达哥拉斯定理,也就是勾股定理。

  • 在遍历数组的时候,将当前球的位置和其它所有球的位置进行距离计算,如果距离小于一定值,则画一条线

  • 计算过程如下图所示

  • 关键代码

    1
    2
    3
    4
    5
    6
    7
    //两点之间的距离计算
    //计算两个Circle 对象的 x 坐标之差
    const newX = circleArray[i].x - circleArray[j].x
    //计算两个Circle 对象的 y 坐标之差
    const newY = circleArray[i].y - circleArray[j].y
    //使用毕达哥拉斯定理,已知两边求第三边
    let distance = Math.sqrt(newX*newX + newY*newY)
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

function animate() {
requestAnimationFrame(animate)
ctx.clearRect(0,0,canvas.width,canvas.height)
for (let i = 0; i < circleArray.length; i++) {
//画图函数的调用放于此处
circleArray[i].draw()
//更新
circleArray[i].update()

//**************************增加的代码***************************************
//遍历当前Circle对象之外的所有Circle,计算当前Circle对象和其它每个Circle之间的距离,使用毕达哥拉斯定理(勾股定理)
for (let j = i+1; j < circleArray.length; j++) {

//两点之间的距离计算
//计算两个Circle 对象的 x 坐标之差
const newX = circleArray[i].x - circleArray[j].x
//计算两个Circle 对象的 y 坐标之差
const newY = circleArray[i].y - circleArray[j].y
//使用毕达哥拉斯定理,已知两边求第三边
let distance = Math.sqrt(newX*newX + newY*newY)

//当粒子和粒子之间的距离小于100时画线
if(distance < 100) {
//路径开始
ctx.beginPath()
//颜色设定为当前对象的color
ctx.strokeStyle = circleArray[i].color
//线宽设置
ctx.lineWidth = 1
//两个点 连成一根线
ctx.moveTo(circleArray[i].x, circleArray[i].y)
ctx.lineTo(circleArray[j].x, circleArray[j].y)
ctx.stroke()
}
}
//****************************************************************************

}
}


计算过程如下图所示:

3. 完整代码

  • 稍做改动,球的半径不再固定,改成随机生成
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<!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 = Math.random() * 15 + 1

//增加一个颜色属性
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

}
}


//***************************************************************
//声明一个数组
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].draw()
//更新
circleArray[i].update()

//**************************增加的代码***************************************
//遍历当前Circle对象之外的所有Circle,计算当前Circle对象和其它每个Circle之间的距离,使用毕达哥拉斯定理(勾股定理)
for (let j = i+1; j < circleArray.length; j++) {

//两点之间的距离计算
//计算两个Circle 对象的 x 坐标之差
const newX = circleArray[i].x - circleArray[j].x
//计算两个Circle 对象的 y 坐标之差
const newY = circleArray[i].y - circleArray[j].y
//使用毕达哥拉斯定理,已知两边
let distance = Math.sqrt(newX*newX + newY*newY)

//当粒子和粒子之间的距离小于100时画线
if(distance < 100) {
//路径开始
ctx.beginPath()
//颜色设定为当前对象的color
ctx.strokeStyle = circleArray[i].color
//线宽设置
ctx.lineWidth = 1
//两个点 连成一根线
ctx.moveTo(circleArray[i].x, circleArray[i].y)
ctx.lineTo(circleArray[j].x, circleArray[j].y)
ctx.stroke()
}
}
//****************************************************************************

}
}
//**********************动画函数**********************

//别忘记调用
animate()

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

本节内容主要是平面几何中的原理应用到实际图形开发中,是不是很有趣? 在这个基础之上还可以做出更多的效果。