使用 canvas 绘制实现五子棋

<!DOCTYPE html>
<html  lang="en">
    <head>   
        <style>
            canvas {
                background-color: #0a0;
                display:block;
                margin:0 auto;
            }
            .tip {
                text-align: center;
                padding: 20px;
            }
        </style>
    </head>
    <body>
        <div class="tip">请黑棋落子</div>
        <script>
            //创建canvas标签
            const canvas = document.createElement("canvas")
            canvas.width = 800;
            canvas.height = 800; document.body.append(canvas)

            // 获取 tip 元素
            const tip = document.getElementsByClassName("tip")[0];

            //得到 context 对象
            const context = canvas.getContext("2d");

            const maxRow = 16;
            const maxCol = 16;

            // 画棋盘
            for(let i=1;i< maxCol;i++) {
                context.moveTo(50,50*i);
                context.lineTo(750,50*i);
                context.stroke();
            }
            for (let i = 1; i < maxRow; i++) {
                context.moveTo(50 * i,50);
                context.lineTo(50 * i,750);
                context.stroke();
            }

            // 使用变量保存当前棋子颜色
            let isBlack = true;
            // 使用二维数组存储棋子
            let circles = []
            for(let i=1;i< maxCol;i++) {
                circles[i] = []
            }
            // 设置一个变量确定是否可以结束游戏
            let endGame = false;

            // 当点击在棋盘里面时,绘制一个圆
            canvas.addEventListener("click",e =>{
                // 判断是否可以继续游戏
                if (endGame) {
                    return
                }

                let {offsetX,offsetY} = e;

                // 确定点击位置边界
                if(offsetX < 25 || offsetY < 25 || offsetX > 775 || offsetY > 775) {
                    return
                }

                // 确定棋子最终位置
                let i = Math.floor((offsetX + 25) / 50)
                let j = Math.floor((offsetY + 25) / 50)

                // 判断当前位置是否已经存在棋子
                if(circles[i][j]) {
                    // 也可以提醒用户当前位置已经有棋子了
                    tip.innerText =`这里不能重复落子,当前是${isBlack?"黑" :"白"}棋的回合` 
                    return
                }

                let x = i * 50;
                let y = j * 50;

                context.beginPath();
                context.arc(x,y,20,0,2*Math.PI)

                // 把对应棋子存放在二维数组中
                circles[i][j] = isBlack?'black' : 'white';

                // 判断当前棋子使用什么颜色
                let tx = isBlack? x-10 : x+10
                let ty = isBlack ? y - 10 : y + 10
                let gradient = context.createRadialGradient(tx, ty,0, tx, ty,30);
                gradient.addColorStop(0,isBlack ? "#ccc" : "#666");
                gradient.addColorStop(1, isBlack ? "#000" : "#fff");
                context.fillStyle= gradient;

                // 设置阴影美化棋子,增加立体感
                context.shadowBlur = 4;
                context.shadowColor = "#333";
                context.shadowOffsetX = 4;

                context.fill()
                context.closePath()

                // 判断当前棋子是否已经连成
                endGame = checkVertical(i,j) || checkHorizontal(i,j) || checkLurd(i,j) || checkRuld(i,j)
                if(endGame) {
                    tip.innerText = `${isBlack ? '黑' : '白'}棋已获胜,请刷新重新开始`
                    return
                }

                // 提醒用户 换人了
                isBlack = !isBlack
                tip.innerText = isBlack ? "请黑棋落子" : "请白棋落子"
            })
            
            // 纵向查找五子棋
            function checkVertical(row,col) {
                // 定义一个变量,记录向上的次数
                let up = 0;
                // 定义一个变量,记录向下的次数
                let down = 0;
                // 定义当前共有几个连接在一起
                let count = 1;
                let times = 0
                // 避免出现死循环
                while(times < 100) {
                    times++;
                    
                    let target = isBlack? "black" : "white";
                    // 以 row,col 为起点,在二维数组上,向上查找
                    up++;
                    if(col - up > 0 && circles[row][col-up] && circles[row][col-up] == target) {
                        count++;
                    }
                    down++;
                    // 以 row,col 为起点,在二维数组上,向下查找
                    if (col + down < maxCol && circles[row][col + down] && circles[row][col + down] == target) {
                        count++;
                    }

                    // 判断是否结束循环
                    if (count >= 5 || col + down < maxCol && col -up> 0 && circles[row][col-up] !== target && circles[row][col+down] !== target) {
                        break;
                    }
                }
                return count >=5
            }
            
            // 横向查找五子棋
            function checkHorizontal (row, col) {
                // 定义一个变量,记录向左的次数
                let left = 0;
                // 定义一个变量,记录向右的次数
                let right = 0;
                // 定义当前共有几个连接在一起
                let count = 1;
                let times = 0
                // 避免出现死循环
                while (times < 100) {
                    times++;

                    let target = isBlack ? "black" : "white";
                    // 以 row,col 为起点,在二维数组上,向左查找
                    left++;
                    if (row - left > 0 && circles[row - left][col] && circles[row - left][col] == target) {
                        count++;
                    }
                    right++;
                    // 以 row,col 为起点,在二维数组上,向右查找
                    if ( row + right<maxRow && circles[row + right][col] && circles[row + right][col] == target) {
                        count++;
                    }

                    // 判断是否结束循环
                    if (count >= 5 || row + right < maxRow && row - left > 0 && circles[row - left][col] !== target && circles[row + right][col] !== target) {
                        break;
                    }
                }
                return count >= 5
            }

            // 左上到右下查找五子棋
            function checkLurd (row, col) {
                // 定义一个变量,记录向左上的次数
                let lu = 0;
                // 定义一个变量,记录向右下的次数
                let rd = 0;
                // 定义当前共有几个连接在一起
                let count = 1;
                let times = 0
                // 避免出现死循环
                while (times < 100) {
                    times++;

                    let target = isBlack ? "black" : "white";
                    // 以 row,col 为起点,在二维数组上,向左上查找
                    lu++;
                    if (row - lu > 0 && col - lu > 0 && circles[row - lu][col - lu] && circles[row - lu][col - lu] == target) {
                        count++;
                    }
                    rd++;
                    // 以 row,col 为起点,在二维数组上,向右下查找
                    if (row + rd < maxRow && col + rd<maxCol && [row + rd][col + rd] && circles[row + rd][col + rd] == target) {
                        count++;
                    }

                    // 判断是否结束循环
                    if (count >= 5 || row + rd < maxRow && col + rd < maxCol && row - lu > 0 && col - lu > 0 && circles[row - lu][col - lu] !== target && circles[row + rd][col + rd] !== target) {
                        break;
                    }
                }
                return count >= 5
            }
            
            // 右上到左下查找五子棋
            function checkRuld (row, col) {
                // 定义一个变量,记录向右上的次数
                let ru = 0;
                // 定义一个变量,记录向左下的次数
                let ld = 0;
                // 定义当前共有几个连接在一起
                let count = 1;
                let times = 0
                // 避免出现死循环
                while (times < 100) {
                    times++;

                    let target = isBlack ? "black" : "white";
                    // 以 row,col 为起点,在二维数组上,向右上查找
                    ru++;
                    if ( row + ru <maxRow && col - ru >0 && [row + ru][col - ru] && circles[row + ru][col - ru] == target) {
                        count++;
                    }
                    ld++;
                    // 以 row,col 为起点,在二维数组上,向左下查找
                    if (row - ld>0 && col + ld <maxCol && [row - ld][col + ld] && circles[row - ld][col + ld] == target) {
                        count++;
                    }

                    // 判断是否结束循环
                    if (count >= 5 || row - ld > 0 && col + ld < maxCol && row + ru < maxRow && col - ru > 0 && circles[row + ru][col - ru] !== target && circles[row - ld][col + ld] !== target) {
                        break;
                    }
                }
                return count >= 5
            }

        </script>
    </body>
