2048小游戏

在这里插入图片描述

思想

简述项目:
1.功能:该项目完成的功能就是通过上下左右键,使相同的方块进行合并,相同的方块合并时,会将方块上面的值变为原来的二倍,游戏的规则是,通过键盘事件,合成最大的数字
2.如何完成:

初始化:

(1)首先进行面板的初始化,根据设置的行数,列数,方块的宽高,以及边框的宽度,计算之后,设置面板的宽高
(2)根据行数和列数,创建值为0的小方块,将他们添加到面板里。
(3)初始化装各个位置的值的二维数组valueMap,以及装生成的方块的squareSet,随机生成两个方块,(调用生成值为2或者4的函数,随机生成行数,列数,生成方块)
(4)进行鼠标事件的绑定,当键盘点击,触发移动函数,

触发移动函数:

在移动函数里面先判断是否游戏结束(判断依据是遍历装方块的数组的值,看是否有为null的,或者看是否有相邻方块值相等存在),如果游戏未结束,调用分析函数(将boardSet存在的值闯到一个数组里面),如果相邻的值相等的话,将后一个值放在前一个值的nextBoard属性里,返回合并后的数组,重新渲染页面,将boardSet初始化,valueMap初始化,遍历原来的boardSet,如果有nextBoard的话,创建一个值为当前值的二倍的方块,添加到面板里,并将值添加到valueMap里面。

init 初始化函数
功能:
1.初始化面板initBoard,
2.初始化二维数组boardSet(创建值为0的方块,在各个位置,调用createSquare),valueMap[i][j] = 0,squareSet[i][j] = null,将boardSet添加到my2048里
3.随机生成两个方块randGenerateSquare,
4.键盘事件绑定,触发move,根据e.key的不同,传给move的方向也不同,设置锁,如果当前键盘事件还未响应完,不对新的键盘事件进行相应。
initBoard 初始化面板
功能:根据设置的rows,cols,squareWidth,spacing的值计算并设置my2048的宽和高
createSquare 生成方块
根据传入的值,left,top,cols,rows创建方块,并将num,cols,rows挂在创建的temp上,并将temp返回。
randGenerateSquare 随机生成方块
1.随机生成行和列,调用randSquareNum生成方块的值(随机生成2或者4)
2.根据行,列,值生成方块,将他添加到my2048里,将他加入squareSet,值加入valueMap
randSquareNum 随机生成2或4,并返回
move 根据按键进行重新渲染
1.调用isOver,判断是否结束
2.创建一个新的newSquareSet,通过调analysisActions(direction),获取合并之后的数组
3.设置定时器,每300ms,调用refresh(newSquareSet)
4.如果isChange = true ,调用randGenerateSquare,调用结束, lock = true; isChange = false;
refresh(newSquareSet) 修改squareSet,valueMap
1.将squareSet清空,创建一个都是null的二维数组newValueMap
2.遍历newSquareSet,如果有nextSquare属性的话,重新创建值为当前值二倍的方块,并将方块渲染到my2048,将原来的方块,以及原来方块的nextSquare在my2048删除,没有nextSquare属性的话,创建一个新的方块,值为当前值,添加到squareSet,渲染到my2048,删除原来的div
3.遍历newSquareSet的时候,如果valueMap的值与squareSet的值不相同的话,isChange = true,newValueMap = squareSet的值如果某个位置元素不存在的话,newValueMap填0
4.最后将newValueMap 给 valueMap

analysisiAction 分析键盘事件触发之后,方块的新位置
1.调用generateNullMap创建一个空的新的NewSquareSet
2.根据direction的不同进行大同小异的处理,以direction = directionEnum.left为例,遍历squareSet数组,将值不为null的,push到temp
3.调用getNewLocation,并且将temp传进去,用temp接收返回值,获取到合并之后的数组
4.将temp里面的值添加到NewSquareSet
5.添加动画,使元素移动
getNewLocation(arr) 将相邻位置值相同的div添加到上一个的nextSquare属性上
1.将arr[0] 放到temp里面,for循环,i=1 -> arr.length - 1
2.判断temp[temp.length - 1]是否有nextSquare,如果没有的话,比较a[i]与temp[temp.length - 1]的值是否相等,如果相等的话,将a[i]放到temp[temp.length - 1]的nextSquare里,如果两个值不等,将他添加到temp里面
3.返回temp
==generateNullMap ==
1.创建一个值都为null的二维数组,并返回
isOver
判断squareSet[i][j]是否还有null,如果有,返回false,不结束
不满足上面的判断,接下来判断相邻的值是否相等(squareSet[i][j] 与 squareSet[i][j + 1]的值,或者squareSet[i + 1][j] 与 squareSet[i][j ]),相等则不结束
否则结束

