Web前端之路Web 前端开发

一个自制的2048小游戏(一)

2016-09-13  本文已影响1865人  酱油_

导语

本次将会从头到尾讲一个2048游戏的制作过程,中间也会穿插自己的理解

一.项目结构

除了html和css文件外,分了main.js,support.js,showanimation.js,以及引入jquery。

文件.png
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <!--手机屏幕兼容预处理-->
    <meta name="viewport" content="
        width=device-width,
        height=device-height,
        initial-scale=1.0,
        minimum-scale=1.0,
        maximum-scale=1.0,
        user-scalable=no">
    <title>2048</title>
    <link rel="stylesheet" type="text/css" href="2048.css">
</head>
<body>
    <header>
        <h1 class="title">我的2048</h1>
        <a href="javascript:newGame();" id="newGameBtn">NewGame</a>
        <p>score:<span id="score">0</span></p>
        <!--<div class="scores-container">
            <div class="score-container">0</div>
            <div class="best-container">0</div>
        </div>-->
    </header>

     <div id="grid-container">
        <div class="grid-cell" id="grid-cell-0-0"></div>
        <div class="grid-cell" id="grid-cell-0-1"></div>
        <div class="grid-cell" id="grid-cell-0-2"></div>
        <div class="grid-cell" id="grid-cell-0-3"></div>
        <div class="grid-cell" id="grid-cell-1-0"></div>
        <div class="grid-cell" id="grid-cell-1-1"></div>
        <div class="grid-cell" id="grid-cell-1-2"></div>
        <div class="grid-cell" id="grid-cell-1-3"></div>
        <div class="grid-cell" id="grid-cell-2-0"></div>
        <div class="grid-cell" id="grid-cell-2-1"></div>
        <div class="grid-cell" id="grid-cell-2-2"></div>
        <div class="grid-cell" id="grid-cell-2-3"></div>
        <div class="grid-cell" id="grid-cell-3-0"></div>
        <div class="grid-cell" id="grid-cell-3-1"></div>
        <div class="grid-cell" id="grid-cell-3-2"></div>
        <div class="grid-cell" id="grid-cell-3-3"></div>
    </div>
    <script type="text/javascript" src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
    <script type="text/javascript" src="support2048.js"></script>
    <script type="text/javascript" src="showanimation.js"></script>
    <script type="text/javascript" src="main2048.js"></script>
</body>
</html>
html, body, div, span, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
abbr, address, cite, code,
del, dfn, em, img, ins, kbd, q, samp,
small, strong, sub, sup, var,
b, i,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, figcaption, figure, 
footer, header, hgroup, menu, nav, section, summary,
time, mark, audio, video {
    margin:0;
    padding:0;
    border:0;
    outline:0;
    font-size:100%;
    vertical-align:baseline;
    background:transparent;
}
body {
    font-size:12px;
    line-height:120%;
    text-align:center;
    color:#333;
    padding:20px;
    font:12px/1.5 '微软雅黑',tahoma,arial,'Hiragino Sans GB',宋体,sans-serif;
}
table{  border-collapse:collapse;
    border-spacing:0;
}
fieldset,img{border:0;}
address,caption,cite,code,dfn,em,strong,th,var{
    font-style:normal;
    font-weight:normal;
}
img{border:none;}
ol,ul{list-style:none;}
input, select,textarea{
    vertical-align:middle;
    outline:none;
}
textarea{resize:none;}
a{
    color:#333;
    text-decoration:none;
}
a:hover{
    text-decoration:underline;
}
/*清浮*/
.clearfix:after{
    content:"";
    display:block;
    clear:both;
}
.clearfix{zoom:1}

