成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁技術文章
文章詳情頁

VUE+Canvas 實現桌面彈球消磚塊小游戲的示例代碼

瀏覽:6日期:2022-09-30 16:59:19

大家都玩過彈球消磚塊游戲,左右鍵控制最底端的一個小木板平移,接住掉落的小球,將球彈起后消除畫面上方的一堆磚塊。

那么用VUE+Canvas如何來實現呢?實現思路很簡單,首先來拆分一下要畫在畫布上的內容:

(1)用鍵盤左右按鍵控制平移的木板;

(2)在畫布內四處彈跳的小球;

(3)固定在畫面上方,并且被球碰撞后就消失的一堆磚塊。

將上述三種對象,用requestAnimationFrame()函數平移運動起來,再結合各種碰撞檢查,就可以得到最終的結果。

先看看最終的效果:

VUE+Canvas 實現桌面彈球消磚塊小游戲的示例代碼

一、左右平移的木板

最底部的木板是最簡單的一部分,因為木板的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坐標(指的磚塊左上角的坐標)

for (let i = 0; i < _this.breaksConfig.row; i++) {for (let j = 0; j < _this.breaksConfig.colunm; j++) { _this.breaks.push({ x: this.breaksConfig.space * (j + 1) + this.breaksConfig.width * j, y: 10 * (i + 1) + this.breaksConfig.height * i, show: true });} }

再加上繪制磚塊的函數:

drawBreaks() { let _this = this; _this.breaks.forEach(item => {if (item.show) { _this.drawRoundRect( item.x, item.y, _this.breaksConfig.width, _this.breaksConfig.height, _this.breaksConfig.radius );} });}四、讓上面三個部分動起來

(function animloop() { if (!_this.gameOver) {_this.movePannel();_this.moveBall();_this.drawAll(); } else {_this.drawCrushBreaks(); } window.requestAnimationFrame(animloop);})();.... drawAll() { this.ctx.clearRect(0, 0, this.clientWidth, this.clientHeight); this.drawPannel(); this.drawBall(); this.drawScore(); this.drawBreaks();}五、游戲結束后的效果

在最開始的動圖里可以看到,游戲結束后,磚塊粉碎成了若干的小球掉落,這個其實和畫單獨的小球類似,思路就是把剩余的磚塊中心坐標處生產若干大小不等,運動軌跡不等,顏色不等的小球,然后繼續動畫。

