十分钟学会用原生JS实现推箱子小游戏

742 阅读5分钟

关键词:二维数组 地图

关键点:用二维数组绘制地图

实现代码如下: 首先我们把html结构和CSS样式写好

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
    <!--给游戏容器添加相对定位的属性,方便使用坐标在容器中定位-->
    #game{
        margin: 0 auto;
        position: relative;
    }
    #game .item{   
    <!--给样类一个固定的宽高,以及绝对定位属性-->
        position: absolute;
        width: 45px;
        height: 45px;
        background-size: 100% 100%;
    }
    #game .wall{
    <!--引入游戏中的墙壁元素-->
        background-image: url("./img/wall.jpg");
    }
    #game .box{
    <!--引入游戏中的箱子元素-->
        background-image: url("./img/box.png");
    }
    #game .player{
    <!--引入游戏中的玩家属性-->
        background-image: url("./img/player.png");
    }
    /* 正确状态的箱子 */
    #game .correct-box{
        background-image: url("./img/over_box.png");
    }
    #game .correct{
    <!--游戏中规定的正确位置,即当所有的箱子都被放置在正确位置时游戏胜利✌️-->
        border:2px solid rgb(24,151,24);
        box-sizing: border-box;
    }
    </style>
</head>
<body>
    <div id="game">//即为游戏的容器
    </div>
    <script src="./js/index.js"></script>
    <script>
        
        </script>
</body>
</html>

引入JS的代码

<!--其中的关键点是二维数组;该二维数组就相当于一个地图map 然后将二维数组中的每一项特殊含义化,然后将数组中的每一项渲染到页面中,将数组可视化-->
var gameDom = document.getElementById('game')
// 在这里我们假设0代表空白,2代表墙壁,3代表箱子,1代表玩家
var size = 45;//每一块的宽高
var map = [
    [0, 0, 2, 2, 2, 2, 2, 0, 0],
    [0, 0, 2, 0, 1, 0, 2, 0, 0],
    [0, 0, 2, 0, 3, 0, 2, 0, 0],
    [2, 2, 2, 0, 0, 0, 2, 2, 2],
    [2, 0, 0, 0, 3, 0, 0, 0, 2],
    [2, 0, 3, 3, 3, 3, 3, 0, 2],
    [2, 0, 0, 0, 3, 0, 0, 0, 2],
    [2, 2, 0, 3, 3, 3, 0, 2, 2],
    [0, 2, 0, 0, 0, 0, 0, 2, 0],
    [0, 2, 0, 0, 3, 0, 0, 2, 0],
    [0, 2, 0, 0, 0, 0, 0, 2, 0],
    [0, 2, 2, 2, 2, 2, 2, 2, 0]
]
// 接下来我们自定义一个正确位置,地图中的正确位置,即为箱子最终如果都放在正确位置上 则游戏结束
var correct = [
    { row: 3, col: 4 },
    { row: 4, col: 4 },
    { row: 5, col: 2 },
    { row: 5, col: 3 },
    { row: 5, col: 4 },
    { row: 5, col: 5 },
    { row: 5, col: 6 },
    { row: 6, col: 4 },
    { row: 7, col: 4 },
    { row: 8, col: 4 },
    { row: 9, col: 4 },
    { row: 10, col: 4 }
];
<!--思路:如果我们要实现整个游戏的运转,首先我们需要找到玩家的位置,以及判断玩家要运动到的下一位置是可以交换的还是不可以交换的,规则就是墙壁不可以移动,不可以交换位置,如果推箱子的过程中目标箱子的在目标方向上下一个位置如果是箱子或者墙壁的话,是不能被移动的-->
// 接下来首先我们需要通过遍历数组map找到玩家的位置 然后可以将玩家1的位置与空白0或者与箱子3的位置进行替换
function getPlayerLoc() {
    for (var i = 0; i < map.length; i++) {
        var row = map[i];//表示map中的第i行也是一个数组,继续循环row找出每一列
        for (var j = 0; j < row.length; j++) {
            var value = map[i][j] //也即row[j],就是二维数组中的每一项
            if (value === 1) {
                // 找到了玩家的位置
                return {
                    row: i,
                    col: j
                }
            }
        }
    }
}

// 判断地图中指定的行和列是否是在正确位置
function isCorrect(row, col) {
    for (var i = 0; i < correct.length; i++) {
        var loc = correct[i];
        if (loc.row === row && loc.col === col) {
            return true //是正确位置
        }
    }
    return false //不是正确位置
}

