HTML5+JavaScript实现连连看游戏

HTML5+JavaScript实现连连看游戏

连连看游戏连接规则:

只能连接相同图案(或图标、字符)的方块。

连线路径必须是由直线段组成的,最多可以有两个拐角。

连线路径必须是空的,不能穿过其他方块。

当两个相同图案的方块被有效连接时,它们会从游戏板上消失。当所有方块都被消除时,玩家获胜。

运行效果:

源码如下(参考https://blog.csdn.net/time1812/article/details/79513508 略有修改):

html 复制代码
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>连连看</title>
    <style>
        /* 单元格边框样式 */
        .border {
            display: inline-block;
            width: 40px;
            height: 40px;
            font-weight: 600;
            font-size: 36px;
            margin: 1px;
        }

        /* 显示路径时的样式 */
        .border.showPath {
            background-color: #99FF00;
        }

        /* 单元格样式 */
        .cell {
            display: inline-block;
            width: 40px;
            height: 40px;
            border: 1px solid #0099FF;
            text-align: center;
            font-weight: 600;
            font-size: 36px;
            background-color: #FFFFFF;
            color: #000000;
        }

        /* 选中单元格的样式 */
        .cell.selected {
            background-color: #3399FF;
            color: #FFFFFF;
        }
 
        /* 显示路径的单元格样式 */
        .cell.showPath {
            background-color: #99FF00;
        }

        /* 行样式 */ 
        .row {
            display: block;
            height: 42px;
        }

        /* 游戏区域的边框样式 */
        #game {
            border: 2px solid #0033FF;
            width: 600px; /* 设置游戏区域的宽度  */
        }
    </style>
</head>
<body onselectstart="return false">
    <div id="game"></div>
    <script type="text/javascript">
        let nx = 12, ny = 8; // 游戏网格的宽和高
        let gameDiv = document.getElementById('game');
        let selectedCell = null; // 当前选中的方块
        let empty = '&nbsp;'; // 空方块
        let count = nx * ny; // 方块总数
        let cellArray = []; // 存储方块的数组

        // 获取特定坐标的方块
        function fc(x, y) {
            return (x < 0 || x > nx + 1 || y < 0 || y > ny + 1) ? null : cellArray[y][x];
        }

        // 获取方块的邻居
        function neighbors(c) {
            return [
                fc(c.x - 1, c.y),
                fc(c.x + 1, c.y),
                fc(c.x, c.y + 1),
                fc(c.x, c.y - 1)
            ];
        }

        // 查找连接路径
        function findPath(c, target, pathStack, turnCount) {
            if (!c) return false;
            let prev = pathStack[pathStack.length - 2];
            if (prev && prev.x !== c.x && prev.y !== c.y && ++turnCount > 2) return false;
            if (c === target) {
                pathStack.push(c);
                return true;
            }
            if (c.innerHTML !== empty || pathStack.includes(c)) return false;

            pathStack.push(c);
            let nexts = neighbors(c);
            for (let next of nexts) {
                if (findPath(next, target, pathStack, turnCount)) return true;
            }
            pathStack.pop();
            return false;
        }

        // 清除路径样式
        function clearPath(path) {
            for (let cell of path) {
                cell.classList.remove('showPath');
            }
        }

        // 绘制路径
        function drawPath(path) {
            for (let cell of path) {
                cell.classList.add('showPath');
            }
            setTimeout(clearPath, 150, path);
        }

        // 尝试匹配两个方块
        function tryMatch(ca, cb) {
            if (ca === cb || ca.innerHTML !== cb.innerHTML) return;

            let pathStack = [ca];
            let found = false;
            let nexts = neighbors(ca);
            for (let next of nexts) {
                if (findPath(next, cb, pathStack, 0)) {
                    found = true;
                    break;
                }
            }

            if (!found) return;

            ca.innerHTML = cb.innerHTML = empty;
            setTimeout(drawPath, 10, pathStack);
            count -= 2;
            if (count < 2) alert('You win!');
        }

        // 处理方块点击事件
        function onCellClicked() {
            if (this.innerHTML === empty) return;

            if (selectedCell) {
                tryMatch(selectedCell, this);
                selectedCell.className = 'cell';
                selectedCell = null;
            } else {
                selectedCell = this;
                selectedCell.className = 'cell selected';
            }
        }

        // 初始化游戏网格
        function init(m, n) {
            for (let i = 0; i < n + 2; i++) {
                let row = document.createElement('div');
                row.className = 'row';
                let cellArrayRow = [];
                cellArray.push(cellArrayRow);
                gameDiv.appendChild(row);
                for (let j = 0; j < m + 2; j++) {
                    let cell = document.createElement('div');
                    cellArrayRow.push(cell);
                    if (i === 0 || j === 0 || i === n + 1 || j === m + 1) {
                        cell.className = 'border';
                        cell.innerHTML = empty;
                    } else {
                        cell.className = 'cell';
                        cell.addEventListener('click', onCellClicked);
                    }
                    cell.id = j + '_gc_' + i;
                    cell.x = j;
                    cell.y = i;
                    row.appendChild(cell);
                }
            }
        }
        
        // 随机重置游戏
        function reset() {
            let all = count = nx * ny;
            let halfAll = all / 2;
            let tmp = [];
            for (let i = 0; i < halfAll; i++) {
                let c = symbols.charAt(Math.floor(Math.random() * 35));
                tmp.push(c, c);
            }
            for (let i = all - 1; i >= 0; i--) {
                let r = Math.floor(Math.random() * i);
                let c = tmp.splice(r, 1);
                let y = Math.floor(i / nx);
                let x = i - y * nx;
                fc(x + 1, y + 1).innerHTML = c;
            }
        }

        init(nx, ny);
        //let symbols = 'ABCDEFGHIGKLMNOPQRSTUVWXYZ123456789'; // 可用符号
        let symbols = 'πφω▽Ф#*∩+■▲▼◆●★♀∽※⊕☆㐃□◇△◎○Ω⊙Θ☮☯㊣@$θ'; // 可用符号

        reset(); // 初始化游戏
    </script>
</body>
</html>
相关推荐
fury_12334 分钟前
当大的div中有六个小的div,上面三个下面三个,当外层div高变大的时候我希望里面的小的div的高也变大
前端·javascript·html
大鸡腿最好吃1 小时前
为啥react要用jsx
前端·javascript·react.js
小黄编程快乐屋1 小时前
前端小练习——大雪纷飞(JS没有上限!!!)
开发语言·前端·javascript
程序猿阿伟1 小时前
《平衡之策:C++应对人工智能不平衡训练数据的数据增强方法》
前端·javascript·c++
STUPID MAN1 小时前
vue3使用后端传递的文件流进行文件预览
前端·javascript·vue.js·文件预览
-代号95271 小时前
【React】二、状态变量useState
前端·javascript·react.js
爬坑的小白1 小时前
el-menu导航三级数据结构及数据展示
前端·javascript·vue.js
guokanglun2 小时前
JavaScript 键盘控制移动
开发语言·javascript
温轻舟2 小时前
前端开发 之 15个页面加载特效中【附完整源码】
前端·javascript·css·html
前端青山2 小时前
CSS 动画效果实现:图片展示与交互
开发语言·前端·javascript·css·vue.js·前端框架