【javascript】2048小游戏

news2024/11/14 14:17:07

目录

什么是2048

游戏状态机

游戏界面绘制

3.1 界面

 3.2 数字的背景颜色

分数逻辑

4.1 加分

4.2 更新最高分 

方向控制逻辑

5.1 数组

5.2 随机数

5.3 初始化 

5.4 判断数组是否全部填满 

5.5 判断方格是否还能移动 

5.6 上下左右的监听事件

5.7 移动

完整代码


什么是2048

2048是一款风靡全球的小游戏,具体的玩法就不多说了,最早于2014年Gabriele Cirulli在github发表的版本。

github链接:

https://github.com/claudiopro/2048-react

不过此项目依赖于GULP。

本文就用javascript写出一个较为完整的2048游戏。

以下是本文实现的游戏界面:

 代码参考于csdn博客:参考博客

2048的实现可以分为3个部分:游戏界面绘制、分数逻辑和方向控制逻辑。

游戏状态机

游戏界面绘制

3.1 界面

<div id="game">
    <span class="container">
        <span class="left">
            <span class="left-topic">2048</span>
            <span class="left-tips">↑上&nbsp;↓下&nbsp;←左&nbsp;→右&nbsp;i重玩</span>
        </span>
        <span class="right">
            <span class="score-box">最高分:<span class="score">0</span></span>
            <span class="score-box">得&emsp;分:<span class="score">0</span></span>
        </span>
    </span>
    
    <div id="box">
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
    </div>
</div>

 3.2 数字的背景颜色

//不同的数字添加不同的背景颜色
function bgcolor(){
    for(var i = 0;i <arr.length;i++){
        for(var j = 0;j <arr.length;j++){
        
        switch(arr[i][j].innerHTML){
            case '2': arr[i][j].style.backgroundColor = "#EEE4DA" ;break;
            case '4': arr[i][j].style.backgroundColor = "#EDE0C8" ;break;
            case '8': arr[i][j].style.backgroundColor = "#F2B179" ;break;
            case '16': arr[i][j].style.backgroundColor = "#F59563" ;break;
            case '32': arr[i][j].style.backgroundColor = "#F67C5F" ;break;
            case '64': arr[i][j].style.backgroundColor = "#F65E3B" ;break;
            case '128': arr[i][j].style.backgroundColor = "#EDCF72" ;break;
            case '256': arr[i][j].style.backgroundColor = "#EDCC61" ;break;
            case '512': arr[i][j].style.backgroundColor = "#EDC850" ;break;
            case '1024': arr[i][j].style.backgroundColor = "yellowgreen" ;break;
            case '2048': arr[i][j].style.backgroundColor = "perple" ;
                        init();
                        alert('游戏胜利');
                        break;
            default:  arr[i][j].style.backgroundColor = "#CDC1B4" ;break;     

        }
        }
    }

}

如果出现了2048,就代表游戏胜利。 

分数逻辑

//最高分
var high = 0;
//得分
var score = 0;

设两个变量,high和score。 

4.1 加分

//加分
function addScore(s) {
    score += s;
    document.getElementsByClassName('score')[1].innerHTML = score;
}

在每次上下左右操作中,如果存在可以合并的情况,就加上合并的值。 

4.2 更新最高分 

//更新最高分
if(score>high)
    document.getElementsByClassName('score')[0].innerHTML = high = score;

 在玩家需要重玩的时候,初始化数组,如果得分比最高分要高的话就更新。

方向控制逻辑

5.1 数组

var divs= document.querySelectorAll("#box>div");
var arr = [[],[],[],[]];

游戏的方格其实对应着一个4*4的二维数组,divs对应着数组的html对象,arr对应着div。

5.2 随机数

//随机产生一个数字
function rand(){
    var x=Math.floor(Math.random()*4);
    var y=Math.floor(Math.random()*4);
    if(arr[x][y].innerHTML == ""){
        arr[x][y].innerHTML = Math.random() > 0.5 ? 2 : 4;
    }else{
        rand();
    }
}

 随机生成2和4。

