2020-04-17

小游戏--2048

只用了HTML、CSS和JavaScript,代码纯手写,逻辑简单已实现,可以尝试自己动手做一下

目前代码是做了PC端的展示,没有做移动端的适配.滑动效果做的不太好,请见谅!

效果展示如下

2048-小游戏

代码展示如下

页面布局--HTML

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
        <link rel="stylesheet" href="css/new.css" />
        <script type="text/javascript" src="js/js.js" ></script>
    </head>
    <body>
        <div id="continer">
            <div id="header">
                <h1 class="title">2048</h1>
                <!--<h3 class="author">by lichong</h3>-->
                <div id="">
                    <label>得分:</label><span id="score">0</span>
                    <button id="newGame">newGame</button>
                </div>
            </div>
            <div id="footer">
                <div id="mask">
                    <h3>当前得分为:</h3>
                    <label id="nowScore"></label> <br />
                    <button id="again">重新开始</button>
                </div>
                <div id="mask-cell-0-0" class="mask-cell"></div>
                <div id="mask-cell-0-1" class="mask-cell"></div>
                <div id="mask-cell-0-2" class="mask-cell"></div>
                <div id="mask-cell-0-3" class="mask-cell"></div>
                
                <div id="mask-cell-1-0" class="mask-cell"></div>
                <div id="mask-cell-1-1" class="mask-cell"></div>
                <div id="mask-cell-1-2" class="mask-cell"></div>
                <div id="mask-cell-1-3" class="mask-cell"></div>
                
                <div id="mask-cell-2-0" class="mask-cell"></div>
                <div id="mask-cell-2-1" class="mask-cell"></div>
                <div id="mask-cell-2-2" class="mask-cell"></div>
                <div id="mask-cell-2-3" class="mask-cell"></div>
                
                <div id="mask-cell-3-0" class="mask-cell"></div>
                <div id="mask-cell-3-1" class="mask-cell"></div>
                <div id="mask-cell-3-2" class="mask-cell"></div>
                <div id="mask-cell-3-3" class="mask-cell"></div>
            </div>
        </div>
    </body>
</html>

页面的渲染--CSS

*{
    margin: 0px;
    padding: 0px;
}
#continer{
    border: 1px solid black;
    width: 500px;   
    margin: 0 auto;
    text-align: center;
    background-color: #8E8E38
}
#header .author{
    margin-left: 200px;
    padding: 20px 0 ;
}
#header label,span{
    position: relative;
    left: -130px;
    text-align: left;
    font-size: 20px;
    border-radius: 2px;
    background-color:blueviolet;
}
#header label{
    margin-right: 0px;
}
#newGame{
    position: relative;
    right: -130px;
    font-size: 20px;
    border-radius: 4px;
    border: 1px solid;
    background-color: blueviolet;
}
#footer{
    width: 500px;
    height: 500px;
    /*background-color: #655123;*/
    position: relative;
}
#mask{
    position: absolute;
    width: 200px;
    height: 300px;
    top: 100px;
    left: 150px;
    z-index: 4;
    border-radius: 10px;
    text-align: center;
    line-height: 100px;
    background-color: #ff33cc;
    visibility: hidden;
}
#nowScore{
    padding: 20px;
    margin: 10px;
    font-size: 50px;
}
#again{
    background-color: #ccff66;
    padding: 10px 20px;
    letter-spacing: 2px;
    border: none;
    border-radius: 5px;
}
#footer .mask-cell{
    position: absolute;
    width: 100px;
    height: 100px;
    border-radius: 6px;
}

逻辑层的实现--JS

//声明一个数组存放卡片上的数字
var nums = new Array();
//获取得分和newGame两个控件
var score = document.getElementById("score");
var newGames = document.getElementById("newGame");
//预加载
window.onload = function(){
    //给newGame添加点击事件
    document.getElementById("newGame").onclick = function(){
        newGame();
        document.getElementById("score").innerHTML = 0;
    }
    //给again添加点击事件
    document.getElementById("again").onclick = function(){
        newGame();
        document.getElementById("score").innerHTML = 0;
        document.getElementById("mask").style.visibility = "hidden";
    }
    document.getElementById("score").innerHTML = 0;
    newGame();
}

