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

导语

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

一.项目结构

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

文件.png
  • html文件
<!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>
  • css文件
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);
}

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

运行效果

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容