5.3 初始化 

//初始化
function init(){
    for(var i = 0;i <arr.length;i++){
        for(var j = 0;j <arr.length;j++){
            arr[i][j] = divs[num];
            arr[i][j].innerHTML = '';
            num++;
        }
    }
    //初始化遍历元素
    num = 0;
    //更新最高分
    if(score>high)
        document.getElementsByClassName('score')[0].innerHTML = high = score;
    //初始化得分
    document.getElementsByClassName('score')[1].innerHTML = score = 0;
    //游戏开始产生2个随机数
    rand();
    rand();
    bgcolor();
}

5.4 判断数组是否全部填满 

//判断方格是否全部填满
function isFull(){
    var bool=true;
    for(var i = 0;i <arr.length;i++){
        for(var j = 0;j <arr.length;j++){
            if(arr[i][j].innerHTML == "" ){
            bool = false;
            }
        }
    }
    if(bool){
    isChange();
    }else{
        rand();
    }
}

设一个布尔值,如果遇到了空就代表游戏可以继续。

5.5 判断方格是否还能移动 

//判断方格是否还能移动
function  isChange(){
    var bool = true;
    for(var i = 0;i < arr.length-1 ;i++){
        for(var j = 0;j< arr.length-1;j++){
            if(arr[i][j].innerHTML == arr[i][j+1].innerHTML || arr[i][j].innerHTML == arr[i+1][j].innerHTML || arr[i+1][j].innerHTML == arr[i+1][j+1].innerHTML || arr[i][j+1].innerHTML == arr[i+1][j+1].innerHTML  ){
                bool = false;
            }
        }
    }
    if(bool){
        alert("游戏结束!");
        init();
    }
}

如果数组中某行某列有相同的就代表可以继续移动。 

5.6 上下左右的监听事件

//上下左右的监听事件
window.onkeydown = function(e){

    switch(e.keyCode){
        case 37 :  isFull(); left();bgcolor();     break;//左
        case 38 :  isFull(); up();bgcolor();     break;//上
        case 39 :  isFull(); right();bgcolor();     break;//右
        case 40 :  isFull(); down(); bgcolor();     break;//下
        case 73 :  init(); break;//初始化
    } 

}

每执行一个事件,需要判断数组是不是满的,如果未满就一定可以继续游戏,如果满了,则需要判断数组中的元素是否还能继续移动。

5.7 移动

上下左右移动的逻辑都是一样的,这里以右移为例。

//右             
function right(){
    for(var i = 0;i <4;i++){
        for(var j = 0;j <4;j++){
            if( j<3&&arr[i][j].innerHTML !=""&& arr[i][j+1].innerHTML==""){
                arr[i][j+1].innerHTML = arr[i][j].innerHTML;
                arr[i][j].innerHTML="";
                right();
            }else if(j<3&&arr[i][j].innerHTML !=""&& arr[i][j].innerHTML == arr[i][j+1].innerHTML){
                arr[i][j+1].innerHTML *=2;
                addScore(arr[i][j+1].innerHTML*1)
                arr[i][j].innerHTML ="";
            } 
        
        }
    }
}

对于数组,有的可能没有数据,如果有数据则找出下一个相同的数据进行合并。

完整代码