function newGame(){
    //初始化
    init();
    //初始化生成两个卡片
    getOneNewNumber();
    getOneNewNumber();
    document.onkeydown = function(e){
        //阻止window默认事件
        e.preventDefault();
        //获取按键的code值
        var keyCode = e.keyCode;
        /*
         * 1.判断是否能向指定的方向移动
         *      能>向左移动>更新视图>重新生成一个卡片
         * 2.不能
         *      游戏结束
         */
        switch (keyCode){
            case 37:
                if(canMoveLeft()){
                    moveLeft();
                    updateView();
                    getOneNewNumber();
                    console.log("还剩下"+noZeroNum()+"个格子")
                }
                if(!noCanMove()){
                    gameOver();
                }
                break;
            case 38:
                if(canMoveUp()){
                    moveUp();
                    updateView();
                    getOneNewNumber();
                    console.log("还剩下"+noZeroNum()+"个格子")
                }
                if(!noCanMove()){
                    gameOver();
                }
                break;
            case 39:
                if(canMoveRight()){
                    moveRigth();
                    updateView();
                    getOneNewNumber();
                    console.log("还剩下"+noZeroNum()+"个格子")
                }
                if(!noCanMove()){
                    gameOver();
                }
                break;
            case 40:
                if(canMoveDown()){
                    moveDown();
                    updateView();
                    getOneNewNumber();
                    console.log("还剩下"+noZeroNum()+"个格子")
                }
                if(!noCanMove()){
                    gameOver();
                }
                break;
        }
        
    }
}
function init(){
    //初始化布局
    for(var i = 0;i<4;i++){
        for(var j = 0;j<4;j++){
            document.getElementById("mask-cell-"+i+"-"+j).style.top = i*120 + 20  + "px";
            document.getElementById("mask-cell-"+i+"-"+j).style.left = j*120 + 20 + "px"; 
            document.getElementById("mask-cell-"+i+"-"+j).style.backgroundColor = "yellowgreen"
        }
    }
    //初始化创建16张数字卡片,放在原来的16个div上(定位)
    for(var i = 0;i<4;i++){
        for(var j = 0;j<4;j++){
            var div = document.createElement("div")
            div.setAttribute("id","number-cell-"+ i +"-"+ j );
            div.setAttribute("class","number-cell" )
            document.getElementById("footer").appendChild(div)
            document.getElementById("number-cell-"+i+"-"+j).style.position = "absolute"
            document.getElementById("number-cell-"+i+"-"+j).style.top = i*120 + 20 + "px";
            document.getElementById("number-cell-"+i+"-"+j).style.left = j*120 + 20 + "px"; 
        }
    }
    //初始化数字
    for(var m = 0;m<4;m++){
        nums[m] = new Array();
        for(var n = 0;n<4;n++){
            nums[m][n] = 0;
        }
    }
    //动态更新布局
    updateView();
}
/*
 * 动态更新视图
 */
function updateView(){
    for(var i = 0;i<4;i++){
        for(var j = 0;j<4;j++){
            var numberCell = document.getElementById("number-cell-"+ i +"-"+ j);
            numberCell.innerText = "";
            if(nums[i][j] == 0){
                numberCell.style.width = 0 + "px";
                numberCell.style.height = 0 + "px";
            }else{
                numberCell.style.width = 100 + "px";
                numberCell.style.height = 100 + "px";
                numberCell.style.textAlign = "center";
                numberCell.style.fontSize = "50px"
                numberCell.style.lineHeight = "100px"
                /*
                 * 根据卡片上的数字不同,添加不同的背景颜色
                 */
                switch (nums[i][j]){
                    case 2:
                        numberCell.style.backgroundColor = "#ffff33";
                        break;
                    case 4:
                        numberCell.style.backgroundColor = "#ffcc33";
                        break;
                    case 8:
                        numberCell.style.backgroundColor = "#ff6633";
                        break;
                    case 16:
                        numberCell.style.backgroundColor = "#ff3333";
                        break;
                    case 32:
                        numberCell.style.backgroundColor = "#ff0033";
                        break;
                    case 64:
                        numberCell.style.backgroundColor = "#ccff66";
                        break;
                    case 128:
                        numberCell.style.backgroundColor = "#cc3399";
                        break;
                    case 256:
                        numberCell.style.backgroundColor = "#9933cc";
                        break;
                    case 512:
                        numberCell.style.backgroundColor = "#66ffff";
                        break;
                    case 1024:
                        numberCell.style.backgroundColor = "#6600cc";
                        break;
                    case 2048:
                        numberCell.style.backgroundColor = "#0066ff";
                        break;
                    default:
                        break;
                }
                    numberCell.innerText = nums[i][j];
            }
        }
    }
}
function getOneNewNumber(){
    //声明一个数组.存放不为零的卡片,存放的内容 i*4+j
    var numPosition = new Array();
    //判断是否还有为零 的空间
    if(noSpace(nums)){
        return;
    }
    //找到数字为零的卡片的位置
    for (var i = 0;i<4;i++) {
        for (var j = 0;j<4;j++) {
            if(nums[i][j] == 0){
                numPosition.push(i*4+j);
            }
        }
    }
        //从不为零的数组中,随机选取一个,还原它的X,Y坐标,然后设置它的css样式,同时把它放进nums数组中
        var random = numPosition[Math.floor(Math.random()*numPosition.length)];
        var randX = Math.floor(random/4);
        var randY = Math.floor(random%4);
        var randNum = Math.random()>0.5?2:4;
        console.log(numPosition);
        document.getElementById("number-cell-"+randX+"-"+randY).style.borderRadius = "6px";
        document.getElementById("number-cell-"+randX+"-"+randY).innerText = randNum;
        document.getElementById("number-cell-"+randX+"-"+randY).style.textAlign = "center";
        document.getElementById("number-cell-"+randX+"-"+randY).style.fontSize = "50px"
        document.getElementById("number-cell-"+randX+"-"+randY).style.lineHeight = "100px"
        switch (randNum){
            case 2:
                document.getElementById("number-cell-"+randX+"-"+randY).style.backgroundColor = "#ffff33";
                break;
            case 4:
                document.getElementById("number-cell-"+randX+"-"+randY).style.backgroundColor = "#ffcc33";
                break;
            default:
                break;
        }
        showAnimation(randX,randY);
        nums[randX][randY] = randNum;
}