var my2048;
var rows = 4;
var cols = 4;
var squareWidth = 100;
var spacing = 12;
var boardSet = [];
var squareSet = [];
var valueMap = [];
var colorMapping = {"0": "#ccc0b3", "2": "#eee4da", "4": "#ede0c8", "8": "#f2b179", "16": "#f59563", "32": "#f67e5f", "64": "#f65e3b", "128": "#edcf72", "256" : "#edcc61", "512": "#9c0", "1024": "#33b5e5", "2048": "#09c"};
var directionEnum = {left:{x:-1, y:0, key:"left"}, right:{x:1, y:0, key:"left"}, top:{x:0, y:-1, key:"top"}, down:{x:0, y:1, key:"top"}};
var lock = true;
var isChange = false;

function move(direction) {
    if (isOver()) {
        alert("game over ~!");
        return;
    }
    var newSquareSet = analysisActions(direction);
    //收尾(保证最终一致性)
    setTimeout(function () {
        refresh(newSquareSet);
        if (isChange) {
            randGenerateSquare();
        }
        lock = true;
        isChange = false;
    }, 300);
}

function analysisActions(direction) {
    var newSquareSet = generateNullMap();
    if (direction == directionEnum.left) {//向左
        console.log("向左");
        for (var i = 0 ; i < squareSet.length ; i ++) {
            var temp = [];
            for (var j = 0 ; j < squareSet[i].length ; j ++) {
                if (squareSet[i][j] != null) {
                    temp.push(squareSet[i][j]);
                }
            }
            temp = getNewLocation(temp);
            for (var k = 0 ; k < newSquareSet[i].length ; k ++) {
                if (temp[k]) {
                    newSquareSet[i][k] = temp[k];
                }
            }
        }
    } else if (direction == directionEnum.right) {//向右
        console.log("向右");
        for (var i = 0 ; i < squareSet.length ; i ++) {
            var temp = [];
            for (var j = squareSet[i].length - 1 ; j >= 0 ; j --) {
                if (squareSet[i][j] != null) {
                    temp.push(squareSet[i][j]);
                }
            }
            temp = getNewLocation(temp);
            for (var k = newSquareSet[i].length - 1 ; k >= 0 ; k --) {
                if (temp[newSquareSet[i].length - 1 - k]) {
                    newSquareSet[i][k] = temp[newSquareSet[i].length - 1 - k];
                }
            }
        }
    } else if (direction == directionEnum.top) {//向前
        console.log("向前");
        for (var j = 0 ; j < squareSet[0].length ; j ++) {
            var temp = [];
            for (var i = 0 ; i < squareSet.length ; i ++) {
                if (squareSet[i][j] != null) {
                    temp.push(squareSet[i][j]);
                }
            }
            temp = getNewLocation(temp);
            for (var k = 0 ; k < newSquareSet.length ; k ++) {
                if (temp[k]) {
                    newSquareSet[k][j] = temp[k];
                }
            }
        }
    } else {//向后
        console.log("向后");
        for (var j = 0 ; j < squareSet[0].length ; j ++) {
            var temp = [];
            for (var i = squareSet.length - 1 ; i >= 0 ; i --) {
                if (squareSet[i][j] != null) {
                    temp.push(squareSet[i][j]);
                }
            }
            temp = getNewLocation(temp);
            for (var k = newSquareSet.length - 1 ; k >= 0 ; k --) {
                if (temp[newSquareSet.length - 1 - k]) {
                    newSquareSet[k][j] = temp[newSquareSet.length - 1 - k];
                }
            }
        }
    }
    //动画
    for (var i = 0 ; i < newSquareSet.length ; i ++) {
        for (var j = 0 ; j < newSquareSet[i].length ; j ++) {
            if (newSquareSet[i][j] == null) {
                continue;
            }
            newSquareSet[i][j].style.transition = direction.key + " 0.3s";
            newSquareSet[i][j].style.left = (j + 1) * spacing + j * squareWidth + "px";
            newSquareSet[i][j].style.top = (i + 1) * spacing + i * squareWidth + "px";
            if(newSquareSet[i][j].nextSquare) {
                newSquareSet[i][j].nextSquare.style.transition = direction.key + " 0.3s";
                newSquareSet[i][j].nextSquare.style.left = (j + 1) * spacing + j * squareWidth + "px";
                newSquareSet[i][j].nextSquare.style.top = (i + 1) * spacing + i * squareWidth + "px";
            }
        }
    }
    return newSquareSet;
}

function getNewLocation(arr) {
    if (arr.length == 0) {
        return [];
    }
    var temp = [];
    temp.push(arr[0]);
    for (var i = 1 ; i < arr.length ; i ++) {
        if (arr[i].num == temp[temp.length - 1].num && (!temp[temp.length - 1].nextSquare || temp[temp.length - 1].nextSquare == null)) {
            temp[temp.length - 1].nextSquare = arr[i];
        } else {
            temp.push(arr[i]);
        }
    }
    return temp;
}

function generateNullMap () {
    var newValueMap = [];
    for (var i = 0 ; i < rows ; i ++) {
        newValueMap[i] = [];
        for (var j = 0 ; j < cols ; j ++) {
            newValueMap[i][j] = null;
        }
    }
    return newValueMap;
}