演示

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
</head>
<style>
    .container{
        display: flex;
    }
    .left{
        width: 250px;
        font-size: 10px;
        display: flex;
        flex-direction: column;
    }
    .left-tips{
        position: relative;
        top: 10px;
        font-weight: bold;
        color:beige;
    }
    .left-topic{
        font-weight: bold;
        color:rgba(172, 130, 75, 0.911);
        font-size: 40px;
    }
    .right{
        display: flex;
        flex-direction: column;
        position: relative;
        left: 45px;
        color:blanchedalmond;
    }
    .score-box{
        width: 200px;
        height: 30px;
        border: 1px solid transparent;
        border-radius: 5px;
        margin-top: 5px;
        margin-bottom: 5px;
        font-weight: bold;
        font-size: 25px;
    }
    .score{
        font-weight: bold;
        font-size: 25px;
    }
    #game{
        width: 500px;
        height: 530px;
        background-color: #BBADA0;
        display: flex;
        justify-content: space-evenly;
        flex-wrap: wrap;
        border-radius: 0.5em;
        margin: 100px auto;
    }
    #box{
        display: flex;
        justify-content: space-evenly;
        flex-wrap: wrap;
        border-radius: 0.5em;
    }
    #box div{
        width: 100px;
        height: 100px;
        border: 1px solid transparent;
        background-color: #CDC1B4;
        font-size: 50px;
        text-align: center;
        line-height: 100px;
        font-weight: bold;
        border-radius: 10px;
        margin-top: 10px;
        color:rgba(172, 141, 101, 0.911);
    }
</style>
<body>
<div id="game">
    <span class="container">
        <span class="left">
            <span class="left-topic">2048</span>
            <span class="left-tips">↑上&nbsp;↓下&nbsp;←左&nbsp;→右&nbsp;i重玩</span>
        </span>
        <span class="right">
            <span class="score-box">最高分:<span class="score">0</span></span>
            <span class="score-box">得&emsp;分:<span class="score">0</span></span>
        </span>
    </span>
    
    <div id="box">
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
    </div>
</div>
    <script >
        //最高分
        var high = 0;
        //得分
        var score = 0;
        var divs= document.querySelectorAll("#box>div");
        var arr = [[],[],[],[]];
        var num=0;

        /*
        主逻辑
        */

        //初始化
        init();
        //上下左右的监听事件
        window.onkeydown = function(e){

            switch(e.keyCode){
                case 37 :  isFull(); left();bgcolor();     break;//左
                case 38 :  isFull(); up();bgcolor();     break;//上
                case 39 :  isFull(); right();bgcolor();     break;//右
                case 40 :  isFull(); down(); bgcolor();     break;//下
                case 73 :  init(); break;//初始化
            } 

        }


