VUE+Canvas實現(xiàn)簡單五子棋游戲的全過程
在布局上,五子棋相比那些目標(biāo)是隨機(jī)運動的游戲,實現(xiàn)起來相對簡單許多,思路也很清晰,總共分為:
(1)畫棋盤;
(2)監(jiān)聽點擊事件畫黑白棋子;
(3)每次落子之后判斷是否有5子相連,有則贏。
最復(fù)雜的恐怕就是如何判斷五子棋贏了,那么就先從簡單的開始,畫個棋盤吧~
1、畫棋盤棋盤很簡單,我們畫個15*15的棋盤,橫線豎線相交錯:
drawCheckerboard() { // 畫棋盤 let _this = this; _this.ctx.beginPath(); _this.ctx.fillStyle = '#fff'; _this.ctx.rect(0, 0, 450, 450); _this.ctx.fill(); for (var i = 0; i < 15; i++) {_this.ctx.beginPath();_this.ctx.strokeStyle = '#D6D1D1';_this.ctx.moveTo(15 + i * 30, 15); //垂直方向畫15根線,相距30px;_this.ctx.lineTo(15 + i * 30, 435);_this.ctx.stroke();_this.ctx.moveTo(15, 15 + i * 30); //水平方向畫15根線,相距30px;_this.ctx.lineTo(435, 15 + i * 30);_this.ctx.stroke(); _this.resultArr.push(new Array(15).fill(0)); }}
先用一個450 * 450 的正方形打底,四周留15寬度的空白,然后畫上間隔為30的線。在for循環(huán)里,我們還初始化了一個15 * 15的二維數(shù)組,并全部填上0,沒錯,就是記錄落子的。
好了,我們在獲取dom的時候順便監(jiān)聽一下click事件,來畫棋子:
let container = document.getElementById('gobang');
container.addEventListener('click', _this.handleClick);
handleClick(event) { let x = event.offsetX - 70; let y = event.offsetY - 70; if (x < 15 || x > 435 || y < 15 || y > 435) {// 點出界的return; } this.drawChess(x, y); if(this.winGame){this.drawResult();return; } this.whiteTurn = !this.whiteTurn; this.drawText();}
畫棋子的代碼:
drawChess(x, y) { let _this = this; let xLine = Math.round((x - 15) / 30); // 豎線第x條 let yLine = Math.round((y - 15) / 30); // 橫線第y條 if(_this.resultArr[xLine][yLine] !== 0){return; } let grd = _this.ctx.createRadialGradient(xLine * 30 + 15,yLine * 30 + 15,4,xLine * 30 + 15,yLine * 30 + 15,10 ); grd.addColorStop(0, _this.whiteTurn ? '#fff' : '#4c4c4c'); grd.addColorStop(1, _this.whiteTurn ? '#dadada' : '#000'); _this.ctx.beginPath(); _this.ctx.fillStyle = grd; _this.ctx.arc(xLine * 30 + 15,yLine * 30 + 15,10,0,2 * Math.PI,false ); _this.ctx.fill(); _this.ctx.closePath(); _this.setResultArr(xLine, yLine); _this.checkResult(xLine, yLine);}
很容易可以計算出點擊坐標(biāo)最近的那個棋盤交叉點,當(dāng)然,如果那里已經(jīng)落了子,就得return。然后在交點處畫上白子或者黑子,這里用漸變填充使棋子看起來更像那么回事。接著,在對應(yīng)的二維數(shù)組里記錄一下棋子狀況:
setResultArr(m, n) { let _this = this; _this.resultArr[m][n] = _this.whiteTurn ? 1 : 2; // 白棋為1;黑棋為2 }
輸贏結(jié)果怎么判斷?肉眼看去,無非就是以當(dāng)前落子為0,0原點建立坐標(biāo)系,然后判斷0°,180°,45°和135°四條線上是否有連續(xù)5子。相比于直接遍歷計數(shù),更好的方法就是取出四條線上的數(shù)據(jù),然后判斷是否有相連的5個1或者2字符。
假設(shè)我們落子的數(shù)組坐標(biāo)是[m, n]。
(1)橫線的結(jié)果數(shù)組字符串:this.resultArr[m].join(’’);
(2)豎線的結(jié)果數(shù)組字符串:
for(let i = 0; i<15; i++){lineHorizontal.push(_this.resultArr[i][n]);}
(3)135°(左上到右下):j從0-15,分別取this.resultArr[m - j][n -j]結(jié)果unshift進(jìn)臨時數(shù)組頭部,取this.resultArr[m + j][n + j]放到臨時數(shù)組尾部,行成結(jié)果;
(4)45°(左下到右上):j從0-15,分別取this.resultArr[m + j][n -j]結(jié)果unshift進(jìn)臨時數(shù)組頭部,取this.resultArr[m - j][n + j]放到臨時數(shù)組尾部,行成結(jié)果;
當(dāng)然這里面都是要判斷一下數(shù)組越界。
得到結(jié)果字符串后,我們判斷是否有“22222”或者“11111”這樣的字符串存在,有則說明勝利。
checkResult(m ,n){ // 判斷是否有5子相連 let _this = this; let checkStr = _this.whiteTurn ? CheckStrWhite : CheckStrBlack; // 取出[m,n]橫豎斜四條線的一維數(shù)組 let lineVertical = _this.resultArr[m].join(’’); if(lineVertical.indexOf(checkStr) > -1){_this.winGame = true;return; } let lineHorizontal = []; for(let i = 0; i<15; i++){lineHorizontal.push(_this.resultArr[i][n]); } lineHorizontal = lineHorizontal.join(’’); if(lineHorizontal.indexOf(checkStr) > -1){_this.winGame = true;return; } let line135 = []; for(let j = 0; j < 15; j++){if(m - j >= 0 && n - j >= 0){ // 左上角 line135.unshift(_this.resultArr[m - j][n -j]);}if(j > 0 && m + j < 15 && n + j < 15){ // 右下角 line135.push(_this.resultArr[m + j][n + j]);} } line135 = line135.join(’’); if(line135.indexOf(checkStr) > -1){_this.winGame = true;return; } let line45 = []; for(let j = 0; j < 15; j++){if(m + j < 15 && n - j >= 0){ // 右上角 line45.unshift(_this.resultArr[m + j][n -j]);}if(j > 0 && m - j >=0 && n + j < 15){ // 左下角 line45.push(_this.resultArr[m - j][n + j]);} } line45 = line45.join(’’); if(line45.indexOf(checkStr) > -1){_this.winGame = true;return; }}
最后勝出,我們顯示一下是哪方獲勝。
至此,一個簡單的黑白棋游戲就做好了~~~~~
老規(guī)矩,源碼貼上:
<template> <div class='gobang'> <canvas height='600'></canvas> </div></template> <script>const CheckStrWhite = '11111';const CheckStrBlack = '22222';export default { name: 'Gobang', data() { return { ctx: null, winGame: false, whiteTurn: false, // 白棋輪;true-黑棋輪 resultArr: [] // 記錄棋子位置的數(shù)組 }; }, mounted() { let _this = this; let container = document.getElementById('gobang'); container.addEventListener('click', _this.handleClick); _this.ctx = container.getContext('2d'); _this.ctx.translate(70,70); _this.drawCheckerboard(); }, computed:{ chessText(){ return this.whiteTurn ? ’白棋’ : ’黑棋’; } }, methods: { drawCheckerboard() { // 畫棋盤 let _this = this; _this.ctx.beginPath(); _this.ctx.fillStyle = '#fff'; _this.ctx.rect(0, 0, 450, 450); _this.ctx.fill(); for (var i = 0; i < 15; i++) {_this.ctx.beginPath();_this.ctx.strokeStyle = '#D6D1D1';_this.ctx.moveTo(15 + i * 30, 15); //垂直方向畫15根線,相距30px;_this.ctx.lineTo(15 + i * 30, 435);_this.ctx.stroke();_this.ctx.moveTo(15, 15 + i * 30); //水平方向畫15根線,相距30px;棋盤為14*14;_this.ctx.lineTo(435, 15 + i * 30);_this.ctx.stroke(); _this.resultArr.push(new Array(15).fill(0)); } _this.drawText(); }, drawChess(x, y) { let _this = this; let xLine = Math.round((x - 15) / 30); // 豎線第x條 let yLine = Math.round((y - 15) / 30); // 橫線第y條 if(_this.resultArr[xLine][yLine] !== 0){return; } let grd = _this.ctx.createRadialGradient(xLine * 30 + 15,yLine * 30 + 15,4,xLine * 30 + 15,yLine * 30 + 15,10 ); grd.addColorStop(0, _this.whiteTurn ? '#fff' : '#4c4c4c'); grd.addColorStop(1, _this.whiteTurn ? '#dadada' : '#000'); _this.ctx.beginPath(); _this.ctx.fillStyle = grd; _this.ctx.arc(xLine * 30 + 15,yLine * 30 + 15,10,0,2 * Math.PI,false ); _this.ctx.fill(); _this.ctx.closePath(); _this.setResultArr(xLine, yLine); _this.checkResult(xLine, yLine); }, setResultArr(m, n) { let _this = this; _this.resultArr[m][n] = _this.whiteTurn ? 1 : 2; // 白棋為1;黑棋為2 },checkResult(m ,n){ // 判斷是否有5子相連 let _this = this; let checkStr = _this.whiteTurn ? CheckStrWhite : CheckStrBlack; // 取出[m,n]橫豎斜四條線的一維數(shù)組 let lineVertical = _this.resultArr[m].join(’’); if(lineVertical.indexOf(checkStr) > -1){_this.winGame = true;return; } let lineHorizontal = []; for(let i = 0; i<15; i++){lineHorizontal.push(_this.resultArr[i][n]); } lineHorizontal = lineHorizontal.join(’’); if(lineHorizontal.indexOf(checkStr) > -1){_this.winGame = true;return; } let line135 = []; for(let j = 0; j < 15; j++){if(m - j >= 0 && n - j >= 0){ // 左上角 line135.unshift(_this.resultArr[m - j][n -j]);}if(j > 0 && m + j < 15 && n + j < 15){ // 右下角 line135.push(_this.resultArr[m + j][n + j]);} } line135 = line135.join(’’); if(line135.indexOf(checkStr) > -1){_this.winGame = true;return; } let line45 = []; for(let j = 0; j < 15; j++){if(m + j < 15 && n - j >= 0){ // 右上角 line45.unshift(_this.resultArr[m + j][n -j]);}if(j > 0 && m - j >=0 && n + j < 15){ // 左下角 line45.push(_this.resultArr[m - j][n + j]);} } line45 = line45.join(’’); if(line45.indexOf(checkStr) > -1){_this.winGame = true;return; } }, drawText(){ let _this = this; _this.ctx.clearRect(435 + 60, 0, 100, 70); _this.ctx.fillStyle = '#fff'; _this.ctx.font='20px Arial'; _this.ctx.fillText(’本輪:’ + _this.chessText, 435 + 70, 35); }, drawResult(){ let _this = this; _this.ctx.fillStyle = '#ff2424'; _this.ctx.font='20px Arial'; _this.ctx.fillText(_this.chessText+’勝!’, 435 + 70, 70); }, handleClick(event) { let x = event.offsetX - 70; let y = event.offsetY - 70; if (x < 15 || x > 435 || y < 15 || y > 435) {// 點出界的return; } this.drawChess(x, y); if(this.winGame){this.drawResult();return; } this.whiteTurn = !this.whiteTurn; this.drawText(); } }};</script> <!-- Add 'scoped' attribute to limit CSS to this component only --><style scoped lang='scss'>.gobang { #gobang { background: #2a4546; }}</style>總結(jié)
到此這篇關(guān)于VUE+Canvas實現(xiàn)簡單五子棋游戲的文章就介紹到這了,更多相關(guān)VUE+Canvas五子棋游戲內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!
相關(guān)文章:
1. 在Android中使用WebSocket實現(xiàn)消息通信的方法詳解2. 淺談python出錯時traceback的解讀3. Python importlib動態(tài)導(dǎo)入模塊實現(xiàn)代碼4. python matplotlib:plt.scatter() 大小和顏色參數(shù)詳解5. windows服務(wù)器使用IIS時thinkphp搜索中文無效問題6. ASP 信息提示函數(shù)并作返回或者轉(zhuǎn)向7. Nginx+php配置文件及原理解析8. 利用promise及參數(shù)解構(gòu)封裝ajax請求的方法9. .NET中l(wèi)ambda表達(dá)式合并問題及解決方法10. JSP數(shù)據(jù)交互實現(xiàn)過程解析