getCurshBreaks() { let _this = this; this.breaks.forEach(item => {if (item.show) { item.show = false; for (let i = 0; i < 8; i++) { // 每個磚塊粉碎為8個小球 this.crushBalls.push({ x: item.x + this.breaksConfig.width / 2, y: item.y + this.breaksConfig.height / 2, dx: _this.getRandomArbitrary(-6, 6), dy: _this.getRandomArbitrary(-6, 6), r: _this.getRandomArbitrary(1, 4), color: _this.getRandomColor() }); }} });},drawCrushBreaks() { this.ctx.clearRect(0, 0, this.clientWidth, this.clientHeight); this.crushBalls.forEach(item => {this.ctx.beginPath();this.ctx.arc(item.x, item.y, item.r, 0, 2 * Math.PI);this.ctx.fillStyle = item.color;this.ctx.fill();this.ctx.closePath();item.x += item.dx;item.y += item.dy;if ( // 碰到左右墻壁 item.x - item.r < 0 || item.x + item.r > this.clientWidth) { item.dx = -item.dx;}if ( // 碰到上下墻壁 item.y - item.r < 0 || item.y + item.r > this.clientHeight) { item.dy = -item.dy;} });},

以上就是桌面彈球消磚塊小游戲的實現思路和部分代碼,實現起來很簡單,兩三百行代碼就可以實現這個小游戲。在小球的運動上可以進行持續優化,并且也可以增加難度選項操作。

最后附上全部的vue文件代碼,供大家參考學習:

<template> <div class='break-ball'> <canvas height='600'></canvas> <div v-if='gameOver'> <div class='dialog'><p class='once-again'>本輪分數:{{score}}分</p><p class='once-again'>真好玩!</p><p class='once-again'>再來一次~~</p><el-button @click='init'>開始</el-button> </div> </div> </div></template> <script>const randomColor = [ '#FF95CA', '#00E3E3', '#00E3E3', '#6F00D2', '#6F00D2', '#C2C287', '#ECFFFF', '#FFDC35', '#93FF93', '#d0d0d0'];export default { name: 'BreakBall', data() { return { clientWidth: 0, clientHeight: 0, ctx: null, crushBalls: [], pannel: {x: 0,y: 0,height: 8,width: 100,speed: 8,dx: 0 }, ball: {x: 0,y: 0,r: 8,dx: -4,dy: -4 }, score: 0, gameOver: false, breaks: [], breaksConfig: {row: 6, // 排數height: 25, // 磚塊高度width: 130, // 磚塊寬度radius: 5, // 矩形圓角space: 0, // 間距colunm: 6 // 列數 } }; }, mounted() { let _this = this; let container = document.getElementById('breakBall'); this.ctx = container.getContext('2d'); this.clientHeight = container.height; this.clientWidth = container.width; _this.init(); 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; }; (function animloop() { if (!_this.gameOver) {_this.movePannel();_this.moveBall();_this.drawAll(); } else {_this.drawCrushBreaks(); } window.requestAnimationFrame(animloop); })(); }, computed:{ showBreaksCount(){ return this.breaks.filter(item=>{return item.show; }).length; } }, methods: { init() { let _this = this; _this.gameOver = false; this.pannel.y = this.clientHeight - this.pannel.height; this.pannel.x = this.clientWidth / 2 - this.pannel.width / 2; this.ball.y = this.clientHeight / 2; this.ball.x = this.clientWidth / 2; this.score = 0; this.ball.dx = [-1,1][Math.floor(Math.random() * 2)]*4; this.ball.dy = [-1,1][Math.floor(Math.random() * 2)]*4; this.crushBalls = []; this.breaks = []; // 計算得出磚塊縫隙寬度 this.breaksConfig.space = Math.floor((this.clientWidth - this.breaksConfig.width * this.breaksConfig.colunm) / (this.breaksConfig.colunm + 1) ); for (let i = 0; i < _this.breaksConfig.row; i++) {for (let j = 0; j < _this.breaksConfig.colunm; j++) { _this.breaks.push({ x: this.breaksConfig.space * (j + 1) + this.breaksConfig.width * j, y: 10 * (i + 1) + this.breaksConfig.height * i, show: true });} } }, drawAll() { this.ctx.clearRect(0, 0, this.clientWidth, this.clientHeight); this.drawPannel(); this.drawBall(); this.drawScore(); this.drawBreaks(); }, 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; } }, 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(); } }, drawScore(){ this.ctx.beginPath(); this.ctx.font='14px Arial'; this.ctx.fillStyle = '#FFF'; this.ctx.fillText('分數:'+this.score,10,this.clientHeight-14); this.ctx.closePath(); }, drawCrushBreaks() { this.ctx.clearRect(0, 0, this.clientWidth, this.clientHeight); this.crushBalls.forEach(item => {this.ctx.beginPath();this.ctx.arc(item.x, item.y, item.r, 0, 2 * Math.PI);this.ctx.fillStyle = item.color;this.ctx.fill();this.ctx.closePath();item.x += item.dx;item.y += item.dy;if ( // 碰到左右墻壁 item.x - item.r < 0 || item.x + item.r > this.clientWidth) { item.dx = -item.dx;}if ( // 碰到上下墻壁 item.y - item.r < 0 || item.y + item.r > this.clientHeight) { item.dy = -item.dy;} }); }, getRandomColor() { return randomColor[Math.floor(Math.random() * randomColor.length)]; }, getRandomArbitrary(min, max) { return Math.random() * (max - min) + min; }, getCurshBreaks() { let _this = this; this.breaks.forEach(item => {if (item.show) { item.show = false; for (let i = 0; i < 8; i++) { this.crushBalls.push({ x: item.x + this.breaksConfig.width / 2, y: item.y + this.breaksConfig.height / 2, dx: _this.getRandomArbitrary(-6, 6), dy: _this.getRandomArbitrary(-6, 6), r: _this.getRandomArbitrary(1, 4), color: _this.getRandomColor() }); }} }); }, 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(); }, 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(); }, drawBreaks() { let _this = this; _this.breaks.forEach(item => {if (item.show) { _this.drawRoundRect( item.x, item.y, _this.breaksConfig.width, _this.breaksConfig.height, _this.breaksConfig.radius );} }); } }};</script> <!-- Add 'scoped' attribute to limit CSS to this component only --><style scoped lang='scss'>.break-ball { width: 900px; height: 600px; position: relative; #breakBall { background: #2a4546; } .container { position: absolute; top: 0; right: 0; bottom: 0; left: 0; background-color: rgba(0, 0, 0, 0.3); text-align: center; font-size: 0; white-space: nowrap; overflow: auto; } .container:after { content: ''; display: inline-block; height: 100%; vertical-align: middle; } .dialog { width: 400px; height: 300px; background: rgba(255, 255, 255, 0.5); box-shadow: 3px 3px 6px 3px rgba(0, 0, 0, 0.3); display: inline-block; vertical-align: middle; text-align: left; font-size: 28px; color: #fff; font-weight: 600; border-radius: 10px; white-space: normal; text-align: center; .once-again-btn { background: #1f9a9a; border: none; color: #fff; } }}</style>

到此這篇關于VUE+Canvas 實現桌面彈球消磚塊小游戲的文章就介紹到這了,更多相關vue彈球消磚塊小游戲內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Vue
相關文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
亚洲大胆女人| 国产精品一级久久久| 亚洲国内自拍| 国产嫩草影院久久久久| 国产成人在线视频网址| 在线观看国产91| 久久久久久久久久久久久女国产乱 | 18欧美亚洲精品| 91视视频在线观看入口直接观看www | 久久夜色精品一区| 成人av网站在线观看| 精品少妇一区二区三区| 高清成人免费视频| 日韩欧美国产一区二区三区| 精品一区二区在线观看| 欧美性受极品xxxx喷水| 久久精品999| 精品视频在线看| 看国产成人h片视频| 欧美丝袜丝交足nylons| 免费精品视频最新在线| 在线观看亚洲a| 精品在线亚洲视频| 在线播放一区二区三区| 久久成人免费日本黄色| 欧美三级日韩三级| 精品一区二区免费看| 日韩视频123| av在线不卡电影| 久久亚洲捆绑美女| 欧美1区视频| 中文字幕第一区| 精品动漫一区| 亚洲影院久久精品| 久久久久网址| 国产精品av久久久久久麻豆网| 国产精品久线在线观看| 亚洲美女网站| 一区二区三区四区在线播放| 国产亚洲网站| 日本欧美在线看| 欧美精品在线观看播放| 不卡一区二区在线| 中文字幕在线不卡一区 | 欧美日韩亚洲综合| 国产高清亚洲一区| 日韩欧美亚洲国产另类| 欧美99在线视频观看| 亚洲视频免费看| 国产精品入口| 日本欧美加勒比视频| 欧美老肥妇做.爰bbww| 国产成人免费在线观看不卡| 国产午夜精品久久久久久免费视| 黑人一区二区| 婷婷丁香久久五月婷婷| 69堂国产成人免费视频| av电影天堂一区二区在线| 国产三级一区二区三区| 亚洲美女色禁图| 免费人成精品欧美精品| 欧美一区二区成人6969| 欧美区国产区| 日本亚洲一区二区| 日韩一级片在线观看| 在线播放亚洲| 久久精品国产99国产精品| 久久综合九色综合欧美98| 亚洲激情综合| 久久91精品久久久久久秒播| 久久久精品免费免费| 国产精品毛片| 国产精品资源网站| 国产精品丝袜久久久久久app| 国产精品久久久久9999高清| 狠狠色伊人亚洲综合成人| 久久久精品人体av艺术| 亚洲尤物在线| 国产成人在线观看免费网站| 日本一二三四高清不卡| 国产欧美日韩| 国产河南妇女毛片精品久久久| |精品福利一区二区三区| 欧美午夜理伦三级在线观看| 色综合久久中文字幕综合网| 丝袜国产日韩另类美女| 精品少妇一区二区三区| 亚洲一区二区伦理| 国产成人a级片| 亚洲免费成人av| 日韩一区二区在线看片| 亚洲日本精品国产第一区| 国产毛片一区二区| 亚洲乱码精品一二三四区日韩在线| 欧亚洲嫩模精品一区三区| 欧美精品一区二区三区在线看午夜 | 日韩欧美在线网站| 亚洲一本视频| 精品写真视频在线观看| 国产精品美女久久久久久久| 在线视频观看一区| 欧美日一区二区在线观看| 日本麻豆一区二区三区视频| 国产欧美日韩亚州综合| 欧美在线综合视频| 亚洲欧洲综合| 狠狠色丁香九九婷婷综合五月| 国产欧美一区二区在线| 欧美日韩在线直播| 伊人蜜桃色噜噜激情综合| 国内精品在线播放| 最新欧美精品一区二区三区| 欧美三区在线视频| 99精品国产在热久久| 国产精品2024| 五月婷婷激情综合| 国产精品情趣视频| 欧美一级生活片| 性xx色xx综合久久久xx| 波多野结衣中文字幕一区 | 1024亚洲合集| 精品精品欲导航| 欧美亚洲动漫精品| 奶水喷射视频一区| 国语自产精品视频在线看抢先版结局 | 日韩精品一区二区三区在线观看| 久久久久久九九九九| 欧美视频福利| 成+人+亚洲+综合天堂| 精品一区二区免费在线观看| 亚洲国产va精品久久久不卡综合 | 在线观看欧美日本| 国产精品日韩精品欧美精品| 国产一区高清视频| jizzjizzjizz欧美| 国产麻豆精品theporn| 日韩在线一二三区| 成人免费在线观看入口| 久久久久久日产精品| 91精品国产综合久久精品图片| 久久精品欧洲| 永久久久久久| 欧美视频成人| 欧美一区二区| 北岛玲一区二区三区四区| 久久99精品久久久久久| 亚洲va韩国va欧美va精品| 国产精品第一页第二页第三页| 精品国产一二三| 欧美一区二区三区视频免费播放| 91高清视频在线| 久久天堂成人| 国产精品久久亚洲7777| 亚洲精品乱码久久久久久蜜桃91| 国产精品videosex极品| 欧美freesex交免费视频| 不卡的av中国片| 99视频一区二区| 成人高清视频免费观看| 国产99一区视频免费| 国产一区视频导航| 久久国产精品露脸对白| 日韩av网站免费在线| 婷婷夜色潮精品综合在线| 亚洲成人一区二区| 亚洲一二三四区不卡| 亚洲主播在线观看| 亚洲精品中文在线| 中文字幕人成不卡一区| 中文字幕一区二区视频| 国产精品午夜在线| 国产三级久久久| 日本一区二区三级电影在线观看 | 国产成人亚洲综合a∨婷婷| 国产原创一区二区| 激情国产一区二区| 国产精品一区二区三区乱码| 国产传媒欧美日韩成人| 国产传媒日韩欧美成人| 成人午夜电影久久影院| 国产成人在线视频免费播放| 国内精品国产成人国产三级粉色| 久久精品国产秦先生| 久久99精品国产麻豆婷婷 | 粉嫩aⅴ一区二区三区四区 | 午夜精品网站| 国语自产精品视频在线看8查询8| 在线成人黄色| 亚洲一区二区高清视频| 色哟哟日韩精品| 91成人在线观看喷潮| 欧美日韩一区二区三区视频| 7777精品伊人久久久大香线蕉 | 国产欧美视频在线观看| 中文字幕亚洲欧美在线不卡| 一片黄亚洲嫩模| 人人爽香蕉精品| 精品在线播放免费| 韩国在线一区二区| 成人免费视频caoporn|