//随机产生一个数字
function rand(){
    var x=Math.floor(Math.random()*4);
    var y=Math.floor(Math.random()*4);
    if(arr[x][y].innerHTML == ""){
        arr[x][y].innerHTML = Math.random() > 0.5 ? 2 : 4;
    }else{
        rand();
    }
}

        //初始化
        function init(){
            for(var i = 0;i <arr.length;i++){
                for(var j = 0;j <arr.length;j++){
                    arr[i][j] = divs[num];
                    arr[i][j].innerHTML = '';
                    num++;
                }
            }
            //初始化遍历元素
            num = 0;
            //更新最高分
            if(score>high)
                document.getElementsByClassName('score')[0].innerHTML = high = score;
            //初始化得分
            document.getElementsByClassName('score')[1].innerHTML = score = 0;
            //游戏开始产生2个随机数
            rand();
            rand();
            bgcolor();
        }

        //加分
        function addScore(s) {
            score += s;
            document.getElementsByClassName('score')[1].innerHTML = score;
        }

        //判断方格是否全部填满
        function isFull(){
            var bool=true;
            for(var i = 0;i <arr.length;i++){
                for(var j = 0;j <arr.length;j++){
                    if(arr[i][j].innerHTML == "" ){
                    bool = false;
                    }
                }
            }
            if(bool){
            isChange();
            }else{
                rand();
            }
        }

        //判断方格是否还能移动
        function  isChange(){
            var bool = true;
            for(var i = 0;i < arr.length-1 ;i++){
                for(var j = 0;j< arr.length-1;j++){
                    if(arr[i][j].innerHTML == arr[i][j+1].innerHTML || arr[i][j].innerHTML == arr[i+1][j].innerHTML || arr[i+1][j].innerHTML == arr[i+1][j+1].innerHTML || arr[i][j+1].innerHTML == arr[i+1][j+1].innerHTML  ){
                        bool = false;
                    }
                }
            }
            if(bool){
                alert("游戏结束!");
                init();
            }
        }

        //不同的数字添加不同的背景颜色
        function bgcolor(){
            for(var i = 0;i <arr.length;i++){
                for(var j = 0;j <arr.length;j++){
                
                switch(arr[i][j].innerHTML){
                    case '2': arr[i][j].style.backgroundColor = "#EEE4DA" ;break;
                    case '4': arr[i][j].style.backgroundColor = "#EDE0C8" ;break;
                    case '8': arr[i][j].style.backgroundColor = "#F2B179" ;break;
                    case '16': arr[i][j].style.backgroundColor = "#F59563" ;break;
                    case '32': arr[i][j].style.backgroundColor = "#F67C5F" ;break;
                    case '64': arr[i][j].style.backgroundColor = "#F65E3B" ;break;
                    case '128': arr[i][j].style.backgroundColor = "#EDCF72" ;break;
                    case '256': arr[i][j].style.backgroundColor = "#EDCC61" ;break;
                    case '512': arr[i][j].style.backgroundColor = "#EDC850" ;break;
                    case '1024': arr[i][j].style.backgroundColor = "yellowgreen" ;break;
                    case '2048': arr[i][j].style.backgroundColor = "perple" ;
                                init();
                                alert('游戏胜利');
                                break;
                    default:  arr[i][j].style.backgroundColor = "#CDC1B4" ;break;     

                }
                }
            }

        }

        //上下左右按下执行的函数 
        //右             
        function right(){
            for(var i = 0;i <4;i++){
                for(var j = 0;j <4;j++){
                    if( j<3&&arr[i][j].innerHTML !=""&& arr[i][j+1].innerHTML==""){
                        arr[i][j+1].innerHTML = arr[i][j].innerHTML;
                        arr[i][j].innerHTML="";
                        right();
                    }else if(j<3&&arr[i][j].innerHTML !=""&& arr[i][j].innerHTML == arr[i][j+1].innerHTML){
                        arr[i][j+1].innerHTML *=2;
                        addScore(arr[i][j+1].innerHTML*1)
                        arr[i][j].innerHTML ="";
                    } 
                
                }
            }
        }

        //左
        function left(){
            for(var i = 0;i <4;i++){
                for(var j = 0;j <4;j++){
                    if( j>0&&arr[i][j].innerHTML !=""&& arr[i][j-1].innerHTML==""){
                        arr[i][j-1].innerHTML = arr[i][j].innerHTML;
                        arr[i][j].innerHTML="";
                        left();
                    }else if(j>0&&arr[i][j].innerHTML !=""&& arr[i][j].innerHTML == arr[i][j-1].innerHTML){
                        arr[i][j-1].innerHTML *=2;
                        addScore(arr[i][j-1].innerHTML*1)
                        arr[i][j].innerHTML ="";
                    } 
                
                }
            }
        }

        //下
        function down(){
            for(var i = 0;i <4;i++){
                for(var j = 0;j <4;j++){
                    if( i<3&&arr[i][j].innerHTML !=""&& arr[i+1][j].innerHTML==""){
                        arr[i+1][j].innerHTML = arr[i][j].innerHTML;
                        arr[i][j].innerHTML="";
                        down();
                    }else if(i<3&&arr[i][j].innerHTML !=""&& arr[i][j].innerHTML == arr[i+1][j].innerHTML){
                        arr[i+1][j].innerHTML *=2;
                        addScore(arr[i+1][j].innerHTML*1)
                        arr[i][j].innerHTML ="";
                    } 
                
                }
            }
        }

        //上
        function up(){
            for(var i = 0;i <4;i++){
                for(var j = 0;j <4;j++){
                    if( i>0&&arr[i][j].innerHTML !=""&& arr[i-1][j].innerHTML==""){
                        arr[i-1][j].innerHTML = arr[i][j].innerHTML;
                        arr[i][j].innerHTML="";
                        up();
                    }else if(i>0&&arr[i][j].innerHTML !=""&& arr[i][j].innerHTML == arr[i-1][j].innerHTML){
                        arr[i-1][j].innerHTML *=2;
                        addScore(arr[i-1][j].innerHTML*1)
                        arr[i][j].innerHTML ="";
                    } 
                
                }
            }
        }

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/693449.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微服务划分的姿势