function noSpace(nums){
    //判断是否还有不为零的卡片
    for (var i = 0;i<4;i++) {
        for (var j = 0;j<4;j++) {
            if(nums[i][j] == 0){
                return false;
            }
        }
    }
    return true;
}
//生成卡片上数字时的动画
function showAnimation(randX,randY,){
    var lefts = randY*120 + 70;
    var tops = randX*120 + 70;
    var width = 0;
    var height = 0;
    var intervalId = setInterval(function(){
        if(tops == (randX*120+20)){
            clearInterval(intervalId);
            return;
        }else{
            width += 2;
            height += 2;
            tops--;
            lefts--;
            document.getElementById("number-cell-"+randX+"-"+randY).style.width = width + "px";
            document.getElementById("number-cell-"+randX+"-"+randY).style.height = height + "px";
            document.getElementById("number-cell-"+randX+"-"+randY).style.top = tops + "px";
            document.getElementById("number-cell-"+randX+"-"+randY).style.left = lefts + "px";
        }
    },5)
}
//如果上下左右都不能移动
function noCanMove(){
    return  canMoveLeft()||canMoveUp()||canMoveRight()||canMoveDown();
}
//游戏结束
function gameOver(){
    setTimeout('document.getElementById("nowScore").innerHTML = document.getElementById("score").innerText',500)
    setTimeout('document.getElementById("mask").style.visibility = "visible"',500)
    document.onkeydown = null;
}
//获取卡片上数字为零的的数量
function noZeroNum(){
    var num = 0;
        for (var i = 0;i<4;i++) {
            for (var j = 0;j<4;j++) {
                if(nums[i][j] == 0){
                    num++;
                }
            }
        }
    return num;
}
//能否左移
function canMoveLeft(){
    //有空余格
    if(noZeroNum()>0){
        return true;
    }else{
        //格子满了,判断相邻的各自是否有相同的
        for (var i = 0;i<4;i++) {
            for (var j = 1;j<4;j++) {
                if(nums[i][j] == nums[i][j-1]){
                    return true;
                }
            }
        }
    }
    return false;
}
//能都上移
function canMoveUp(){
    //有空余格
    if(noZeroNum()>0){
        return true;
    }else{
        //格子满了,判断相邻的各自是否有相同的
        for (var i = 1;i<4;i++) {
            for (var j = 0;j<4;j++) {
                if(nums[i][j] == nums[i-1][j]){
                    return true;
                }
            }
        }
    }
    return false;
}
//能否右移
function canMoveRight(){
    //有空余格
    if(noZeroNum()>0){
        return true;
    }else{
        //格子满了,判断相邻的各自是否有相同的
        for (var i = 3;i>=0;i--) {
            for (var j = 2;j>=0;j--) {
                if(nums[i][j] == nums[i][j+1]){
                    return true;
                }
            }
        }
    }
    return false;
}
//能否下移
function canMoveDown(){
    //有空余格
    if(noZeroNum()>0){
        return true;
    }else{
        //格子满了,判断相邻的各自是否有相同的
        for (var i = 2;i>=0;i--) {
            for (var j = 3;j>=0;j--) {
                if(nums[i][j] == nums[i+1][j]){
                    return true;
                }
            }
        }
    }
    return false;
}
/*
 * 判断卡片上数字相同时,能否叠加
 *      由于是一个4x4的布局,
 *      传过来四个参数,分别是两个卡片的坐标
 *      如果两个坐标相差1,即相邻,则直接相加
 *      如果两个坐标相差2,即 中间隔一个卡片,判断此 卡片上数字是否为零,是零则相加
 *      如果两个坐标相差3,即中间隔两个卡片,这两个卡片上数字都为零,则相加
 */