</html>

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在uni-app中使用canvas实现五子棋可以按照以下步骤进行: 1. 创建canvas组件 在需要使用canvas的页面中,添加一个canvas组件: ```html <canvas class="chessboard" canvas-id="canvas"></canvas> ``` 2. 获取canvas上下文 在页面的`onLoad`生命周期函数中,获取canvas的上下文: ```js onLoad() { // 获取canvas上下文 this.ctx = uni.createCanvasContext('canvas', this); } ``` 3. 绘制棋盘 绘制棋盘可以使用`ctx`的绘图API,例如`ctx.beginPath()`、`ctx.moveTo()`、`ctx.lineTo()`等。具体的绘制方法可以参考以下代码: ```js drawChessboard() { const cellWidth = this.data.cellWidth; const boardWidth = this.data.boardWidth; const rows = this.data.rows; const cols = this.data.cols; const margin = this.data.margin; // 绘制棋盘背景 this.ctx.fillStyle = '#D1B18F'; this.ctx.fillRect(0, 0, boardWidth, boardWidth); // 绘制棋盘格线 this.ctx.beginPath(); for (let i = 0; i < rows; i++) { this.ctx.moveTo(margin + cellWidth / 2, margin + i * cellWidth + cellWidth / 2); this.ctx.lineTo(boardWidth - margin - cellWidth / 2, margin + i * cellWidth + cellWidth / 2); } for (let i = 0; i < cols; i++) { this.ctx.moveTo(margin + i * cellWidth + cellWidth / 2, margin + cellWidth / 2); this.ctx.lineTo(margin + i * cellWidth + cellWidth / 2, boardWidth - margin - cellWidth / 2); } this.ctx.stroke(); } ``` 4. 绘制棋子 绘制棋子可以使用`ctx.arc()`和`ctx.fill()`方法实现。具体的绘制方法可以参考以下代码: ```js drawChess(x, y, color) { const cellWidth = this.data.cellWidth; const margin = this.data.margin; const radius = cellWidth / 2 - margin; // 计算棋子的坐标 const cx = margin + x * cellWidth; const cy = margin + y * cellWidth; // 绘制棋子 this.ctx.beginPath(); this.ctx.arc(cx, cy, radius, 0, 2 * Math.PI); this.ctx.fillStyle = color; this.ctx.fill(); } ``` 5. 绑定事件 在canvas上绑定事件可以使用`canvas`组件的`@touchstart`、`@touchmove`、`@touchend`等事件。具体的绑定方法可以参考以下代码: ```html <canvas class="chessboard" canvas-id="canvas" @touchstart="onTouchStart" @touchmove="onTouchMove" @touchend="onTouchEnd" ></canvas> ``` 6. 实现游戏逻辑 实现五子棋的游戏逻辑可以在页面的`methods`中进行。例如,判断胜负可以使用一个二维数组来记录棋盘上的棋子,然后通过遍历该数组来判断是否存在连成五个的棋子。具体的实现方法可以参考以下代码: ```js data() { return { // 棋盘格子的宽度 cellWidth: 30, // 棋盘的行数和列数 rows: 15, cols: 15, // 棋盘的宽度 boardWidth: 450, // 棋盘的边缘空白区域 margin: 15, // 棋子的颜色 chessColor: ['white', 'black'], // 当前下棋的玩家 currentPlayer: 0, // 棋盘上的棋子 chessboard: [], // 是否游戏结束 gameOver: false, }; }, onLoad() { this.ctx = uni.createCanvasContext('canvas', this); this.initChessboard(); this.drawChessboard(); }, initChessboard() { // 初始化棋盘 for (let i = 0; i < this.rows; i++) { this.chessboard[i] = []; for (let j = 0; j < this.cols; j++) { this.chessboard[i][j] = -1; } } }, onTouchStart(e) { // 获取触摸点的坐标 const x = e.touches[0].x; const y = e.touches[0].y; // 计算在棋盘中的位置 const i = Math.floor((y - this.data.margin) / this.data.cellWidth); const j = Math.floor((x - this.data.margin) / this.data.cellWidth); // 判断该位置是否为空 if (this.chessboard[i][j] === -1 && !this.gameOver) { // 绘制棋子 this.drawChess(j, i, this.chessColor[this.currentPlayer]); // 记录棋子 this.chessboard[i][j] = this.currentPlayer; // 判断是否胜利 if (this.checkWin(i, j, this.currentPlayer)) { this.gameOver = true; uni.showToast({ title: `玩家${this.currentPlayer + 1}胜利`, icon: 'none' }); return; } // 切换玩家 this.currentPlayer = 1 - this.currentPlayer; } }, checkWin(row, col, player) { const dirs = [[-1, 0], [1, 0], [0, -1], [0, 1], [-1, -1], [1, 1], [-1, 1], [1, -1]]; for (let i = 0; i < dirs.length; i++) { let count = 1; const dx = dirs[i][0]; const dy = dirs[i][1]; for (let j = 1; j < 5; j++) { const x = row + j * dx; const y = col + j * dy; if (x < 0 || x >= this.rows || y < 0 || y >= this.cols || this.chessboard[x][y] !== player) { break; } count++; } if (count === 5) { return true; } } return false; }, ``` 以上就是在uni-app中使用canvas实现五子棋的步骤,希望对你有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值