我们知道微服务是一种理念&#xff0c;没有确切的定义和边界&#xff0c;好比设计原则&#xff0c;是属于抽象的概念。在定义不明确的情况下谈划分也是一种各说各话&#xff0c;具体问题需要具体分析&#xff0c;所以这篇文章谈到的划分也不是绝对标准&#xff0c;仅供参考。 有…

final, finally和finalize的区别

final、finally和finalize是Java中用于异常处理的关键字。每个关键字都有不同的功能。final是一个访问修饰符&#xff0c;finally是异常处理中的代码块&#xff0c;而finalize是Object类的方法。 除此之外&#xff0c;final、finally和finalize之间还存在许多区别。下面是final…

netty学习(1):1个客户端与服务器通信

1. 新建maven工程&#xff0c;添加netty依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"…

Avoid adding reactive properties to a Vue instance or its root $da

避免在运行时向Vue实例或其根$data添加反应性属性-在数据选项中预先声明它。 在页面中声明对象&#xff0c;直接修改即可。 data(){return{addressInfo:{}}}

阿里云服务器地域可用区怎么选?

阿里云服务器地域和可用区怎么选择&#xff1f;地域是指云服务器所在物理数据中心的位置&#xff0c;地域选择就近选择&#xff0c;访客距离地域所在城市越近网络延迟越低&#xff0c;速度就越快&#xff1b;可用区是指同一个地域下&#xff0c;网络和电力相互独立的区域&#…

如何在Mac上安装 Stable Diffusion 来创作

​ 看着别人玩&#xff0c;是不是特想自己搭建一个&#xff0c;那么现在教程来了。 玩这种需要算力的东西&#xff0c;电脑配置肯定是越高越好了。我的电脑配置如下&#xff1a;​ 接下来就开始安装了。 第一步&#xff1a;安装homebrew 打开terminal终端&#xff08;comma…

使用maven中的profile动态打包不同环境的配置文件

maven中的profile可以在打包时动态选择不同的配置文件进行打入&#xff0c;在项目具有开发、测试、生产环境时可以更方便优雅的进行不同环境的打包运行 示例图&#xff1a; 1-配置profile 第一步需要为每个环境配置一个profile标签&#xff0c;在pom文件中进行配置。我这里只…

如何做好工程英语翻译

近年来&#xff0c;随着全球经济的持续发展&#xff0c;涉外工程业务日益增多&#xff0c;工程英语翻译的需求也越来越大。那么&#xff0c;工程英语翻译难吗&#xff0c;如何做好工程英语翻译&#xff0c;服务好的北京翻译公司哪里有&#xff1f; 据了解&#xff0c;工程英语语…

macOS Ventura 13.4.1With OpenCore 0.9.3 and winPE双引导黑苹果镜像

镜像特点 完全由黑果魏叔官方制作&#xff0c;针对各种机型进行默认配置&#xff0c;让黑苹果安装不再困难。系统镜像设置为双引导分区&#xff0c;全面去除clover引导分区&#xff08;如有需要&#xff0c;可以自行直接替换opencore分区文件为clover引导文件&#xff09;备注…

知识蒸馏学习记录(二)

上一篇博文中我们介绍了知识蒸馏的一些基础知识&#xff0c;这里我们来学习其到底是如何完成知识蒸馏过程的。 知识蒸馏为何可以让学生网络模型小却性能强&#xff1f; 详细很多同学与我有相同的疑问&#xff0c;尽管它依靠不同的蒸馏温度T可以学得一些hard target标注无法包…

