首页 > 网站 > WEB开发 > 正文

Javascript写了一个2048的游戏

2024-04-27 14:08:01
字体:
来源:转载
供稿:网友

javascript写了一个2048的游戏

  去年2048很火, 本来我也没玩过, 同事说如果用JS写2048 只要100多行代码;

  PS(iWeb峰会暨攻城师嘉年华2015嘉年华要来啦, 在文章结尾有具体的地址和时间);

  今天试了一下, 逻辑也不复杂, 主要是数据构造函数上的数据的各种操作, 然后通过重新渲染DOM实现界面的更新, 整体不复杂, JS,CSS,和HTML合起来就300多行;

  界面的生成使用了underscore.jstemplate方法, 使用了jQuery,主要是DOM的选择操作以及动画效果,事件的绑定只做了PC端的兼容,只绑定了keydown事件;

  把代码放到github-page上, 通过点击这里查看 实例: 打开2048实例;

  效果图如下:

  

  所有的代码分为两大块,Data, View;

  Data是构造函数, 会把数据构造出来, 数据会继承原型上的一些方法;

  View是根据Data的实例生成视图,并绑定事件等, 我直接把事件认为是controller了,和View放在了一起, 没必要分开;

  Data的结构如下:

        /**         * @desc 构造函数初始化         * */        init : function        /**         * @desc 生成了默认的数据地图         * @param void         * */        generateData : function        /**         * @desc 随机一个block填充到数据里面         * @return void         * */        generationBlock : function        /**         * @desc 获取随机数 2 或者是 4         * @return 2 || 4;         * */        getRandom : function        /**         * @desc 获取data里面数据内容为空的位置         * @return {x:number, y:number}         * */        getPosition : function        /**         * @desc 把数据里第y排, 第x列的设置, 默认为0, 也可以传值;         * @param x, y         * */        set : function        /**         * @desc 在二维数组的区间中水平方向是否全部为0         * @desc i明确了二维数组的位置, k为开始位置, j为结束为止         * */        no_block_horizontal : function        no_block_vertica : function        /**         * @desc 往数据往左边移动,这个很重要         * */        moveLeft : function        moveRight : function        moveUp : function        moveDown : function

  有了数据模型,那么视图就简单了,主要是用底线库underscoretemplate方法配合数据生成html字符串,然后对界面进行重绘:

