马赛克版推箱子

292 阅读5分钟

我正在参加掘金社区游戏创意投稿大赛个人赛,详情请看:游戏创意投稿大赛

前言

推箱子的思路大致如下:

  • 初始化一个推箱子的地图数据,数据中的0,1,2,3,4分别对应(空白区域,墙,小球,箱子和小人);
  • 收集数据中对应的图片集;
  • 建一个格子棋盘用来作为渲染地图数据的容器;
  • 初始化页面时创建地图,根据地图数据指定对应图片的所在位置;
  • 编写控制小人移到的方法;
  • 编写键盘控制方向的方法,并根据方向移动小人;
  • 编写判断箱子碰撞的方法来判断是碰撞的箱子还是小球;

实现

HTML代码

<div class="game-title">Qiuの推箱子</div>
<div class="container">
     <div id="game-container"></div>
     <div class="controller">
         <div class="text">提示面板</div>
         <div id="showInfo"></div>
     </div>
</div>

CSS代码

        /*标题*/
        .game-title {
            text-align: center;
            line-height: 80px;
            font-size: 30px;
            color: #03a9f4;
            font-weight: bold;
        }

        /* 游戏整体 */
        .container {
            width: auto;
            height: auto;
            display: flex;
            flex-wrap: row nowrap;
            justify-content: center;
            align-items: center;
        }

        /* 地图容器 */
        #game-container {
            background-color: #ffeb3b;
            position: relative;
        }

        /* 方格 */
        #game-container div {
            width: 35px;
            height: 35px;
            position: absolute;
        }

        #game-container div img {
            width: 35px;
            height: 35px;
            position: absolute;
            border-radius: 6px;
        }

        #game-container div.people img {
            z-index: 2;
        }

        #game-container div.box img {
            z-index: 1;
        }

        /* 提示语 */
        .controller {
            width: 150px;
            height: 420px;
            margin-left: 20px;
            padding: 10px;
            box-sizing: border-box;
            background-color: #feffb1;

        }

        .text {
            width: 100%;
            height: 30px;
            line-height: 30px;
            margin-top: 20px;
            text-align: center;
            border: 2px solid black;
            background-color: aquamarine;
        }

        #showInfo {
            height: 320px;
            font-size: 12px;
            margin: 10px auto;
            padding: 10px;
            box-sizing: border-box;
            border: 2px solid black;
            background-color: aquamarine;
        }

渲染效果如下

image.png

