各人都玩过弹球消砖块游戏,阁下键节制最底端的一个小木板平移,接住掉落的小球,将球弹起后消除画面上方的一堆砖块。
那么用VUE+Canvas如何来实现呢?实现思路很简朴,首先来拆分一下要画在画布上的内容:
(1)用键盘阁下按键节制平移的木板;
(2)在画布内四处弹跳的小球;
(3)牢靠在画面上方,而且被球碰撞后就消失的一堆砖块。
将上述三种工具,用requestAnimationFrame()函数平移举动起来,再团结各类碰撞查抄,就可以获得最终的功效。
先看看最终的结果:
一、阁下平移的木板最底部的木板是最简朴的一部门,因为木板的y坐标是牢靠的,我们配置木板的初始参数,包罗其宽度,高度,平移速度等,然后实现画木板的函数:
pannel: { x: 0, y: 0, height: 8, width: 100, speed: 8, dx: 0 }, .... drawPannel() { this.drawRoundRect( this.pannel.x, this.pannel.y, this.pannel.width, this.pannel.height, 5 ); }, drawRoundRect(x, y, width, height, radius) { // 画圆角矩形 this.ctx.beginPath(); this.ctx.arc(x + radius, y + radius, radius, Math.PI, (Math.PI * 3) / 2); this.ctx.lineTo(width - radius + x, y); this.ctx.arc( width - radius + x, radius + y, radius, (Math.PI * 3) / 2, Math.PI * 2 ); this.ctx.lineTo(width + x, height + y - radius); this.ctx.arc( width - radius + x, height - radius + y, radius, 0, (Math.PI * 1) / 2 ); this.ctx.lineTo(radius + x, height + y); this.ctx.arc( radius + x, height - radius + y, radius, (Math.PI * 1) / 2, Math.PI ); this.ctx.fillStyle = "#008b8b"; this.ctx.fill(); this.ctx.closePath(); }
措施初始化的时候,监听键盘的阁下偏向键,来移动木板,通过长度判定是否移动到了阁下界线使其不能继承移出画面:
document.onkeydown = function(e) { let key = window.event.keyCode; if (key === 37) { // 左键 _this.pannel.dx = -_this.pannel.speed; } else if (key === 39) { // 右键 _this.pannel.dx = _this.pannel.speed; } }; document.onkeyup = function(e) { _this.pannel.dx = 0; }; .... movePannel() { this.pannel.x += this.pannel.dx; if (this.pannel.x > this.clientWidth - this.pannel.width) { this.pannel.x = this.clientWidth - this.pannel.width; } else if (this.pannel.x < 0) { this.pannel.x = 0; } },
二、弹跳的小球和碰撞检测小球的举动和木板雷同,只是不只有dx的偏移,尚有dy的偏移。
并且还要有碰撞检测:
(1)当碰撞的是上、右、左墙壁以及木板上的时候则反弹;
(2)当碰撞到是木板以外的下界线的时候,则输掉游戏;
(3)当碰撞的是砖块的时候,被碰的砖块消失,分数+1,小球反弹。
于是和木板一样,将小球部门分为画小球函数drawBall()和小球举动函数moveBall():
drawBall() { this.ctx.beginPath(); this.ctx.arc(this.ball.x, this.ball.y, this.ball.r, 0, 2 * Math.PI); this.ctx.fillStyle = "#008b8b"; this.ctx.fill(); this.ctx.closePath(); }, moveBall() { this.ball.x += this.ball.dx; this.ball.y += this.ball.dy; this.breaksHandle(); this.edgeHandle(); }, breaksHandle() { // 触碰砖块检测 this.breaks.forEach(item => { if (item.show) { if ( this.ball.x + this.ball.r > item.x && this.ball.x - this.ball.r < item.x + this.breaksConfig.width && this.ball.y + this.ball.r > item.y && this.ball.y - this.ball.r < item.y + this.breaksConfig.height ) { item.show = false; this.ball.dy *= -1; this.score ++ ; if(this.showBreaksCount === 0){ this.gameOver = true; } } } }); }, edgeHandle() { // 边沿检测 // 遇到顶部反弹 if (this.ball.y - this.ball.r < 0) { this.ball.dy = -this.ball.dy; } if ( // 遇到阁下墙壁 this.ball.x - this.ball.r < 0 || this.ball.x + this.ball.r > this.clientWidth ) { this.ball.dx = -this.ball.dx; } if ( this.ball.x >= this.pannel.x && this.ball.x <= this.pannel.x + this.pannel.width && this.ball.y + this.ball.r >= this.clientHeight - this.pannel.height ) { // 球的x在板子范畴内并触遇到了板子 this.ball.dy *= -1; } else if ( (this.ball.x < this.pannel.x || this.ball.x > this.pannel.x + this.pannel.width) && this.ball.y + this.ball.r >= this.clientHeight ) { // 球遇到了底边沿了 this.gameOver = true; this.getCurshBreaks(); } }
三、砖块的生成砖块的生成也较量简朴,这里我们初始了一些数据:
breaksConfig: { row: 6, // 排数 height: 25, // 砖块高度 width: 130, // 砖块宽度 radius: 5, // 矩形圆角 space: 0, // 间距 colunm: 6 // 列数 }
按照这些设置项以及画布宽度,我们可以计较出每个砖块的横向间隙是几多:
// 计较得出砖块偏差宽度 this.breaksConfig.space = Math.floor( (this.clientWidth - this.breaksConfig.width * this.breaksConfig.colunm) / (this.breaksConfig.colunm + 1) );
于是我们可以获得每个砖块在画布中的x,y坐标(指的砖块左上角的坐标)