View的原型方法:        renderHTML : function //生成html字符串,然后放到界面中        init : function //构造函数初始化方法        bindEvents : function //给str绑定事件, 认为是控制器即可

  因为原始的2048有方块的移动效果, 我们独立起来了一个服务(工具方法,这个工具方法会被View继承), 主要是负责界面中的方块的移动, getPost是给底线库用的, 在模板生成的过程中需要根据节点的位置动态生成横竖坐标,然后定位:

    var util = {        animateShowBlock : function() {            setTimeout(function() {                this.renderHTML();            }.bind(this),200);        },        animateMoveBlock : function(PRop) {            $("#num"+prop.form.y+""+prop.form.x).animate({top:40*prop.to.y,left:40*prop.to.x},200);        },        //底线库的模板中引用了这个方法;        getPost : function(num) {            return num*40 + "px";        }        //这个应该算是服务;    };

  下面是全部的代码, 引用的JS使用了CDN,可以直接打开看看:

<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title></title></head><body><script src="http://cdn.bootcss.com/underscore.js/1.8.3/underscore-min.js"></script><script src="http://cdn.bootcss.com/jquery/2.1.4/jquery.js"></script><style>    #g{        position: relative;    }    .block,.num-block{        position: absolute;        width: 40px;        height: 40px;        line-height: 40px;        text-align: center;        border-radius: 4px;    }    .block{        border:1px solid #eee;        box-sizing: border-box;    }    .num-block{        color:#27AE60;        font-weight: bold;    }</style>    <div class="container">        <div class="row">            <div id="g">            </div>        </div>    </div><script id="tpl" type="text/template">    <% for(var i=0; i<data.length; i++) {%>            <!--生成背景块元素--->        <% for(var j=0; j< data[i].length; j++ ) { %>            <div id="<%=i%><%=j%>" class="block" style="left:<%=util.getPost(j)%>;top:<%=util.getPost(i)%>"  data-x="<%=j%>" data-y="<%=i%>" data-info='{"x":<%=[j]%>,"y":<%=[i]%>}'>            </div>        <% } %>            <!--生成数字块元素--->        <% for(var j=0; j< data[i].length; j++ ) { %>            <!--如果数据模型里面的值为0,那么不显示这个数据的div--->            <% if ( 0!==data[i][j] ) {%>                <div id="num<%=i%><%=j%>" class="num-block" style="left:<%=util.getPost(j)%>;top:<%=util.getPost(i)%>" >                    <%=data[i][j]%>                </div>            <% } %>        <% } %>    <% } %></script><script>    var Data = function() {        this.init();    };    $.extend(Data.prototype, {        /**         * @desc 构造函数初始化         * */        init : function() {            this.generateData();        },        /**         * @desc 生成了默认的数据地图         * @param void         * */        generateData : function() {            var data = [];            for(var i=0; i<4; i++) {                data[i] = data[i] || [];                for(var j=0; j<4; j++) {                    data[i][j] = 0;                };            };            this.map = data;        },        /**         * @desc 随机一个block填充到数据里面         * @return void         * */        generationBlock : function() {            var data = this.getRandom();            var position = this.getPosition();            this.set( position.x, position.y, data)        },        /**         * @desc 获取随机数 2 或者是 4         * @return 2 || 4;         * */        getRandom : function() {            return Math.random()>0.5 ? 2 : 4;        },        /**         * @desc 获取data里面数据内容为空的位置         * @return {x:number, y:number}         * */        getPosition : function() {            var data = this.map;            var arr = [];            for(var i=0; i<data.length; i++ ) {                for(var j=0; j< data[i].length; j++ ) {                    if( data[i][j] === 0) {                        arr.push({x:j, y:i});                    };                };            };            return arr[ Math.floor( Math.random()*arr.length ) ];        },        /**         * @desc 把数据里第y排, 第x列的设置, 默认为0, 也可以传值;         * @param x, y         * */        set : function(x,y ,arg) {            this.map[y][x] = arg || 0;        },        /**         * @desc 在二维数组的区间中水平方向是否全部为0         * @desc i明确了二维数组的位置, k为开始位置, j为结束为止         * */        no_block_horizontal: function(i, k, j) {            k++;            for( ;k<j; k++) {                if(this.map[i][k] !== 0)                return false;            };            return true;        },        //和上面一个方法一样,检测的方向是竖排;        no_block_vertical : function(i, k, j) {            var data = this.map;            k++;            for(; k<j; k++) {                if(data[k][i] !== 0) {                    return false;                };            };            return true;        },        /**         * @desc 往左边移动         * */        moveLeft : function() {            /*            * 往左边移动;            * 从上到下, 从左到右, 循环;            * 从0开始继续循环到当前的元素 ,如果左侧的是0,而且之间的空格全部为0 , 那么往这边移,            * 如果左边的和当前的值一样, 而且之间的空格值全部为0, 就把当前的值和最左边的值相加,赋值给最左边的值;            * */            var data = this.map;            var result = [];            for(var i=0; i<data.length; i++ ) {                for(var j=1; j<data[i].length; j++) {                    if (data[i][j] != 0) {                        for (var k = 0; k < j; k++) {                            //当前的是data[i][j], 如果最左边的是0, 而且之间的全部是0                            if (data[i][k] === 0 && this.no_block_horizontal(i, k, j)) {                                result.push( {form : {y:i,x:j}, to :{y:i,x:k}} );                                data[i][k] = data[i][j];                                data[i][j] = 0;                                //加了continue是因为,当前的元素已经移动到了初始的位置,之间的循环我们根本不需要走了                                break;                            }else if(data[i][j]!==0 && data[i][j] === data[i][k] && this.no_block_horizontal(i, k, j)){                                result.push( {fo
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表