function canAdd(i,j,k,l){
    if(i == k){
        if(l-j == 1){
            return true;
        }
        if(l-j == 2){
            return nums[i][j+1] == 0 ;
        }
        if(l-j == 3){
            return nums[i][j+1] == 0 && nums[i][j+2] == 0;
        }
    }
    if(j == l){
        if(k-i == 1 ){
            return true;
        }
        if(k-i == 2){
            return nums[i+1][j] == 0;
        }
        if(k-i == 3){
            return nums[i+1][j] == 0 && nums[i+2][j] == 0;
        }
    }
}
/*
 * 左移
 *      遍历nums二维数组,如果左边为零,直接位移
 *                  ,如果相等,判断中间是否有间隔,没有则直接相加
 */
function moveLeft(){
    for (var i = 0;i<4;i++) {
        for(var j = 0;j<4;j++){
            if(nums[i][j] != 0){
                for(var k = 0;k<j;k++){
                    if(nums[i][k] == 0){
                        nums[i][k] = nums[i][j];
                        nums[i][j] = 0;
                    }
                    if(nums[i][k] == nums[i][j] ){
                        if(canAdd(i,k,i,j)){
                            nums[i][k] *= 2;
                            nums[i][j] = 0
                            var grade =  document.getElementById("score").innerText;
                            grade = Number(grade);
                            grade += nums[i][k];
                            document.getElementById("score").innerHTML = grade;
                        }
                        
                    }
                }
            }
        }
    }
}


function moveUp(){
    for (var i = 0;i<4;i++) {
        for(var j = 0;j<4;j++){
            if(nums[i][j] != 0){
                for(var k = 0;k<i;k++){
                    if(nums[k][j] == 0){
                        nums[k][j] = nums[i][j];
                        nums[i][j] = 0;
                    }
                    if(nums[k][j] == nums[i][j] ){
                        if(canAdd(k,j,i,j)){
                            nums[k][j] *= 2;
                            nums[i][j] = 0;
                            var grade =  document.getElementById("score").innerText;
                            grade = Number(grade);
                            grade += nums[k][j];
                            document.getElementById("score").innerHTML = grade;
                        }
                        
                    }
                }
            }
        }
    }
}
function moveRigth(){
    for (var i = 3;i>=0;i--) {
        for(var j = 3;j>=0;j--){
            if(nums[i][j] != 0){
                for(var k = 3;k>j;k--){
                    if(nums[i][k] == 0){
                        nums[i][k] = nums[i][j];
                        nums[i][j] = 0;
                    }
                    if(nums[i][k] == nums[i][j] ){
                        if(canAdd(i,j,i,k)){
                            nums[i][k] *= 2;
                            nums[i][j] = 0;
                            var grade =  document.getElementById("score").innerText;
                            grade = Number(grade);
                            grade += nums[i][k];
                            document.getElementById("score").innerHTML = grade;
                        }
                        
                    }
                }
            }
        }
    }
}
function moveDown(){
    for (var i = 3;i>=0;i--) {
        for(var j = 3;j>=0;j--){
            if(nums[i][j] != 0){
                for(var k = 3;k>i;k--){
                    if(nums[k][j] == 0){
                        nums[k][j] = nums[i][j];
                        nums[i][j] = 0;
                    }
                    if(nums[k][j] == nums[i][j] ){
                        if(canAdd(i,j,k,j)){
                            nums[k][j] *= 2;
                            nums[i][j] = 0;
                            var grade =  document.getElementById("score").innerText;
                            grade = Number(grade);
                            grade += nums[k][j];
                            document.getElementById("score").innerHTML = grade;
                        }
                        
                    }
                }
            }
        }
    }
}

逻辑层的实现用了最原始的js,如果采用jq,代码量可以少很多,并且滑动效果也可以做的更好,有兴趣的话可以尝试一下!

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

推荐阅读更多精彩内容