前言
大家好,我是林三心,用最通俗易懂的话讲最难的知识点是我的座右铭,基础是进阶的前提是我的初心~
又很多朋友最近说想要入门 Canvas
,问我能不能出一篇讲解 Canvas
的文章,但是我感觉直接讲会比较无聊,还不如通过一些案例来让大家去手敲呢
所以我准备使用 Canvas
实现一个星星连线的小游戏,希望大家能喜欢~
效果 & 实现思路
期望的效果如下:
这个小游戏的开发可以分为以下几个步骤:
1、绘制一个小星星,并且让它能够移动起来。 2、创建一百个这样的小星星 3、当小星星相互靠近的时候,将它们连接起来 4、当鼠标移动的时候,生成小星星 5、当鼠标点击的时候,生成五个小星星
绘制一个小星星,并且让它能够移动起来
移动星星的操作实际上并不复杂。它的原理是先清除原有的星星,然后再重新绘制,同时借助定时器,这样就能营造出星星在移动的视觉效果。不过,这里有个需要注意的地方:当星星碰到边界的时候,要让它反弹回来
达到以下移动以及反弹的效果:
画一百个小星星
创建一个 数组stars
来存储这些星星
效果如下:
当星星之间靠近时,进行连线
若两个星星的 x
坐标与 y
坐标的差值均小于50
,那么就对这两个星星进行连线操作,而连线仅仅需要运用ctx.moveTo
和ctx.lineTo
即可达成
大家不妨思考一下,为何两个forEach
不能合并在一起执行呢?这是个颇具思考性的问题。或者大家也可以尝试将其合并执行,看看效果如何,这样就能明白了。这就算给大家布置的一个作业啦!
效果如下:
当鼠标移动的时候,生成小星星
也就是鼠标到哪,那个小星星就到哪,并且这个小星星走到哪都会跟距离近的小星星 连线
效果如下:
鼠标点击生成五个小星星
思路就是,鼠标点击,生成5个小星星,并加到 数组stars
中
效果如下:
完整代码
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
// 获取当前视图的宽度和高度
let aw = document.documentElement.clientWidth || document.body.clientWidth
let ah = document.documentElement.clientHeight || document.body.clientHeight
// 赋值给canvas
canvas.width = aw
canvas.height = ah
// 屏幕变动时也要监听实时宽高
window.onresize = function () {
aw = document.documentElement.clientWidth || document.body.clientWidth
ah = document.documentElement.clientHeight || document.body.clientHeight
// 赋值给canvas
canvas.width = aw
canvas.height = ah
}
// 本游戏无论是实心,还是线条,色调都是白色
ctx.fillStyle = 'white'
ctx.strokeStyle = 'white'
function Star(x, y, r) {
// x,y是坐标,r是半径
this.x = x
this.y = y
this.r = r
// speed参数,在 -3 ~ 3 之间取值
this.speedX = (Math.random() * 3) * Math.pow(-1, Math.round(Math.random()))
this.speedY = (Math.random() * 3) * Math.pow(-1, Math.round(Math.random()))
}
Star.prototype.draw = function () {
ctx.beginPath()
ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2)
ctx.fill()
ctx.closePath()
}
Star.prototype.move = function () {
this.x -= this.speedX
this.y -= this.speedY
// 碰到边界时,反弹,只需要把speed取反就行
if (this.x < 0 || this.x > aw) this.speedX *= -1
if (this.y < 0 || this.y > ah) this.speedY *= -1
}
function drawLine(startX, startY, endX, endY) {
ctx.beginPath()
ctx.moveTo(startX, startY)
ctx.lineTo(endX, endY)
ctx.stroke()
ctx.closePath()
}
const stars = []
for (let i = 0; i < 100; i++) {
// 随机在canvas范围内找一个坐标画星星
stars.push(new Star(Math.random() * aw, Math.random() * ah, 3))
}
const mouseStar = new Star(0, 0, 3)
canvas.onmousemove = function (e) {
mouseStar.x = e.clientX
mouseStar.y = e.clientY
}
window.onclick = function (e) {
for (let i = 0; i < 5; i++) {
stars.push(new Star(e.clientX, e.clientY, 3))
}
}
// 星星的移动
setInterval(() => {
ctx.clearRect(0, 0, aw, ah)
// 鼠标星星渲染
mouseStar.draw()
// 遍历移动渲染
stars.forEach(star => {
star.move()
star.draw()
})
stars.forEach((star, index) => {
// 类似于冒泡排序那样,去比较,确保所有星星两两之间都比较到
for (let i = index + 1; i < stars.length; i++) {
if (Math.abs(star.x - stars[i].x) < 50 && Math.abs(star.y - stars[i].y) < 50) {
drawLine(star.x, star.y, stars[i].x, stars[i].y)
}
}
if (Math.abs(mouseStar.x - star.x) < 50 && Math.abs(mouseStar.y - star.y) < 50) {
drawLine(mouseStar.x, mouseStar.y, star.x, star.y)
}
})
}, 50)
结语
我是林三心,一个待过小型toG型外包公司、大型外包公司、小公司、潜力型创业公司、大公司的作死型前端选手