2048 逻辑编程以及注意事项

本文详细介绍了一款基于浏览器的2048数字游戏的实现原理及代码结构,包括使用HTML、CSS和JavaScript构建游戏界面的过程,以及核心的逻辑算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

                                                        2048

  • 游戏介绍

  2048是一款数字小游戏,游戏规则很简单,操作按键 上↑下↓左←右→来操作数字的移动。

  • 游戏构成

  运行环境:浏览器界面

  文件组成: HTML  CSS  JS

  游戏界面:

    

  • 原理

游戏的实现不是很复杂,HTML界面就是简单的  4*4 网格,我采用的是  div 元素盒子包裹16个小div盒子,CSS样式方面简单设置就可以,  重点在 JS 逻辑。

我总结的js要点如下:

  1. 首先要定义两组变量来分别表示HTML页面的  行 和 列。

  2. 定义二维数组data来保存数字

  3. data数组中的数组发生变化并不影响到HTML页面的显示内容,所以定义函数 updataView() 来把data数组中数字的变化更新到 HTML 页面上。

  4. 随机生成数字 2 或 4 是反复执行的,所以要用循环来执行这个操作。

  5. random()方法可返回介于0.0~1.0之间的一个随机数。生成的随机数 *RN/CN 来确定数字应该放入的随机位置。

  6. 移动所有行/列不可能一步操作就能实现,所以先移动一行/列,然后用循环操作来达到移动所有行/列的效果。

  7. 判断是否移动是进行接下来操作的先决条件。打个比方:一个小时之前我在学校大门口碰到你了,现在我在食堂又一次看到你了,那我就认为你发生了移动。   用在这里也一样:  先将data转为字符串保存在before中执行完一些操作以后再将将data转为字符串保存在after中,然后判断before和after是否相等(before=after?),如果 before=after 就认为没有发生移动,如果 before!=after 就认为数字发生了变化也就是发生了移动。

  8. 移动一行原理图

 

  • 游戏代码

HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>2048</title>
    <link rel="stylesheet" href="2048.css">
</head>
<body>
<!--1.得分:score    这里是得分记录板-->
<p>SCORE:
    <span id="score">0</span>
</p>
    <!--2.接下来采用代码补全的方式来设计一个4*4的游戏界面-->
    <!--代码补全:  div#gridPanel>div#c00*16 +TAB -->
    <div id="gridPanel">
        <div id="c00"></div>
        <div id="c01"></div>
        <div id="c02"></div>
        <div id="c03"></div>

        <div id="c10"></div>
        <div id="c11"></div>
        <div id="c12"></div>
        <div id="c13"></div>

        <div id="c20"></div>
        <div id="c21"></div>
        <div id="c22"></div>
        <div id="c23"></div>

        <div id="c30"></div>
        <div id="c31"></div>
        <div id="c32"></div>
        <div id="c33"></div>
    </div>
<!--3.接下来是游戏结束面板-->
<div id="gameover">
    <p>
        GAME OVER!<br>
        SCORE:<span id="final">0</span><br>
        <a href="javascript:start()">TRY AGAIN!</a>
    </p>
</div>
<script src="2048.js"></script>
</body>
</html>

 

CSS:

#gridPanel{
    width: 480px;
    height: 480px;
    margin: 0 auto;
    border-radius: 10px;
    background:#bbada0;
}
div>div{
    width: 100px;
    height: 100px;
    margin-top: 16px;
    margin-left: 16px;
    float: left;
    background: #ccc0b3;
    border-radius: 6px;

    color: #fff;
    font-size: 60px;
    text-align: center;
    line-height: 100px;

}