// 渲染地图
function render() {
    // 1.清空游戏的容器;
    gameDom.innerHTML = ''
    // 2、遍历地图中的所有内容
    for (var i = 0; i < map.length; i++) {
        var row = map[i]//行
        for (var j = 0; j < row.length; j++) {
            var value = map[i][j]
            var div = document.createElement('div')
            div.className = 'item';//添加样式类
            var isRight = isCorrect(i, j);
            if (value === 0) {//空白位置包括正确的空白位置和普通的空白位置
                if (isRight) {//正确的空白位置
                    div.classList.add('correct')
                } else {
                    continue;//因为普通空白位置不需要添加任何东西
                }
            } else if (value === 1) {//将玩家添加到地图中显示
                div.classList.add('player')
            } else if (value === 2) {//将墙壁添加到地图中显示
                div.classList.add('wall')
            } else {
                if (isRight) {
                    div.classList.add('correct-box')//添加正确位置的箱子
                } else {
                    div.classList.add('box')//添加非正确位置的箱子
                }
            }
            // 设置div的坐标
            div.style.left = size * j + 'px';
            div.style.top = size * i + 'px';
            gameDom.appendChild(div)//将div添加到game容器中
        }
    }
    var rowNumber = map.length;//地图的行数
    var colNumber = map[0].length;//地图的列数
    gameDom.style.height = rowNumber * size + 'px';
    gameDom.style.width = colNumber * size + 'px';
}
render()

// 让玩家按照指定的方向,移动

function move(direction) {
    // 首先我们需要得到玩家的位置
    var palyerLoc = getPlayerLoc();
    // 再者我们需要得到玩家下一方向位置的信息 因为有些地方能走 有些地方不能走
    var nextLoc = getNextLoc(palyerLoc);
    // 通过坐标拿到地图上的值
    var value = map[nextLoc.row][nextLoc.col];
    // 接下来 我们就推动盒子走动
    if (value === 2) {
        return;//下一位置是墙壁 不能走动
    }
    else if (value === 0) {//说明前方是空白 可以走动
        // 就可以交换 palyerloc与nextloc的位置
        exchange(palyerLoc, nextLoc)
    }
    else if (value === 3) {//说明前方是箱子,此时我们需要判断箱子的下一位置是什么,当箱子的下一位置为空的时候,可以推动箱子移动,但是当箱子的下一位置是箱子或者墙壁的时候 不能推动箱子
        var nextnextloc = getNextLoc(nextLoc);
        var nextvalue = map[nextnextloc.row][nextnextloc.col];
        if (nextvalue === 0) {//箱子前方没有东西,可以移动
            // 箱子和下一位置空白互换
            exchange(nextLoc, nextnextloc)
            // 玩家和下一位置互换
            exchange(palyerLoc, nextLoc)
        } else {
            return
        }
    }
    render()
    // 获取玩家下一位置的函数
    function getNextLoc(originLoc) {
        if (direction === 'left') {
            return {
                row: originLoc.row,
                col: originLoc.col - 1
            }
        }
        else if (direction === 'right') {
            return {
                row: originLoc.row,
                col: originLoc.col + 1
            }
        }
        else if (direction === 'up') {
            return {
                row: originLoc.row - 1,
                col: originLoc.col
            }
        }
        else if (direction === 'down') {
            return {
                row: originLoc.row + 1,
                col: originLoc.col
            }
        }

    }

    // 交换位置的函数
    function exchange(loc1, loc2) {
        var temp = map[loc1.row][loc1.col];
        map[loc1.row][loc1.col] = map[loc2.row][loc2.col];
        map[loc2.row][loc2.col] = temp;
    }
}

// 加入键盘事件
window.onkeydown = function (e) {
    if (e.key === 'ArrowUp') {
        move('up')
    }
    else if (e.key === 'ArrowDown') {
        move('down')
    }
    else if (e.key === 'ArrowLeft') {
        move('left')
    }
    else if (e.key === 'ArrowRight') {
        move('right')
    }
    else if(isVictory()){
        alert(`游戏胜利✌️`)
    }

}

// 判断游戏是否胜利
function isVictory() {
    for (var i = 0; i < correct.length; i++) {
        var loc = correct[i];
        var value = map[loc.row][loc.col]
        if (value !== 3) {
            return false
        }
    }
    return true

}


若要添加游戏关卡,可以更改二维数组map中对应的值进行更改