function isOver() {
    for (var i = 0 ; i < squareSet.length ; i ++) {
        for (var j = 0 ; j < squareSet[i].length ; j ++) {
            if (squareSet[i][j] == null) {
                return false;
            }
            if (squareSet[i][j + 1] && squareSet[i][j].num == squareSet[i][j + 1].num || squareSet[i + 1] && squareSet[i + 1][j] && squareSet[i][j].num == squareSet[i + 1][j].num){
                return false;
            }
        }
    }
    return true;
}

function refresh(newSquareSet) {//纠正位图,保证最终一致性
    squareSet = generateNullMap();
    var newValueMap = generateNullMap();
    for (var i = 0 ; i < rows ; i ++) {
        for (var j = 0 ; j < cols ; j ++) {
            //新的存在则添加
            if (newSquareSet[i][j]) {
                if (newSquareSet[i][j].nextSquare) {
                    var temp = createSquare(newSquareSet[i][j].num * 2, newSquareSet[i][j].offsetLeft, newSquareSet[i][j].offsetTop, i, j);
                    squareSet[i][j] = temp;
                    my2048.append(temp);
                    my2048.removeChild(newSquareSet[i][j].nextSquare);
                    my2048.removeChild(newSquareSet[i][j]);
                } else {
                    var temp = createSquare(newSquareSet[i][j].num, newSquareSet[i][j].offsetLeft, newSquareSet[i][j].offsetTop, i, j);
                    squareSet[i][j] = temp;
                    my2048.append(temp);
                    my2048.removeChild(newSquareSet[i][j]);
                }
                if (valueMap[i][j] != squareSet[i][j].num) {
                    isChange = true;
                }
                newValueMap[i][j] = squareSet[i][j].num;
            } else {
                newValueMap[i][j] = 0;
            }
        }
    }
    valueMap = newValueMap;
}

function randSquareNum() {
    return Math.random() >= 0.5 ? 4 : 2;
}

function randGenerateSquare() {
    for (;;) {
        var randRow = Math.floor(Math.random() * rows);
        var randCol = Math.floor(Math.random() * cols);
        if (valueMap[randRow][randCol] == 0) {
            var temp = createSquare(randSquareNum(), randCol * squareWidth + (randCol + 1) * spacing, randRow * squareWidth + (randRow + 1) * spacing, randRow, randCol);
            valueMap[temp.row][temp.col] = temp.num;
            squareSet[temp.row][temp.col] = temp;
            my2048.appendChild(temp);
            return true;
        }
    }
}

function createSquare(value, left, top, row, col) {
    var temp = document.createElement("div");
    temp.style.width = squareWidth + "px";
    temp.style.height = squareWidth + "px";
    temp.style.left = left + "px";
    temp.style.top = top + "px";
    temp.style.background = colorMapping[value];
    temp.style.lineHeight = squareWidth + "px";
    temp.style.textAlign = "center";
    temp.style.fontSize = 0.4 * squareWidth + "px";
    temp.num = value;
    temp.row = row;
    temp.col = col;
    if (value > 0) {
        temp.innerHTML = "" + value;
    }
    return temp;
}

function initBoard() {
    my2048 = document.getElementById("my2048");
    my2048.style.width = cols * squareWidth + (cols + 1) * spacing + "px";
    my2048.style.height = rows * squareWidth + (rows + 1) * spacing + "px";
}

function init() {
    //初始化棋盘
    initBoard();
    for (var i = 0 ; i < rows ; i ++){
        boardSet[i] = [];
        valueMap[i] = [];
        squareSet[i] = [];
        for (var j = 0 ; j < cols ; j ++){
            valueMap[i][j] = 0;
            squareSet[i][j] = null;
            boardSet[i][j] = createSquare(0, j * squareWidth + (j + 1) * spacing, i * squareWidth + (i + 1) * spacing, i, j);
            my2048.appendChild(boardSet[i][j]);
        }
    }
    //初始化方块
    randGenerateSquare();
    randGenerateSquare();
    //添加事件
    document.addEventListener("keydown", function(e) {
        if (!lock) return;
        lock = false;
        switch (e.key) {
            case "ArrowUp": move(directionEnum.top);break;
            case "ArrowDown": move(directionEnum.down);break;
            case "ArrowLeft": move(directionEnum.left);break;
            case "ArrowRight": move(directionEnum.right);break;
            default : {
                lock = true;
            }
        }
    })
}

window.onload = function () {
    init();
}

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <script src="index.js"></script>
    <link href="index.css" rel="stylesheet"/>
</head>
<body>
    <div id="my2048">
    </div>

</body>
</html>

css

body, div, span, a {
    margin: 0;
    padding: 0;
}

#my2048 {
    margin-left: auto;
    margin-right: auto;
    position: relative;
    background: #bbada0;
}

#my2048 div {
    position: absolute;
    display: inline-block;
    border: 0px;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值