《计算机系统与网络安全》 第四章 密码学基础

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

8--Gradle进阶 - Gradle任务的入门、任务行为

8--Gradle进阶 - Gradle任务的入门、任务行为 Gradle Task Gradle 项目工程的管理 实质上是 Task 对象的集合。一个 Task 表示一个逻辑上较为独立的执行过程&#xff0c;比如编译Java 源代码&#xff0c;拷贝文件&#xff0c; 打包Jar 文件&#xff0c;甚至可以是执行一个系统命…

flutter Exception: Gradle task assembleDebug failed with exit code 1

Exception: Gradle task assembleDebug failed with exit code 1 解决方案&#xff1a; 出现这个问题&#xff0c;可能是依赖的插件无法下载 找到项目的android->build.gradle, 将 google() mavenCentral()改成 maven{url https://maven.aliyun.com/repository/google }m…

XML的运用(XML解析)

一、XML文件的三种配置位置机读取方式 Java中配置XML文件的三种配置位置机读取方式&#xff1a;常用的三种 1、同包下 在演式之前我们把前期演示的部分给准备好&#xff1a; 我们以properties为后缀的文本为例&#xff1a; unamemybatis_ssm upassxiaoli urljdbc:mysql://lo…

短视频矩阵-短视频seo源码开发搭建

开发场景&#xff1a;抖音seo&#xff0c;短视频seo&#xff0c;抖音矩阵&#xff0c;短视频矩阵源码开源 一、 短视频矩阵源码需要掌握以下技术&#xff1a; 1. 视频编码技术 短视频矩阵系统利用视频编码技术&#xff0c;将视频文件进行压缩和解压缩&#xff0c;实现了高质…

cut一些常用的用法

目录 介绍语法示例切割提取指定列数据切割提取指定字符数据切割提取指定字节数据切割提取指定单词数据切割提取bash进程的PID号 小结 介绍 cut 译为“剪切, 切割” , 是一个强大文本处理工具&#xff0c;它可以将文本按列进行划分的文本处理。cut命令逐行读入文本&#xff0c;…

掌握apply和call,解密JavaScript的this指向

文章目录 一、介绍apply和call方法1.1 简述apply和call方法的作用1.2 apply和call方法的共同点与不同点 二、深入理解apply方法2.1 apply方法的语法和参数介绍2.2 apply方法的使用示例2.3 apply方法的应用场景 三、深入理解call方法3.1 call方法的语法和参数介绍3.2 call方法的…

MySQL:库的操作和表的操作(内含MySQL数据类型讲解)

进入数据库的数据目录 cd var/lib/mysql 库的操作 创建数据库 创建数据库的本质是创建目录。 创建数据库时有两个编码集&#xff1a;1.数据库编码集&#xff08;存储时使用&#xff09;2.进行字段比对读取时使用的编码方式&#xff09; 语法&#xff1a; CREATE DATABASE …

SpringBoot+Prometheus采集Metrics指标数据

简介 本文介绍在springboot3.x里配置启用系统指标监控功能&#xff0c;来监视系统各项Metrics指标&#xff0c;从而实时了解应用的运行健康状态&#xff0c;通过promtheus服务提供数据收集与指标可视化方案&#xff1b; Metrics指标 metrics指标表示应用程序代码运行中提供的…

【JavaWeb】前端之CSS基础认知

目录 前言 1、CSS基本语法规范 2、向HTML中引入CSS的方式 2.1、内部样式 2.2、外部样式 2.3、内联样式 3、CSS选择器 3.1、基础选择器 3.1.1、标签选择器 3.1.2、类选择器 3.1.3、id选择器 3.1.4、通配符选择器 3.2、复合选择器 3.2.1、后代选择器 4、CSS常用元素…