2048小游戏——简简单单利用js做出自己的游戏!!

这篇博客教你如何利用JavaScript轻松创建属于自己的2048小游戏。从游戏逻辑梳理、CSS样式设计到JS代码实现,包括游戏界面设计、开始与结束状态判断、视图更新、操作按键响应等关键步骤,让你一步步构建出完整的游戏功能。

博主教你轻轻松松利用js技巧 写出属于自己的2048小游戏!!

在这里插入图片描述

自己做出实现在页面中

想必大家都听说过甚至玩过2048这款小游戏 博主无聊时也会拿起手机或者在电脑上玩上几把 但是大家有没有想过自己花费点时间做出一个2048游戏 会不会非常有成就感呢?
在这里插入图片描述
废话不多说 开始

一.首先大家要整理一下逻辑。

首先大家在打开电脑,准备敲代码写出游戏的时候,一定要先思考,该游戏的每一步应该用什么样的逻辑判断去表达,包括游戏的输赢判断条件是什么,有没有理清楚,建议没玩过的宝贝们可以下载一个去玩玩,是非常有必要的。

1>游戏的界面应该怎么样用css去设计更为美观

每个人都有自己的审美观 在做到保证基本样式的情况下 可以添加一些自己的元素进去

2>游戏的开始与结束:

需要添加:游戏进行状态(status) 游戏结束状态(gameover) 游戏运行状态 (gamerunning)

然后分别写出游戏开始的代码块封装成一个函数 命名为“start游戏开始函数”。然后写出游戏在什么状态下会结束,写出一个总的判断条件封装成“gameover游戏结束函数”。

3>游戏的视图更新 分数,样式,数据

需要添加:游戏得分属性(score) 游戏数据存储数组[data]

然后写出游戏进行时视图的更新.样式的变化.数据的变化.分数的变化 封装成一个函数用来进行调用。

>特别重要的操作按钮键

创建键盘上下左右键按下事件绑定各自的功能
按下左键 数字移动功能封装成一个函数
按下左键 数字进行相加的功能以及判定封装成两个函数

为了保证游戏的完整性 所有的封装函数功能都是相辅相成的 所以每一个都是不可缺少的

二 在HTML文档中利用css写出游戏基本样式

因为布局比较简单 博主在这简单介绍一下我的布局 主要还是讲解js部分
首先打开百度搜索2048小游戏 然后对比页面进行设计 先上博主的效果图:
在这里插入图片描述

(ul li) 标签部分为游戏格 用div写也是一样的效果

注意:博主为了方便稍后的调用 li标签的id名 才设置成这个样子 与行列一一对应

(div的tab属性名标签)为游戏分数与历史分数
(div的zhebu属性名标签)为游戏结束后全屏遮布效果
<body>

    <div class="father">
        <div class="top_1">
            <div class="top_l">
                <p class="bigzi">2048</p>
                <p class="bigzi1">Play 2048 Game Online</p>
                <p class="bigzi2">Join the numbers and get to the <b>2048 tile!</b> </p>
            </div>
            <div class="top_r">
                <div class="tab tab1">
                    <p>BEST</p>
                    <P class="score03">0</P>
                </div>
                <div class="tab tab2">
                    <p class="score01">SCORE</p>
                    <P class="score02">0</P>
                </div>
                <div class="tab3">
                    <p><button>New Gamen</button></p>
                </div>
            </div>
        </div>
        <div class="bot">
            <ul>
                <li class="cell" id="c00"></li>
                <li class="cell" id="c01"></li>
                <li class="cell" id="c02"></li>
                <li class="cell" id="c03"></li>

                <li class="cell" id="c10"></li>
                <li class="cell" id="c11"></li>
                <li class="cell" id="c12"></li>
                <li class="cell" id="c13"></li>

                <li class="cell" id="c20"></li>
                <li class="cell" id="c21"></li>
                <li class="cell" id="c22"></li>
                <li class="cell" id="c23"></li>

                <li class="cell" id="c30"></li>
                <li class="cell" id="c31"></li>
                <li class="cell" id="c32"></li>
                <li class="cell" id="c33"></li>
            </ul>
        </div>
    </div>
    <div id="zhebu">
        <p>
            GAME OVER !<br> SCORE:
            <span id="score00">0</span><br>
            <a href="">TRY AGAIN</a>
        </p>
    </div>

