VUE+Canvas实现简单的五子棋游戏
之前的canvas小游戲系列歡迎大家戳:
《VUE實現一個Flappy Bird~~~》
《VUE+Canvas實現上吊火柴人猜單詞游戲》
《VUE+Canvas 實現桌面彈球消磚塊小游戲》
《VUE+Canvas實現雷霆戰機打字類小游戲》
《VUE+Canvas實現財神爺接元寶小游戲》
在布局上,五子棋相比那些目標是隨機運動的游戲,實現起來相對簡單許多,思路也很清晰,總共分為:
(1)畫棋盤;
(2)監聽點擊事件畫黑白棋子;
(3)每次落子之后判斷是否有5子相連,有則贏。
最復雜的恐怕就是如何判斷五子棋贏了,那么就先從簡單的開始,畫個棋盤吧~
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循環里,我們還初始化了一個15 * 15的二維數組,并全部填上0,沒錯,就是記錄落子的。
2、監聽點擊事件畫黑白棋子
好了,我們在獲取dom的時候順便監聽一下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); }很容易可以計算出點擊坐標最近的那個棋盤交叉點,當然,如果那里已經落了子,就得return。然后在交點處畫上白子或者黑子,這里用漸變填充使棋子看起來更像那么回事。接著,在對應的二維數組里記錄一下棋子狀況:
setResultArr(m, n) {let _this = this;_this.resultArr[m][n] = _this.whiteTurn ? 1 : 2; // 白棋為1;黑棋為2}3、檢查五子棋輸贏結果
輸贏結果怎么判斷?肉眼看去,無非就是以當前落子為0,0原點建立坐標系,然后判斷0°,180°,45°和135°四條線上是否有連續5子。相比于直接遍歷計數,更好的方法就是取出四條線上的數據,然后判斷是否有相連的5個1或者2字符。
假設我們落子的數組坐標是[m, n]。
(1)橫線的結果數組字符串:this.resultArr[m].join('');
(2)豎線的結果數組字符串:
for(let?i?=?0;?i<15;?i++){
????????lineHorizontal.push(_this.resultArr[i][n]);
}
(3)135°(左上到右下):j從0-15,分別取this.resultArr[m?-?j][n?-j]結果unshift進臨時數組頭部,取this.resultArr[m?+?j][n?+?j]放到臨時數組尾部,行成結果;
(4)45°(左下到右上):j從0-15,分別取this.resultArr[m?+?j][n?-j]結果unshift進臨時數組頭部,取this.resultArr[m?-?j][n?+?j]放到臨時數組尾部,行成結果;
當然這里面都是要判斷一下數組越界。
得到結果字符串后,我們判斷是否有“22222”或者“11111”這樣的字符串存在,有則說明勝利。
checkResult(m ,n){ // 判斷是否有5子相連let _this = this;let checkStr = _this.whiteTurn ? CheckStrWhite : CheckStrBlack;// 取出[m,n]橫豎斜四條線的一維數組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;} }最后勝出,我們顯示一下是哪方獲勝。
至此,一個簡單的黑白棋游戲就做好了~~~~~
老規矩,源碼貼上:
<template><div class="gobang"><canvas id="gobang" width="800" 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: [] // 記錄棋子位置的數組};},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]橫豎斜四條線的一維數組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>可怕,記錄一下,留個念想
總結
以上是生活随笔為你收集整理的VUE+Canvas实现简单的五子棋游戏的全部內容,希望文章能夠幫你解決所遇到的問題。