JS代码

        // 节点参数
        var container = document.getElementById("game-container");
        var showInfo = document.getElementById('showInfo');//提示面板

        //地图数据(0:空白区域,1:墙,2:小球,3:箱子,4:小人)
        var mapdata = [
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0,
            0, 0, 0, 1, 0, 2, 1, 0, 0, 0, 0, 0,
            0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0,
            0, 0, 1, 1, 0, 3, 0, 3, 2, 1, 0, 0,
            0, 0, 1, 2, 3, 0, 4, 1, 1, 1, 0, 0,
            0, 0, 1, 1, 1, 1, 3, 1, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        ];

        // 横纵坐标格子数
        var globl_size = { x: 12, y: 12 };
        var message = '';

        // 初始化加载
        window.onload = function () {
            CreateMap()
        };

        // 创建地图
        var CreateMap = function () {
            // 设置容器大小
            container.style.cssText = "width:" + globl_size.x * 35 + "px;height:" + globl_size.y * 35 + "px;";

            // 将地图数据渲染到容器的每个格子
            for (var i = 0; i < globl_size.x * globl_size.y; i++) {//144
                var opeople;
                var x, y;
                switch (mapdata[i]) {
                    case 1: //墙
                        //设置(x,y)坐标
                        x = i % globl_size.x;
                        y = parseInt(i / globl_size.x);

                        // 创建格子
                        var appenddiv = document.createElement("div");
                        // 设置格子在地图中的位置
                        appenddiv.style.cssText = "left:" + x * 35 + "px;top:" + y * 35 + "px;";
                        // 设置格子参数
                        appenddiv.className = "wall";
                        appenddiv.x = x;
                        appenddiv.y = y;

                        // 这种image对象的方式 有一种预加载的功能,当你给他src的时候,就会开始加载图片
                        var wall_img = new Image();
                        // 墙的图片
                        wall_img.src = "./images/wall.png";
                        // 将图片标签追加到div格子中
                        appenddiv.appendChild(wall_img);

                        // 将div格子放到整张地图中
                        container.appendChild(appenddiv);
                        break;
                    case 2://小球
                        //设置(x,y)坐标
                        x = i % globl_size.x;
                        y = parseInt(i / globl_size.x);

                        // 创建格子
                        var appenddiv = document.createElement("div");
                        // 设置格子在地图中的位置
                        appenddiv.style.cssText = "left:" + x * 35 + "px;top:" + y * 35 + "px;";
                        // 设置格子参数
                        appenddiv.className = "ball";
                        appenddiv.x = x;
                        appenddiv.y = y;

                        var wall_img = new Image();
                        //小球图片
                        wall_img.src = "./images/ball.png";
                        // 将图片标签追加到div格子中
                        appenddiv.appendChild(wall_img);

                        // 将div格子放到整张地图中
                        container.appendChild(appenddiv);
                        break;
                    case 3://箱子
                        //设置(x,y)坐标
                        x = i % globl_size.x;
                        y = parseInt(i / globl_size.x);

                        // 创建格子
                        var appenddiv = document.createElement("div");
                        // 设置格子在地图中的位置
                        appenddiv.style.cssText = "left:" + x * 35 + "px;top:" + y * 35 + "px;";
                        // 设置格子参数
                        appenddiv.className = "box";
                        appenddiv.x = x;
                        appenddiv.y = y;

                        var wall_img = new Image();
                        //箱子图片
                        wall_img.src = "./images/box.png"
                        // 将图片标签追加到div格子中
                        appenddiv.appendChild(wall_img);

                        // 将div格子放到整张地图中
                        container.appendChild(appenddiv);
                        break;
                    case 4://小人
                        //设置(x,y)坐标
                        x = i % globl_size.x;
                        y = parseInt(i / globl_size.x);

                        // 创建格子
                        var appenddiv = document.createElement("div");
                        // 设置格子在地图中的位置
                        appenddiv.style.cssText = "left:" + x * 35 + "px;top:" + y * 35 + "px;";
                        // 设置格子参数
                        appenddiv.className = "people";
                        appenddiv.x = x;
                        appenddiv.y = y;

                        var wall_img = new Image();
                        // 小人图片
                        wall_img.src = "./images/people.png"
                        opeople = wall_img;
                        // 将图片标签追加到div格子中
                        appenddiv.appendChild(wall_img);

                        // 将div格子放到整张地图中
                        container.appendChild(appenddiv);
                        break;
                }
            }
            contralPeople(opeople);
        };

        // 键盘控制方向
        var contralPeople = function (people) {
            document.onkeydown = function (event) {
                event = event || window.event;
                var keyCode = event.keyCode;
                console.log(keyCode)
                switch (keyCode) {
                    //左
                    case 37:
                        movePeople({ x: -1 }, people);
                        break;
                    //上
                    case 38:
                        movePeople({ y: -1 }, people);
                        break;
                    // 右
                    case 39:
                        movePeople({ x: 1 }, people);
                        break;
                    // 下
                    case 40:
                        movePeople({ y: 1 }, people);
                        break;
                }
            }
        };

        // 移动小人
        var movePeople = function (position, people) {
            //先找到小人所在的div格子
            parent_div = people.parentNode;
            // 箱子
            var box = getClass(container, "box");

            x = position.x || 0;
            y = position.y || 0;
            if (mapdata[parent_div.x + x + (parent_div.y + y) * globl_size.x] != 1) {
                parent_div.x = parent_div.x + x;
                parent_div.y = parent_div.y + y;
                parent_div.style.left = parent_div.offsetLeft + x * 35 + "px";
                parent_div.style.top = parent_div.offsetTop + y * 35 + "px";

                for (var i = 0; i < box.length; i++) {
                    if (box[i].x == parent_div.x && box[i].y == parent_div.y) {
                        if (mapdata[box[i].x + x + (box[i].y + y) * globl_size.x] != 1) {
                            //检测两个箱子是否碰撞,如果碰撞,小人则弹回
                            if (!twoBoxJianCe(box[i], x, y)) {
                                box[i].x = box[i].x + x;
                                box[i].y = box[i].y + y;
                                box[i].style.left = box[i].offsetLeft + x * 35 + "px";
                                box[i].style.top = box[i].offsetTop + y * 35 + "px";
                                isOrNoSuccess();
                            } else {
                                parent_div.x = parent_div.x - x;
                                parent_div.y = parent_div.y - y;
                                parent_div.style.left = parent_div.offsetLeft - x * 35 + "px";
                                parent_div.style.top = parent_div.offsetTop - y * 35 + "px";
                            }
                        } else {
                            // 人物弹回
                            parent_div.x = parent_div.x - x;
                            parent_div.y = parent_div.y - y;
                            parent_div.style.left = parent_div.offsetLeft - x * 35 + "px";
                            parent_div.style.top = parent_div.offsetTop - y * 35 + "px";
                        }
                    }
                }
            }
        };

        // 检测两个箱子是否碰撞
        var twoBoxJianCe = function (box, x, y) {
            var obox = getClass(container, "box");
            for (var i = 0; i < obox.length; i++) {
                if (obox[i] != box) {
                    if (obox[i].x == box.x + x && obox[i].y == box.y + y) {
                        message = '箱子不能碰撞!'
                        showInfo.innerHTML = message
                        //碰撞
                        return true;
                    }
                }
            }
            //没碰撞
            return false;
        };

        //判断是否成功
        var isOrNoSuccess = function () {
            var ball = getClass(container, "ball");
            var box = getClass(container, "box");
            var successnum = 0;
            for (var i = 0; i < box.length; i++) {
                for (var j = 0; j < ball.length; j++) {
                    if (box[i].x == ball[j].x && box[i].y == ball[j].y) {
                        successnum++;
                    }
                }
            }
            if (successnum == ball.length) {
                message = '游戏通关了,太棒了!'
                showInfo.innerHTML = message
            }
        };

        // 找标签
        var getClass = function (node, classname) {
            if (node.getElementsByClassName) {
                //如果存在该标签 就返回
                return node.getElementsByClassName(classname);
            } else {
                var elems = node.getElementsByTagName(node),
                    defualt = [];
                for (var i = 0; i < elems.length; i++) {
                    //遍历所有标签
                    if (elems[i].className.indexOf(classname) != -1) {
                        //查找相应类名的标签
                        defualt[defualt.length] = elems[i];
                    }
                }
                return defualt;
            }
        };

游戏效果如下

game.gif