</body>
css样式与大家分享一下 博主写的比较简略
 <style>
 //以下为主结构基本样式
        * {
            margin: 0px;
            padding: 0px;
            list-style: none;
            /* background-color: #FAF8EF; */
        }
        
        .father {
            width: 510px;
            height: 700px;
            /* border: 1px solid; */
            margin: 0 auto;
            z-index: 2;
        }
        
        .top_1 {
            color: #776E65;
            width: 100%;
            height: 160px;
            background-color: #FAF8EF;
        }
        
        .top_r {
            width: 150px;
        }
        
        .bigzi {
            font-weight: 900;
            font-size: 75px;
        }
        
        .bigzi1 {
            font-weight: 900;
            font-size: 20px;
        }
        
        .top_l,
        .top_r {
            float: left;
            margin-top: 5px;
        }
        
        .top_r {
            margin-left: 10px;
            width: 165px;
            /* border: 1px solid; */
        }
        
        .tab {
            width: 70px;
            height: 70px;
            /* border: 1px solid; */
            float: right;
            text-align: center;
            background-color: #bbada0;
            color: #fff;
        }
        
        .tab1 {
            margin-left: 21px;
        }
        
        .tab3 {
            width: 100%;
            height: 40px;
            text-align: center;
            background-color: #9f8d77;
            float: left;
            line-height: 40px;
            border-radius: 4px;
            margin-top: 30px;
        }
        
        .bot {
            width: 100%;
            height: 535px;
            /* border: 1px solid; */
            background-color: #BBADA0;
        }
        
        .cell {
            width: 110px;
            height: 110px;
            background-color: #CDC0B4;
            float: left;
            margin-left: 14px;
            margin-top: 19px;
            border-radius: 5px;
            font-size: 60px;
            line-height: 110px;
            text-align: center;
            color: #fff;
        }
         .score02,
        .score03 {
            font-size: 20px;
        }
        
        button {
            font-size: 20px;
            background: #9f8d77;
            border: 0px;
            color: #FAF8EF;
        }
        
        #zhebu {
            position: absolute;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;
            background-color: rgba(55, 55, 55, 0.5);
            display: none; //游戏结束时 遮罩才会弹出来 所以先隐藏
        }
        
        #zhebu>p {
            width: 300px;
            height: 200px;
            background-color: #fff;
            position: absolute;
            top: 50%;
            left: 50%;
            margin-top: -100px;
            margin-left: -150px;
            text-align: center;
            border-radius: 10px;
            border: 1px solid;
            line-height: 65px;
            font-size: 40px;
        }
        
        #zhebu>p>a {
            padding: 10px;
            color: #fff;
            background-color: #9f8d77;
            border-radius: 6px;
            text-decoration: none;
        }
        //下面是不同数值 产生的不同游戏格字体颜色 以及格子颜色
        .n2 {
            background-color: #eee3da;
            color: #776e65
        }
        
        .n4 {
            background-color: #ede0c8;
            color: #776e65
        }
        
        .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;
            font-size: 40px
        }
        
        .n2048 {
            background-color: #09c;
            font-size: 40px
        }
        
        .n4096 {
            background-color: #a6c;
            font-size: 40px
        }
        
        .n8192 {
            background-color: #93c;
            font-size: 40px

js代码部分 封装函数的逻辑代码解析

首先为了能更好的取值并使用各个函数

创建一个game对象,游戏中所有的属性和方法都放在game对象中
并创建出需要用到的对象名以及属性:

var game = {
    score: 0, //添加一个得分属性
    status: 1, //添加一个游戏状态
    gameover: 0, //添加一个游戏结束状态
    gamerunning: 1, //添加一个游戏运行状态
    data: [], //添加一个数组,用于存储游戏数据的,
    }
游戏开始的代码进行封装

大家请先思考 在进行游戏重新开始 要做到哪些方面的更新重置?
1.游戏状态必须设置为游戏运行中
2.将分数重置
3.清空历史游戏数据的储存器data数组
4.游戏开始时会产生两个随机数2或4 并随机出现在格子随机的两个位置

start: function() {
        this.status = this.gamerunning; //游戏状态重新设置为运行状态
        this.score = 0; //分数重置
        this.data = []; //清空游戏数据数组
        
        // 生成二维数组,放置在data数组中保存数据 16个0
        for (var r = 0; r < 4; r++) {
            this.data[r] = []
            for (var c = 0; c < 4; c++) {
                this.data[r][c] = 0;
            }
        }
        
        this.randomNum() //随机产生的数封装的函数  因为开始会随机两个数  所以这里调用两次
        this.randomNum() 
        this.dataView() //视图更新函数 稍后会做讲解
    },

以及生成随机数的代码:
游戏开始产生的随机数字只可能是2或4 再根据for死循环生成随机行和列。
博主这里需要提到上面的li命名方式就是为了能一一对应,给大家画个简易图片:
在这里插入图片描述
行和列分别是从0开始 到3结束 每一行都是四格
所以用到floor向下取整 获取随机数

// 生成随机数
    randomNum: function() {
        for (;;) {
            // 生成随机位置
            var r = Math.floor(Math.random() * 4) //随机生成行
            var c = Math.floor(Math.random() * 4) //随机生成列
                // 判断位置上是否有数据
            if (this.data[r][c] == 0) { //没有数据
                var num = Math.random() > 0.3 ? 2 : 4; //三元表达式 表示非2即4
                this.data[r][c] = num;
                break;
            }
        }
    },
游戏进行需要视图更新以及样式和数据的修改 封装成函数

首先利用双层for循环 遍历出所有的li 即每一个横纵排列的游戏格
然后判断数组中的值是否为0 不为0则需要渲染游戏格

 dataView: function() {
            for (r = 0; r < 4; r++) {
                for (c = 0; c < 4; c++) {
                    var liAll = document.getElementById("c" + r + c) //注意观察博主的li命名方式
                    if (this.data[r][c] != 0) { //数组中的值不为0,渲染页面
                        liAll.innerHTML = this.data[r][c];  //修改li的值
                        liAll.className = "cell n" + this.data[r][c]
                    } else { //数组中的值为0,数据不能显示至
                        liAll.innerHTML = "";
                        liAll.className = "cell";
                    }
                }
            }

            //找到分数class名并设置分数
            document.getElementsByClassName("score02")[0].innerHTML = this.score;

            //判断条件  
            if (this.status == this.gameover) { //gameover 为游戏结束的函数 稍后会讲解 
                document.getElementById("score00").innerHTML = this.score;
                document.getElementById("zhebu").style.display = "block"; //游戏结束便会弹出遮罩层  宣布游戏结束

            } else {
                document.getElementById("zhebu").style.display = "none"  //没结束遮罩永远不会弹出
            }
        },

游戏结束判断代码片 封装成函数

所有的游戏都会在某种情况下结束掉 要先列举出每一种情况 一件都不能少 否则游戏会无限进行下去:
1.游戏中方格被数字填充满 没有位置可以移动并产生随机数
2.游戏格子占满时要判断相邻数字之间能否左右上下能否相加
如果以上两点都满足 则游戏结束 弹出遮罩层 宣布游戏结束。
给大家看一下遮罩层的效果图:
在这里插入图片描述

isGameover: function() {
            for (var r = 0; r < 4; r++) {
                for (var c = 0; c < 4; c++) {
                    if (this.data[r][c] == 0) {
                        //有空位置 说明没结束
                        return false;
                    }
                    if (c < 3) {
                        if (this.data[r][c] == this.data[r][c + 1]) {
                            //说明左右相邻相等,可以进行相加,游戏没有结束
                            return false;
                        }
                    }
                    if (r < 3) {
                        if (this.data[r][c] == this.data[r + 1][c]) {
                            //说明上下相邻数据相等,则可以相加,游戏没有结束
                            return false;
                        }
                    }
                }
            }
            return true; //游戏结束 
        },
上下左右按键操作以及数字位置调换

向左移动 封装函数:
博主封装了三个函数(moveLeft) (moveLeftRow:)(getNextinRow)
三个函数都有着各自的功能 但是每一个功能都是联系紧密的 所以需要一起来看:

moveLeft: function() {
            var before = String(this.data)
            console.log(before);
            for (r = 0; r < 4; r++) {
                this.moveLeftRow(r)

            }
            var after = String(this.data)
            console.log(after);
            if (before != after) {
                this.randomNum()
                if (this.isGameover()) {
                    this.status = this.gameover
                }
                this.dataView()
            }
        },
        moveLeftRow: function(r) { //单独抽出一行进行写逻辑
            for (var c = 0; c < 3; c++) { //最左边的不需要移动,所以遍历三次
                //找出r行c列后面不为0的数据的位置保存至nextc中
                var nextc = this.getNextinRow(r, c)
                console.log(nextc);
                if (nextc != -1) {
                    //这一行中有需要移动的数据

                    if (this.data[r][c] == 0) {
                        this.data[r][c] = this.data[r][nextc]
                        this.data[r][nextc] = 0;
                        c--;
                        //c留在原地继续左移动
                    } else if (this.data[r][c] == this.data[r][nextc]) {
                        this.data[r][c] = this.data[r][c] * 2;
                        console.log(this.data[r][c]);
                        this.score += this.data[r][c] * 1000; //分数
                        this.data[r][nextc] = 0;
                    }
                } else {
                    //这一行没有需要移动的数据
                    break;
                }
            }

        },
        getNextinRow: function(r, c) {
            for (var i = c + 1; i < 4; i++) {
                if (this.data[r][i] != 0) {
                    return i;
                }
            }
            return -1; //如果当前行找不到不为0的数据则返回-1
        },

同理只需要修改行列 就可以做出向右,向上,向下移动的封装函数:

 moveRight: function() {
            var before1 = String(this.data);
            console.log(before1);
            for (r = 0; r < 4; r++) {
                this.moveRightRow(r)

            }
            var after1 = String(this.data);
            console.log(after1);
            if (before1 != after1) {
                this.randomNum()
                if (this.isGameover()) {
                    this.status = this.gameover
                }
                this.dataView()
            }
        },
        moveRightRow: function(r) {
            for (var c = 3; c > 0; c--) {
                var prevc = this.getPrevRow(r, c)
                console.log(prevc);
                if (prevc != -1) {
                    if (this.data[r][c] == 0) {
                        this.data[r][c] = this.data[r][prevc]
                        this.data[r][prevc] = 0;
                        c++;
                    } else if (this.data[r][c] == this.data[r][prevc]) {
                        this.data[r][c] = this.data[r][c] * 2;
                        this.score += this.data[r][c] * 1000;
                        this.data[r][prevc] = 0;
                    }
                } else {
                    break;
                }
            }
        },
        getPrevRow: function(r, c) {
            for (var i = c - 1; i > -1; i--) {
                if (this.data[r][i] != 0) {
                    return i;
                }
            }
            return -1;
        },
        moveUp: function() {
            var before1 = String(this.data);
            console.log(before1);
            for (c = 0; c < 4; c++) {
                this.moveUpRow(c)

            }
            var after1 = String(this.data);
            console.log(after1);
            if (before1 != after1) {
                this.randomNum()
                if (this.isGameover()) {
                    this.status = this.gameover
                }
                this.dataView()
            }
        },
        moveUpRow: function(r) {
            for (var r = 0; r < 3; r++) {
                var prevc = this.getPrev1Row(r, c)
                console.log(prevc);
                if (prevc != -1) {
                    if (this.data[r][c] == 0) {
                        this.data[r][c] = this.data[prevc][c]
                        this.data[prevc][c] = 0;
                        r--;
                    } else if (this.data[r][c] == this.data[prevc][c]) {
                        this.data[r][c] = this.data[r][c] * 2;
                        this.score += this.data[r][c] * 1000;
                        this.data[prevc][c] = 0;
                    }
                } else {
                    break;
                }
            }
        },
        getPrev1Row: function(r, c) {
            for (var i = r + 1; i < 4; i++) {
                if (this.data[i][c] != 0) {
                    return i;
                }
            }
            return -1;
        },
        moveDow: function() {
            var before1 = String(this.data);
            console.log(before1);
            for (c = 0; c < 4; c++) {
                this.moveDowRow(c)

            }
            var after1 = String(this.data);
            console.log(after1);
            if (before1 != after1) {
                this.randomNum()
                if (this.isGameover()) {
                    this.status = this.gameover
                }
                this.dataView()
            }
        },
        moveDowRow: function(c) {
            for (var r = 3; r > 0; r--) {
                var prevc = this.getDowRow(r, c)
                console.log(prevc);
                if (prevc != -1) {
                    if (this.data[r][c] == 0) {
                        this.data[r][c] = this.data[prevc][c]
                        this.data[prevc][c] = 0;
                        r++;
                    } else if (this.data[r][c] == this.data[prevc][c]) {
                        this.data[r][c] = this.data[r][c] * 2;
                        this.score += this.data[r][c] * 1000;
                        this.data[prevc][c] = 0;
                    }
                } else {
                    break;
                }
            }
        },
        getDowRow: function(r, c) {
            for (var i = r - 1; i > -1; i--) {
                if (this.data[i][c] != 0) {
                    return i;
                }
            }
            return -1;

        }
绑定键盘上下移动键
game.start()
        // console.log(game.getNextinRow());
    document.onkeydown = function(event) {
        if (event.keyCode == 37) {
            game.moveLeft()
        }
        if (event.keyCode == 39) {
            game.moveRight()
        }
        if (event.keyCode == 38) {
            game.moveUp()
        }
        if (event.keyCode == 40) {
            game.moveDow()
        }

2048的小游戏咱们就写到这儿,中间是还有一些小细节的,大家可以添加更多自己的元素,把游戏功能添加更多,如果有什么问题 可以评论,博主会耐心解答!

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值