前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >键码经典游戏:快速实现可运行的 2048

键码经典游戏:快速实现可运行的 2048

作者头像
掘金安东尼
发布2023-10-27 15:33:54
2030
发布2023-10-27 15:33:54
举报
文章被收录于专栏:掘金安东尼

序言

欢迎来到“2048”的魔法阵 🔢

本篇带来简易版-2048 数字游戏的编程实践~

废话少说,直接开冲!!

先看码上掘金效果:

image.png
image.png

设计思路

首先,玩过 2048 的都知道:基础版本是一个 4x4 的网格,作为游戏的主界面;

image.png
image.png

然后关键是生成数字和移动,即:

1、游戏在开始时和每次数字移动后要随机在空白格子生成数字2或4

2、玩家可以通过上、下、左、右箭头键移动数字。相同的数字在移动过程中会合并

接着就是,每一轮操作后,游戏界面格子的数字要实时更新;

按照这个思路,设想一下:会有哪些函数方法?

那么,一些基础的应该有比如:

  • initializeGame(): 初始化游戏界面,生成4x4的网格;
  • handleInput(event): 处理用户的键盘输入,控制数字的移动方向;
  • slide(direction): 根据用户的输入移动和合并数字;
  • getColumn(col): 获取指定列的数字,辅助处理上下移动的逻辑;
  • addNumber(): 在空白的格子中随机生成数字2或4;
  • render(): 更新并渲染游戏界面,显示当前的数字分布;

代码实现

有了基本思路,直接开撸~

HTML 和 CSS 部分比较简单,JS 部分按照上述思路逐步细化:

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>2048 Game</title>
    <style>
        #game-container {
            display: grid;
            grid-template-columns: repeat(4, 100px);
            grid-template-rows: repeat(4, 100px);
            gap: 10px;
            margin: 50px auto;
        }

        .cell {
            width: 100px;
            height: 100px;
            background-color: #f4f4f4;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 32px;
            font-weight: bold;
        }
    </style>
</head>

<body>

    <div id="game-container"></div>

    <script>
        const size = 4;
        let grid = Array(size).fill().map(() => Array(size).fill(''));

        function createCell(row, col) {
            const cell = document.createElement('div');
            cell.id = `cell-${row}-${col}`;
            cell.className = 'cell';
            return cell;
        }
        
        // 初始化4x4的网格
        function initializeGame() {
            const gameContainer = document.getElementById('game-container');
            for (let row = 0; row < size; row++) {
                for (let col = 0; col < size; col++) {
                    gameContainer.appendChild(createCell(row, col));
                }
            }
        }

        document.addEventListener('keydown', handleInput);

        // 处理用户的键盘输入
        function handleInput(event) {
            let gridChanged = false;
            switch (event.key) {
                case 'ArrowUp':
                    gridChanged = slide('up');
                    break;
                case 'ArrowDown':
                    gridChanged = slide('down');
                    break;
                case 'ArrowLeft':
                    gridChanged = slide('left');
                    break;
                case 'ArrowRight':
                    gridChanged = slide('right');
                    break;
            }
            // 如果网格发生了改变,添加新的数字并重新渲染界面
            if (gridChanged) {
                addNumber();
                render();
            }
        }

        // 根据用户的输入移动和合并数字
        function slide(direction) {
            const originalGrid = JSON.stringify(grid);
            for (let i = 0; i < size; i++) {
                let row = (direction === 'up' || direction === 'down') ? getColumn(i) : grid[i].slice();
                row = row.filter(cell => cell !== ''); // Remove empty cells
                if (direction === 'down' || direction === 'right') {
                    row.reverse();
                }

                for (let j = 1; j < row.length; j++) {
                    if (row[j - 1] === row[j]) {
                        row[j - 1] *= 2;
                        row[j] = '';
                    }
                }

                row = row.filter(cell => cell !== ''); // Remove merged cells

                while (size - row.length) {
                    row.push(''); // Fill the row with empty cells
                }

                if (direction === 'down' || direction === 'right') {
                    row.reverse();
                }

                if (direction === 'up' || direction === 'down') {
                    for (let j = 0; j < size; j++) {
                        grid[j][i] = row[j];
                    }
                } else {
                    grid[i] = row;
                }
            }

            return JSON.stringify(grid) !== originalGrid;
        }

        // 获取指定列的数字
        function getColumn(col) {
            const column = [];
            for (let i = 0; i < size; i++) {
                column.push(grid[i][col]);
            }
            return column;
        }

        // 在空白的格子中随机生成数字2或4
        function addNumber() {
            const availableCells = [];
            for (let i = 0; i < size; i++) {
                for (let j = 0; j < size; j++) {
                    if (!grid[i][j]) {
                        availableCells.push({ row: i, col: j });
                    }
                }
            }

            if (availableCells.length) {
                const { row, col } = availableCells[Math.floor(Math.random() * availableCells.length)];
                grid[row][col] = Math.random() < 0.9 ? 2 : 4;
            }
        }

        // 更新并渲染游戏界面
        function render() {
            grid.forEach((row, i) => {
                row.forEach((number, j) => {
                    const cell = document.getElementById(`cell-${i}-${j}`);
                    cell.textContent = number || '';
                });
            });
        }

        initializeGame();
        addNumber();
        addNumber();
        render();
    </script>

</body>

</html>

打完收工,整个代码思路比较清晰的~ 我们将代码分割成多个函数,使每个函数都有明确的职责,也可以提高代码的可读性和可维护性。

代码调优

更进一步:代码调优;毕竟代码总是有优化的空间。

针对以上代码,我们还有能做的,比如:

1、还差一个结束判断,即当没有空格且所有相邻的数字都不相等时,添加一个函数来判断游戏是否结束,并给出相应的提示;

2、还可以为玩家提供撤销上一步的操作的功能,增加游戏的可玩性;

3、还可以考虑兼顾响应式兼容等等

所以以上只是一个简易版的 2048,可以更快地帮助我们理解代码的功能和运行机制


以上!以上便是本次键码经典游戏之 2048 分享;

感兴趣的同学可以动手试试~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-10-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 序言
  • 设计思路
  • 代码实现
  • 代码调优
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档