.n2{background-color:#eee3da}
.n4{background-color:#ede0c8}
.n8{background-color:#f2b179}
.n16{background-color:#f59563}
.n32{background-color:#f67c5f}
.n64{background-color:#f65e3b}
.n128{background-color:#edcf72}
.n256{background-color:#edcc61}
.n512{background-color:#9c0}
.n1024{background-color:#33b5e5}
.n2048{background-color:#09c}
.n4096{background-color:#a6c}
.n8192{background-color:#93c}
.n2,.n4{color:#776e65}
.n1024,.n2048,.n4096,.n8192{font-size:40px}

p{
    width: 480px;margin: 0 auto;
    font-size: 40px;font-weight: bold;
    font-family: Arial;padding-top: 15px;
}
#gameover{
    display: none;
    /*要让div.gameover铺满全屏*/
    position: absolute;top: 0;left: 0;
    bottom: 0;right: 0;
    background: rgba(55,55,55,.5);
}
#gameover>p{
    width: 300px;
    height:200px;background: #ffffff;
    position: absolute;  top:50%;left: 50%;
    margin-top: -100px;margin-left: -150px;
    text-align: center;line-height: 1.5em;
    border-radius: 10px;
    border: 1px solid #edcf72;
}
#gameover a{
    padding: 10px;
    background: #9f8d77;
    color: #ffffff;
    border-radius: 6px;
    text-decoration: none;
}

 

JS:

var RN=4,CN=4;//定义总行数,总列数
var data;//定义变量date保存二维数组
var score=0;//保存得分
var status=0;//保存游戏状态
//0:表示游戏结束   1:表示运行中
const RUNNING=1, GAMEOVER=0;
//启动游戏
function start() {
    //将游戏状态置为运行中
    status=RUNNING;
    //将得分归0
    score=0;
    //创建空数组保存在data中
    data=[];
    //r从0到<RN
    for (var r=0;r<RN;r++){
        //向data中压入一个空的子数组
        data.push([]);
        //c从0到<CN结束
        for (var c=0;c<CN;c++){
            //为data中r行c位置保存一个0
            data[r][c]=0;
        }
    }
    console.log(data.join("\n"));
    //随机生成2个2或4
    randomNum();randomNum();
    //将data中的数据更新到页面内容中(调用函数 updataView)
    updataView();
    //为当前页面添加键盘按下处理函数
    document.onkeydown=function (e) {
        //判断按键号
        switch (e.keyCode){
            //左
            case 37: moveLeft(); break;
            //上
            case 38: moveUp(); break;
            //右
            case 39: moveRight(); break;
            //下
            case 40: moveDown(); break;
        }
    }
}
//将data中的每个元素填写到页面的对应div中
function updataView() {
    //双重循环  遍历 data
    for (var r=0;r<RN;r++){
        for (var c=0;c<CN;c++) {
            //用r,c拼对应div的id
            var id = "c" + r + c;
            //用id找到对应div
            var div=document.getElementById(id);
            //如果data中r行c列不为0 将data中r行c列的值保存到div的内容中 否则清空页面中 div 的内容(因为r行c列为0 也有可能是值发生了移动,而页面的值会呆在原地并不会移动)
            if (data[r][c] != 0){
                div.innerHTML = data[r][c];
                //设置div的class为n+data[r][c]
                div.className = "n" + data[r][c];
            }else {
                div.innerHTML = "";
                //清空div的class
                div.className = "";
            }

        }
    }
    //设置id为score的span的内容为score(将内存中计算的得分显示到页面上)
    var span=document.getElementById("score");
    span.innerHTML=score;
    //找到游戏结束的界面div
    var div=document.getElementById("gameover");
    //如果游戏结束
    if (status==GAMEOVER){
        //找到id为final的span,设置其内容为score
        var span=document.getElementById("final");
        span.innerHTML=score;
        //设置gameoverdiv显示
        div.style.display="block";
    }else {
        div.style.display="none";
    }
}
//在data中一个随机位置生成2或4
function randomNum() {
    //反复
    while (true){
        //random()方法可返回介于0~1之间的一个随机数
        //在0~RN-1之间生成一个随机整数保存在r
        var r=parseInt(Math.random()*RN);
        //在0~CN-1之间生成一个随机整数保存在c
        var c=parseInt(Math.random()*CN);
        //以上两句代码意思是  在4*4界面中找随机位置

        //如果data中r行c列的值为0
        if (data[r][c]==0){
            //为data中r行c列随机保存一个2或4
            data[r][c]=Math.random()<0.5?2:4;
            //退出循环
            break;
        }
    }
}
//左移所有行
function moveLeft() {
    //将data转为字符串保存在before中
    var before=String(data);
    //r从0到<RN
    for (var r=0;r<RN;r++){
        //左移第r行
        moveLeftInRow(r);
    }
    //将data转为字符串保存在after中
    var after=String(data);
    //如果before不等于after(这里相当于不同时间在同一地点拍照,照片内容有变化就认为发生了移动)
    if (before!=after){
        //随机生成一个2或4
        randomNum();
        //如果游戏结束就修改游戏状态为GAMEOVER
        if (isGAMEOVER()) status=GAMEOVER;
        //更新页面
        updataView();
    }
}
//左移第r行
function moveLeftInRow(r) {
    //c从0开始,到<CN-1
    for(var c=0;c<CN-1;c++){
        //找r行c右侧下一个不为0的位置nextc
        var nextc=getNextcInRow(r,c);
        //如果没找到就退出循环
        if (nextc==-1)break;
        else {
            //如果c位置的值为0
            if (data[r][c]==0){
                //将nextc位置的值赋值给c位置
                data[r][c]=data[r][nextc];
                //将nextc位置的值置为0
                data[r][nextc]=0;
                //将c-1
                c--;
            }else if (data[r][c]==data[r][nextc]){
                //否则如果c位置的值等于nextc位置的值
                //将c位置的值*2
                data[r][c]*=2;
                //将*2后的元素值累加到score中
                score+=data[r][c];
                //将nextc位置的值置为0
                data[r][nextc]=0;
            }
        }
    }
}
//找r行c列右侧下一个不为0的位置
function getNextcInRow(r,c) {
    //nextc从c+1开始,到<CN结束
    for(var nextc=c+1;nextc<CN;nextc++){
        //如果data中r行nextc位置不等于0就返回nextc
        if (data[r][nextc]!=0) return nextc;
    }
    //返回-1
    return -1;
}
//右移所有行
function moveRight() {
    //将data专为字符串保存到before中
    var before=String(data);
    //r从0开始,到<RN结束
    for (var r=0;r<RN;r++){
        //右移第r行
        moveRightInRow(r);
    }
    //将data转为字符串保存在after中
    var after=String(data);
    //如果before不等于after时
    if (before!=after){
        //随机生成2或4
        randomNum();
        //如果游戏结束就修改游戏状态为GAMEOVER
        if (isGAMEOVER()) status=GAMEOVER;
        //更新页面
        updataView();
    }
}
//右移第r行
function moveRightInRow(r) {
    //c从CN-1开始,到>0结束,递减1
    for (var c=CN-1;c>0;c--){
        //查找r行c列左侧前一个不为0的位置prevc
        var prevc=getPrevcInRow(r,c);
        //如果没有找到就退出循环
        if (prevc==-1) break;
        else {
            //如果c位置的值为0
            if (data[r][c]==0){
                //用prevc位置的值代替c位置的值
                data[r][c]=data[r][prevc];
                //将prevc位置的值置为0
                data[r][prevc]=0;
                //c+1
                c++;
            }else if (data[r][c]==data[r][prevc]){
                //否则如果c位置的值等于prevc位置的值  那么将c位置的值*2
                data[r][c]*=2;
                //将*2后的元素值累加到score中
                score+=data[r][c];
                //将prevc位置的值置为0
                data[r][prevc]=0;
            }
        }
    }
}
//查找r行c列左侧前一个不为0的位置
function getPrevcInRow(r,c) {
    //prevc从c-1开始,到>=0,递减1
    for (var prevc=c-1;prevc>=0;prevc--){
        //如果data中r行prevc位置的值不等于0就返回prevc
        if (data[r][prevc]!=0) return prevc;
    }
    //返回-1
    return -1;
}
//上移所有列
function moveUp() {
    //将data转为字符串保存到before中
    var before=String(data);
    //c从0到<CN
    for (var c=0;c<CN;c++){
        //上移第c列
        moveUpInCol(c);
    }
    //将data转为字符串保存在after中
    var after=String(data);
    //如果before不等于after
    if (before!=after){
        //随机生成一个2或4
        randomNum();
        //如果游戏结束就修改游戏状态为GAMEOVER
        if (isGAMEOVER()) status=GAMEOVER;
        //更新页面
        updataView();
    }
}
//上移第c列
function moveUpInCol(c) {
    //r从0到RN-1
    for (var r=0;r<RN-1;r++){
        //找c列r行下方第一个不为0的位置nextr
        var  nextr=getNextrInCol(r,c);
        //如果没找到就退出循环
        if (nextr==-1) break;
        else {
            //如果r行c列的值为0
            if (data[r][c]==0){
                //就用nextr行c列的值代替r行c列的值
                data[r][c]=data[nextr][c];
                //将nextr行c列的值置为0
                data[nextr][c]=0;
                //r留在原地
                r--;
            }else if (data[r][c]==data[nextr][c]){
                //否则如果r行c列的值等于nextr行c列的值,就将r行c列的值*2
                data[r][c]*=2;
                //将*2后的元素值累加到score中
                score+=data[r][c];
                //将nextr行c列的值置为0
                data[nextr][c]=0;
            }
        }
    }
}
//查找r行c列下方下一个不为0的位置
function getNextrInCol(r,c) {
    //nextr从r+1开始到<RN结束
    for (var nextr=r+1;nextr<RN;nextr++){
        //如果nextr行c列的值不为0就返回nextr
        if (data[nextr][c]!=0) return nextr;
    }
    //返回 -1
    return -1;
}
//下移所有列
function moveDown() {
    //将data转为字符串保存到before
    var before=String(data);
    //c从0开始——> <CN结束
    for(var c=0;c<CN;c++){
        //下移第c列
        moveDownInCol(c);
    }
    //将data转为字符串保存到after中
    var after=String(data);
    //如果before!=after
    if (before!=after){
        //随机生成一个2或4
        randomNum();
        //如果游戏结束就修改游戏状态为GAMEOVER
        if (isGAMEOVER()) status=GAMEOVER;
        //更新页面
        updataView();
    }

}
//下移第c列
function moveDownInCol(c) {
    //r从RN-1到0
    for(var r=RN-1;r>0;r--){
        //找c列r行上一个不为0的位置
        var prevr=getPrevrInCol(r,c);
        //如果没有找到就退出循环
        if (prevr==-1) break;
        else {
            //如果c列r行的值为0
            if (data[r][c]==0){
                //将c列prevr行的值给r行c列
                data[r][c]=data[prevr][c];
                //将c列prevr行置0
                data[prevr][c]=0;
                //将r留在原地
                r++;
            }else if (data[r][c]==data[prevr][c]){
                //如果两者相等  将原来的值*2
                data[r][c]*=2;
                //将该结果累加到 score中
                score+=data[r][c];
                //将上一位置的值清空
                data[prevr][c]=0;
            }
        }
    }
}
//查找上一个不为0的位置
function getPrevrInCol(r,c) {
    //prevr从RN-1开始到prevr>=0结束
    for(var prevr=r-1;prevr>=0;prevr--){
        //如果data[prevr][c]!=0  返回prevr
        if (data[prevr][c]!=0) return prevr;
    }
    //返回  -1
    return -1;
}
//判断游戏是否结束
function isGAMEOVER() {
    //遍历data
    for (var r=0;r<RN;r++){
        for (var c=0;c<CN;c++){
            //如果当前元素是0,就返回false
            if (data[r][c]==0) return false;
            //如果c<CN-1且当前元素等于右侧元素就返回false
            if (c<CN-1&&data[r][c]==data[r][c+1]) return false;
            //如果r<RN-1切当前元素等于下方元素就返回false
            if (r<RN-1&&data[r][c]==data[r+1][c]) return false;
        }
    }
    //返回true
    return true;
}

start();

 

  • 注意事项

要让页面div元素铺满全屏有两种方法

  1.    position: absolute;top: 0;left: 0; bottom: 0;right: 0;
  2.    width: 100%;height: 100%;
      
      opacity(模糊)是可以继承的
      解决方法:background:rgba()可以有效的避免继承   :background: rgba(55,55,55,.5);

  • 总结

以上内容纯属个人见解还有很多不足之处,如有兴趣希望可以互相交流一下心得体会。代码部分并非原创,也有参考其他资料和各大博主的文章内容,还请见谅。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值