/********************************************/
body{
    background:#978E81;
}
header{
    display:block;
    margin:0 auto;
    width:100%;     /*为了兼容移动端*/
    text-align:center;
}
header h1{
    font-family:Arial;
    font-size:30px;
    font-weight:bold;
}
header #newGameBtn{
    display: block;
    margin:10px auto;
    width:100px;
    padding:5px 10px;
    background-color:#8f7a66;
    font-family:Arial;
    color:white;
    border-radius:10px;
    text-decoration:none;
}
header #newGameBtn:hover{
    background-color:#9f8b77;
}
header p{
    font-family:Arial;
    font-size:25px;
    margin:10px auto;

}
#grid-container{
    width:460px;
    height:460px;
    padding:20px;
    margin:30px auto;
    background-color: #bbada0;
    border-radius:10px;
    position:relative;
}
.grid-cell{
    width:100px;
    height:100px;
    border-radius:12px;
    background-color:#ccc0b3;
    position:absolute;

}
.number-cell{
    border-radius:4px;
    font-family:Arial;
    font-weight:bold;
    font-size:60px;
    line-height:100px;
    text-align:center;
    position:absolute;
}

二.游戏逻辑循序渐进,初始化

  1. 首先毫无疑问,需要先初始化游戏,渲染方块之类的。
    我们声明两个变量。
var board=new Array();  //存储游戏的数据
var score=0;    //得分

然后定义一个newGame函数,并且等document加载完后调用它

$(document).ready(function(){
    newGame();
})
function newGame(){
    //为移动端初始化宽度
    prepareForMobile();
    //初始化棋盘格
    init();
    //在随机两个格子生成数字
    generateOneNumber();
    generateOneNumber();
}

先忽略那个兼容移动端的,我们根据游戏的逻辑,在newGame里面写了两件事,一个是初始化,一个是随机在格子中生成一个数字,一开始要有两个,所以这个方法调用两遍。下面是init里的内容

function init(){
    //有数字的小方块
    for(var i=0;i<4;i++){
        for(var j=0;j<4;j++){
            var gridCell=$("#grid-cell-"+i+"-"+j);
            gridCell.css({
                "top":getPosTop(i,j),
                "left":getPosLeft(i,j)
            });
        }
    }
    //初始化board数组
    for(var i=0;i<4;i++){
        board[i]=new Array();
        for(var j=0;j<4;j++){
            board[i][j]=0;

        }
    }
    //有操作,更新界面
    updateBoardView();

    score=0;
    $("#score").text(score);
}

在init初始化里面,我们先做的是给16个背景小方块,因为在css文件里面我们只写了定位方式absolute。
通过遍历得到每个格子,css()方法给他们设置定位。我们将getPosTop,getPosLeft两个方法写在support.js中

//20是格子之间的距离,100是一个小格子的宽度
function getPosTop(i,j){
    var top=20+i*(100+20);
    return top;
}
function getPosLeft(i,j){
    var left=20+j*(100+20);
    return left;
}

定位完成后我们进行的是board数组的初始化,初始化为一个4*4的二维数组,值为false。board初始化完成后我们则根据board来将游戏界面更新。因为后续我们会经常使用到根据board数组更新游戏画面,所以将其写成一个updateBoardView()方便调用

  1. updateBoardView()函数
    因为有注释,所以简单说一下。我们是动态加载有数字的方块的,每次更新先将所有的数字方块全部移除,在弄个循环创建它们,并且创建的同时用css设置样式。设置样式时先判断这个位置的board是不是0,为零的话则将宽高设置为0,并将它们的top,left设置在背景方格的中间(这里是为了后面的animate动画是从中间变化)。对于board中有值的,则需要多设置他们的background-color和color。最后将值显示在html中,即theNumberCell.text(board[i][j])
