zoukankan      html  css  js  c++  java
  • JS实现2408小游戏

    一.游戏简介

    2048是一款休闲益智类的数字叠加小游戏,类似于欢乐消消消,很有意思的一个小游戏。

    二.游戏玩法

    在 4*4 的16宫格中,您可以选择上、下、左、右四个方向进行操作,数字会按方向移动,相邻的两个数字相同就会合并,组成更大的数字,每次移动或合并后会自动增加一个数字。

    当16宫格中没有空格子,且四个方向都无法操作时,游戏结束。

    三、游戏目的

    目的是合并出 2048 这个数字,获得更高的分数。

    四.游戏截图

    五.游戏实现的原理

    把16个格子看成4*4的二维数组

    在HTML中给每个格子添加类名和属性,来记录每个格子的位置

    采用三元表达式随机生成0~1的小数,和0.5(可以设置游戏难度)比较,来给出2或4

    最后再把数据更新到每个div中

    判断游戏结束:

    每个格子上的数都不为零,上下左右的数都不相同的时候就判断游戏结束

    HTML设置整体的布局

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>2048小游戏</title>
    <link rel="stylesheet" type="text/css" href="2048.css">
    </head>
    <body>
    <div class="bag">
    <h1>2048</h1>
    <button onclick="game.start();">new game</button>
    <div class="score">
    <span>当前分数:</span>
    <span id="scoreValue">0</span>
    </div>
    <div class="highScore">
    <span>最高得分:</span>
    <span id="highScoreValue">0</span>
    </div>

    <div class="box">
    <!-- 第一行 -->
    <div class="item" id= "c00"></div>
    <div class="item" id= "c01"></div>
    <div class="item" id= "c02"></div>
    <div class="item" id= "c03"></div>
    <!-- 第二行 -->
    <div class="item" id= "c10"></div>
    <div class="item" id= "c11"></div>
    <div class="item" id= "c12"></div>
    <div class="item" id= "c13"></div>
    <!-- 第三行 -->
    <div class="item" id= "c20"></div>
    <div class="item" id= "c21"></div>
    <div class="item" id= "c22"></div>
    <div class="item" id= "c23"></div>
    <!-- 第四行 -->
    <div class="item" id= "c30"></div>
    <div class="item" id= "c31"></div>
    <div class="item" id= "c32"></div>
    <div class="item" id= "c33"></div>
    </div>
    <header id="false_1">
    <h1>GAME OVER</h1>
    <p>SCORE:<span id="endScore">0</span></p>
    <br>
    <button onclick="game.start();">再玩一次</button>
    </header>
    </div>

    <script type="text/javascript" src="2048.js"></script>
    </body>
    </html>

    CSS界面设置div样式

    body{
    background-color: #fff8dc;
    }
    .bag{
    600px;
    height: 650px;
    background-color: #ffe4e1;
    border-radius: 20px;
    margin: 0 auto;
    position: relative;
    }
    .bag>h1{
    position: absolute;
    font-size: 70px;
    color:#ff69b4;
    left: 75px;
    top: 30px;
    }
    .box{
    450px;
    height: 450px;
    border-radius: 10px;
    background-color:#ffb6c1;
    position: absolute;
    top: 170px;
    left: 75px;

    }
    header{
    450px;
    height: 450px;
    border-radius: 20px;
    background-color:rgba(20,20,20,0.5);
    z-index: -99;
    position: absolute;
    top: 170px;
    left: 75px;
    }
    header>h1{
    font-size: 50px;
    text-align: center;
    color: #ffb6c1;
    }
    header>button{
    200px;
    height: 60px;
    font-size: 30px;
    color: #ff69b4;
    border-radius: 6px;
    border:none;
    background-color:#ffb6c1;
    margin-left: 125px;
    }
    header>p{
    color: #ff69b4;
    font-size: 30px;
    font-weight: bold;
    text-align: center;
    }
    .false{
    z-index: 99;
    }
    .item{
    100px;
    height: 100px;
    border-radius: 8px;
    background-color:#ff69b4;
    float:left;
    margin: 10px 0 0 10px;
    font-size: 60px;
    text-align: center;
    line-height: 100px;
    }
    .bag>button{
    100px;
    height: 40px;
    font-size: 18px;
    color: #ff69b4;
    border-radius: 6px;
    border:none;
    background-color:#ffb6c1;
    position: absolute;
    right: 75px;
    top: 110px;
    }
    .bag>.score{
    100px;
    height: 60px;
    background-color: #ffb6c1;
    position: absolute;
    border-radius: 6px;
    left: 75px;
    top:20px;
    color: #ff69b4;
    font-size: 18px;
    text-align: center;
    }
    .score>span{
    display: block;
    }
    .highScore{
    100px;
    height: 60px;
    background-color: #ffb6c1;
    position: absolute;
    border-radius: 6px;
    right:75px;
    top:20px;
    color: #ff69b4;
    font-size: 18px;
    text-align: center;
    }
    .highScore>span{
    display: block;
    }
    .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}

    最后JS界面设计算法运算调用函数

    var game = {
    RN:4,CN:4,
    data:null,//保存游戏的二维数组 //总行数,总列数
    score:0, //分数初始值为0
    highScore:0,//最高分初始值为0
    start(){
    //清零分数
    this.score = 0;
    //1.初始化data二维数组 每一个数据都初始化为
    //新建空数组存储到data
    this.data = [];
    //通过总行数和总列数,循环遍历每个数。并且赋值为0
    for(var r = 0;r<this.RN;r++){
    //空数组中的r行
    //新建一个空数组保存在data的r行中
    this.data[r] = [];
    for(var c = 0;c<this.CN;c++){
    //空数组中r行c位置的数值 设置为0
    this.data[r][c] = 0;
    }
    }
    //2.随机在二维数组中添加两个数值,2或4
    this.randomNum();
    this.randomNum();
    console.log(this.data.join(' '));
    //3.将data二维数组中的数据展示到页面的div中去
    this.updataView();
    //4.触发游戏
    //当在键盘上按上,下,左,右触发事件
    document.onkeydown = function(e){
    switch(e.keyCode){
    case 37://左移
    //this.moveleft(); 这里面的this关键字不在指向game,因此调用game的成员不能使用this关键字
    game.moveLeft();
    break;
    case 39://右移
    game.moveRight();
    break;
    case 38://上移
    game.moveTop();
    break;
    case 40://下移
    game.moveBottom();
    break;
    }
    }
    //清零游戏结束界面的样式
    document.getElementById("false_1").className = '';
    },
    updataView(){
    //将data中的数据更新到div中
    //遍历二维数组data
    //r从0开始,到RN结束
    //c从0开始,到CN结束
    for(var r = 0;r<this.RN;r++){
    for(var c = 0;c<this.CN;c++){
    //找到id为"c"+r+c的div元素
    var div = document.getElementById("c"+r+c);
    //获取到data r行c列的数据 存储变量n中
    var n = this.data[r][c];
    //判断n是否为0
    //如果是0
    //div的内容设置为空,清除div的内容
    if(n==0){
    div.innerHTML = "";
    //恢复div的class为 item
    div.className = "item";//否则
    }else{
    //将div的值设置为n
    div.innerHTML = n;
    //将div的class设置为 item 'n'+n
    div.className ="item n"+n;
    }
    }//c 的循环结束
    //r 的循环结束
    }
    document.getElementById("scoreValue").innerHTML = this.score;
    if(this.score>this.highScore){
    this.highScore = this.score;
    }
    document.getElementById('highScoreValue').innerHTML = this.highScore;
    },
    randomNum(){
    //在一个随机位置生成2或4
    //反复:
    while(true){
    // 在0~RN-1之间生成随机数r
    r = Math.floor(Math.random()*this.RN);
    // 在0~CN-1之间生成随机数c
    c = Math.floor(Math.random()*this.CN);
    // 根据data中r行c列的值来处理
    // 如果data中r行c列的值为0
    if(this.data[r][c] == 0){
    // 将data中的r行c列赋值为:
    // 2或者4的数字 随机生成一个小数,如果<0.5,就取2,否则就取4
    this.data[r][c] = Math.random()>0.6?2:4;
    break;
    }
    // 退出循环
    }
    },
    end(){
    for(var r = 0;r<this.RN;r++){
    for(var c=0;c<this.CN;c++){
    if(this.data[r][c]==0){
    return false;
    }
    }
    }
    for(var r=1;r<this.RN-1;r++){
    for(var c=0;c<this.CN;c++){
    if((this.data[r+1][c] == this.data[r][c])||(this.data[r-1][c]==this.data[r][c])){
    return false;
    }
    }
    }
    for(var r=0;r<this.RN;r++){
    for(var c=1;c<this.CN-1;c++){
    if((this.data[r][c-1] == this.data[r][c])||(this.data[r][c+1] == this.data[r][c])){
    return false;
    }
    }
    }
    return true;
    },
    isend(){
    if(this.end()){
    document.getElementById("false_1").className = 'false';
    document.getElementById("endScore").innerHTML = this.score;
    }
    },
    moveLeft(){
    //左移所有行
    //给数组拍照 var before = String(arr)
    var before = String(this.data);
    //r从0开始,到<RN结束
    for(var r = 0;r<this.RN;r++){
    this.moveLeftInRow(r);
    }
    //左移r行
    //r循环结束
    //移动结束以后,再给数组拍照 赋值给after
    var after = String(this.data);
    //如果data数组中的数据有变化 如果before != after
    if(before != after){
    //调用updateView更新页面中数据
    this.randomNum();
    this.updataView();
    this.isend();
    }
    },
    moveLeftInRow(r){
    //c从0开始,到<CN-1
    ////查找r行c列 下一个不为0的位置nextc
    for(var c = 0;c<this.CN-1;c++){
    for(var i = c+1;i<this.CN;i++){
    // i从c+1开始,到<CN结束
    // 当前i位置的值是否为0
    if(this.data[r][i] != 0){
    // 值不为0的位置 i赋值nextc
    var nextc = i;
    break;
    }else{
    // 否则
    // 将nextc赋值为-1
    nextc = -1;
    }
    }// i循环结束
    // 如果nextc的值为-1,证明后面的都是0,直接退出
    if (nextc == -1) {
    break;
    }else{// 否则
    // 找r行c列位置的值,判断是否为0
    if(this.data[r][c] == 0) {// 如果是0 将nextc位置的值赋值给c位置
    this.data[r][c] = this.data[r][nextc];
    this.data[r][nextc] = 0;// 将nextc位置的值赋值为0
    c--;// 将c留在原地
    }else if(this.data[r][c] == this.data[r][nextc]){
    // 否则 else if(c位置的值等于nextc位置的值)
    this.data[r][c] *= 2;// 将c位置的值*2
    this.score += this.data[r][c];
    this.data[r][nextc] = 0;// 将nextc位置的值赋值为0
    // c的循环结束
    }
    }
    }
    },
    moveRight(){
    //右移所有行
    //给数组拍照 var before = String(arr)
    var before = String(this.data);
    //r从0开始,到<RN结束
    for(var r = 0;r<this.RN;r++){
    this.moveRightInRow(r);
    }
    //右移r行
    //r循环结束
    //移动结束以后,再给数组拍照 赋值给after
    var after = String(this.data);
    //如果data数组中的数据有变化 如果before != after
    if(before != after){
    //调用updateView更新页面中数据
    this.randomNum();
    this.updataView();
    this.isend();
    }
    },
    moveRightInRow(r){
    //c从cn-1开始,到0
    ////查找r行c列 上一个不为0的位置nextc
    for(var c = this.CN-1;c>0;c--){
    for(var i = c-1;i>=0;i--){
    // i从c-1开始,到>-1结束
    // 当前i位置的值是否为0
    if(this.data[r][i] != 0){
    // 值不为0的位置 i赋值nextc
    var nextc = i;
    break;
    }else{
    // 否则
    // 将nextc赋值为-1
    nextc = -1;
    }
    }// i循环结束
    // 如果nextc的值为-1,证明后面的都是0,直接退出
    if (nextc == -1){
    break;
    }else{// 否则
    // 找r行c列位置的值,判断是否为0
    if(this.data[r][c] == 0) {// 如果是0 将nextc位置的值赋值给c位置
    this.data[r][c] = this.data[r][nextc];
    this.data[r][nextc] = 0;// 将nextc位置的值赋值为0
    c++;// 将c留在原地
    }else if(this.data[r][c] == this.data[r][nextc]){
    // 否则 else if(c位置的值等于nextc位置的值)
    this.data[r][c] *= 2;// 将c位置的值*2
    this.score += this.data[r][c];
    this.data[r][nextc] = 0;// 将nextc位置的值赋值为0
    // c的循环结束
    }
    }
    }
    },
    moveTop(){
    //上移所有列
    //给数组拍照 var before = String(arr)
    var before = String(this.data);
    //c从0开始,到<CN结束
    for(var c = 0;c<this.CN;c++){
    this.moveTopInRow(c);
    }
    //上移c列
    //c循环结束
    //移动结束以后,再给数组拍照 赋值给after
    var after = String(this.data);
    //如果data数组中的数据有变化 如果before != after
    if(before != after){
    //调用updateView更新页面中数据
    this.randomNum();
    this.updataView();
    this.isend();
    }
    },
    moveTopInRow(c){
    //r从0开始,到<CN-1
    ////查找r行c列 下一个不为0的位置nextr
    for(var r = 0;r<this.RN-1;r++){
    for(var i = r+1;i<this.RN;i++){
    // i从r+1开始,到<RN结束
    // 当前i位置的值是否为0
    if(this.data[i][c] != 0){
    // 值不为0的位置 i赋值nextr
    var nextr = i;
    break;
    }else{
    // 否则
    // 将nextr赋值为-1
    nextr = -1;
    }
    }// i循环结束
    // 如果nextr的值为-1,证明后面的都是0,直接退出
    if (nextr == -1) {
    break;
    }else{// 否则
    // 找r行c列位置的值,判断是否为0
    if(this.data[r][c] == 0) {// 如果是0 将nextr位置的值赋值给r位置
    this.data[r][c] = this.data[nextr][c];
    this.data[nextr][c] = 0;// 将nextr位置的值赋值为0
    r--;// 将r留在原地
    }else if(this.data[r][c] == this.data[nextr][c]){
    // 否则 else if(c位置的值等于nextc位置的值)
    this.data[r][c] *= 2;// 将c位置的值*2
    this.score += this.data[r][c];
    this.data[nextr][c] = 0;// 将nextc位置的值赋值为0
    // c的循环结束
    }
    }
    }
    },
    moveBottom(){
    //下移所有行
    //给数组拍照 var before = String(arr)
    var before = String(this.data);
    //c从0开始,到<CN结束
    for(var c = 0;c<this.CN;c++){
    this.moveBottomInRow(c);
    }
    //下移c列
    //c循环结束
    //移动结束以后,再给数组拍照 赋值给after
    var after = String(this.data);
    //如果data数组中的数据有变化 如果before != after
    if(before != after){
    //调用updateView更新页面中数据
    this.randomNum();
    this.updataView();
    this.isend();
    }
    },
    moveBottomInRow(c){
    //c从CN-1开始,到>0
    ////查找r行c列 下一个不为0的位置nextr
    for(var r = this.CN-1;r>0;r--){
    for(var i = r-1;i>=0;i--){
    // i从r-1开始,到>-1结束
    // 当前i位置的值是否为0
    if(this.data[i][c] != 0){
    // 值不为0的位置 i赋值nextr
    var nextr = i;
    break;
    }else{
    // 否则
    // 将nextr赋值为-1
    nextr = -1;
    }
    }// i循环结束
    // 如果nextr的值为-1,证明后面的都是0,直接退出
    if (nextr == -1){
    break;
    }else{// 否则
    // 找r行c列位置的值,判断是否为0
    if(this.data[r][c] == 0) {// 如果是0 将nextr位置的值赋值给c位置
    this.data[r][c] = this.data[nextr][c];
    this.data[nextr][c] = 0;// 将nextr位置的值赋值为0
    r++;// 将c留在原地
    }else if(this.data[r][c] == this.data[nextr][c]){
    // 否则 else if(c位置的值等于nextr位置的值)
    this.data[r][c] *= 2;// 将c位置的值*2
    this.score += this.data[r][c];
    this.data[nextr][c] = 0;// 将nextr位置的值赋值为0
    // r的循环结束
    }
    }
    }
    },
    }

     六.总结

    1.布局,样式比较简单

    2.js算法设计比较麻烦,构造函数不熟练,练习较少

    3.游戏进行到一半,出现死循环,界面卡死不动,原因是循环里面的break位置没有放对地方

  • 相关阅读:
    MFC 的CLIST控件
    。。。。
    异常网
    27款经典的CSS框架 狼人:
    分析:从服务器出货情况看云发展情况 狼人:
    互联网是双刃剑 需合理把握 狼人:
    自由职业者和外包接单项目分析 狼人:
    Google发布Native Client首个开发工具包 狼人:
    MVC框架 EasyJWeb 2.0 发布 狼人:
    谷歌Chrome 11对早期开发者开放使用 狼人:
  • 原文地址:https://www.cnblogs.com/hyh888/p/11331402.html
Copyright © 2011-2022 走看看