//更新棋盘上显示的方块
function updateBoardView(){
    //如果有number-cell后先删除
    $(".number-cell").remove();
    //遍历格子,改变样式
    for(var i=0;i<4;i++){
        for(var j=0;j<4;j++){
            $("#grid-container").append('<div class="number-cell" id="number-cell-'+i+'-'+j+'"></div>')
            var theNumberCell=$("#number-cell-"+i+"-"+j);

            if(board[i][j]==0){
                theNumberCell.css({
                    "width":"0px",
                    "height":"0px",
                    "top":getPosTop(i,j)+50,/*这里是为了把它放中间,动画才好看*/
                    "left":getPosLeft(i,j)+50
                });
            }else{
                theNumberCell.css({
                    "width":100+'px',
                    "height":100+'px,
                    "top":getPosTop(i,j),
                    "left":getPosLeft(i,j),
                    "background-color":getNumberBackgroundColor(board[i][j]),
                    "color":getNumberColor(board[i][j])
                });
                theNumberCell.text(board[i][j]);
            }
        }
        $('.number-cell').css({
            'line-height':cellSideLength+'px',
            'font-size':0.6*cellSideLength+'px'
        })
    }
}
  1. 数字方块的背景色与前景色的获取
    我们将这两个函数写在support.js中,就使用了一个switch,简单明了,不多解释
function getNumberBackgroundColor(number){
    var color="black";
    switch(number){
        case 2:
            color='#eee4da';
            break;
        case 4:
            color="#ede0c8";
            break;
        case 8:
            color='#f2b179';
            break;
        case 16:
            color="#f59563";
            break;
        case 32:
            color='#f67c5f';
            break;
        case 64:
            color="#f65e3b";
            break;
        case 128:
            color='#edcf72';
            break;
        case 256:
            color="#edcc61";
            break;
        case 512:
            color='#9c0';
            break;
        case 1024:
            color="#33b5e5";
            break;
        case 2048:
            color='#09c';
            break;
    }
    return color;
}
function getNumberColor(number){
    if(number<=4){
        return "#776e50";
    }
    return "white";
}

三.初始化最后一步:generateOneNumber()

要想在格子上随机生成一个数字,首先我们需要先确定还有空格子可以生成,没有的话直接返回,所以先判断

//先看有无空格
    if(nospace(board)){
        return false;
    }

将nospace(board)写在support.js中

function nospace(board){
    for(var i=0;i<4;i++){
        for(var j=0;j<4;j++){
            if(board[i][j]==0){
                return false;
            }
        }
    }
    return true;
}

接着要随机生成一个坐标,并且判断这个点是不是为空,不为空则继续随机生成。实在是找不到了,就遍历格子,选第一个为空的格子

//随机生成一个位置
    var randx=parseInt(Math.floor(Math.random()*4));
    var randy=parseInt(Math.floor(Math.random()*4));
//看是不是空格,优化随机
    var times=0;
    while(times<50){
        if(board[randx][randy]==0){
            break;
        }
        //重复
        var randx=parseInt(Math.floor(Math.random()*4));
        var randy=parseInt(Math.floor(Math.random()*4));

        times++;
    }
    if(times==50){
        for(var i=0;i<4;i++){
            for(var j=0;j<4;j++){
                if(board[i][j]==0){
                    randx=i;
                    randy=j;
                }
            }
        }
    }

然后随机生成个2或4 var randNumber=Math.random()<0.65?2:4;
最后将这个数字格子用动画表现出来,并更新board数组

    showNumberWithAnimation(randx,randy,randNumber);
    board[randx][randy]=randNumber;

最后,我们将showNumberWithAnimation()写在showanimation.js中。
主要是通过jq的animate实现动画效果。

function showNumberWithAnimation(i,j,randNumber){
    var numberCell=$("#number-cell-"+i+"-"+j);

    numberCell.css({
        'background-color':getNumberBackgroundColor(randNumber),
        'color':getNumberColor(randNumber)
    });
    
    numberCell.animate({
        width:100,
        height:100,
        top:getPosTop(i,j),
        left:getPosLeft(i,j)
    },50);
    numberCell.text(randNumber);
}

至此,我们的游戏的初始化就完成了,在浏览器里运行一下吧

运行效果

因为一篇写完的话太长,所以先写到这里,后续的请看接下来的文章,谢谢

上一篇 下一篇

猜你喜欢

热点阅读