Skip to content

推箱子

main.js

js
/* 入口模块,用来执行其它模块,做整体模块的整合执行,例如数据监控等功能 */
import "./game.js";

map.js

js
/* 地图模块 */
export const SPACE = 0;
export const PLAYER = 1;
export const WALL = 2;
export const BOX = 3;

//地图上所有元素的坐标
export const mapPoint = [
  [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],
];
// 箱子正确的点位
export const correctPoint = [
  { 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 },
];

// 游戏界面盒子的宽高
export const gameWidth = mapPoint[0].length * 45;
export const gameHeight = mapPoint.length * 45;

game.js

js
/* game模块,用来整合整个模块,并且监听事件 */
import playerMove, { UP, DOWN, LEFT, RIGHT, isWin } from "./play.js";
import initMap from "./ui.js";
//页面添加dom元素
initMap();

// 绑定事件
let gameover = false;

window.addEventListener("keydown", function (e) {
  if (gameover) return;

  let res = false;
  if (e.key === "ArrowUp") {
    res = playerMove(UP);
  } else if (e.key === "ArrowDown") {
    res = playerMove(DOWN);
  } else if (e.key === "ArrowLeft") {
    res = playerMove(LEFT);
  } else if (e.key === "ArrowRight") {
    res = playerMove(RIGHT);
  }

  if (res) {
    initMap();
    if (isWin()) {
      gameover = true;
      console.log("游戏结束");
    }
  }
});

play.js

js
/* 操作模块,用来实现操作的逻辑 */
import * as Map from "./map.js";

//
export const UP = "up";
export const DOWN = "down";
export const LEFT = "left";
export const RIGHT = "right";

/**
 *玩家移动的函数
 * @param {*} direction    方向:up down left right
 * @returns {boolean} 是否可以移动
 */
function playerMove(direction) {
  const player = getPlayerPoint();
  const next = getNextPoint(direction, player.row, player.col);
  if (next.value === Map.WALL) {
    return false;
  } else if (next.value === Map.SPACE) {
    exchange(player, next);
    return true;
  } else if (next.value === Map.BOX) {
    const nextNext = getNextPoint(direction, next.row, next.col);
    if (nextNext.value === Map.SPACE) {
      exchange(next, nextNext);
      exchange(player, next);
      return true;
    } else {
      return false;
    }
  }
}

/**
 *
 * @param {*} direction 将移动的方向
 * @param {*} row       当前行
 * @param {*} col       当前列
 * @returns 下一个位置的坐标点信息{row:下个位置的行,col:下个位置的列,value:地图上该处的值 0|1|2|3}
 */
function getNextPoint(direction, row, col) {
  if (direction === UP) {
    return {
      row: row - 1,
      col,
      value: Map.mapPoint[row - 1][col],
    };
  } else if (direction === DOWN) {
    return {
      row: row + 1,
      col,
      value: Map.mapPoint[row + 1][col],
    };
  } else if (direction === LEFT) {
    return {
      row,
      col: col - 1,
      value: Map.mapPoint[row][col - 1],
    };
  } else if (direction === RIGHT) {
    return {
      row,
      col: col + 1,
      value: Map.mapPoint[row][col + 1],
    };
  }
}

/**
 * 获取当前玩家所在的行和列
 * @returns row:当前行,col:当前列 {row,col,value}
 */
function getPlayerPoint() {
  /* forEach中使用return只会终止当前循环,立即进入下一次循环 */
  let playerInfo = null;
  Map.mapPoint.forEach((_row, rowIndex) => {
    _row.forEach((_col, colIndex) => {
      if (_col === Map.PLAYER) {
        playerInfo = {
          row: rowIndex,
          col: colIndex,
          value: _col,
        };
      }
    });
  });
  if (playerInfo) return playerInfo;
  throw new Error("没有找到玩家");
}

/**
 * 交换地图中玩家与点位的位置
 * @param  point1 玩家当前位置信息
 * @param  point2 下一个点位信息
 */
function exchange(point1, point2) {
  [Map.mapPoint[point2.row][point2.col], Map.mapPoint[point1.row][point1.col]] =
    [
      Map.mapPoint[point1.row][point1.col],
      Map.mapPoint[point2.row][point2.col],
    ];
  // ...
}

/**判断箱子是否全部在正确的点位 */
export function isWin() {
  return Map.correctPoint.every(
    (item) => Map.mapPoint[item.row][item.col] === Map.BOX
  );
}

export default playerMove;

ui.js

js
/* UI模块,用来渲染页面 */
import * as Map from "./map.js";

//
const ogame = document.querySelector("#game");
const eleWidth = 45;
const eleHeight = 45;
/**
 *设置一个元素到#game容器中
 * @param {*} row 要新增元素的行坐标
 * @param {*} col 要新增元素的列坐标
 */
function setOneItem(row, col) {
  const div = document.createElement("div");
  div.classList.add("item");
  div.style.left = col * eleWidth + "px";
  div.style.top = row * eleHeight + "px";

  const type = Map.mapPoint[row][col];
  const isRight = isRightPoint(row, col);
  // console.log("type", type);
  if (type === Map.PLAYER) {
    div.classList.add("player");
  } else if (type === Map.WALL) {
    div.classList.add("wall");
  } else if (type === Map.BOX) {
    if (isRight) {
      div.classList.add("correct-box");
    } else {
      div.classList.add("box");
    }
  } else {
    if (isRight) {
      div.classList.add("correct");
    } else {
      return;
    }
  }

  ogame.appendChild(div);
}

/**
 * 判断是否在正确的位置
 * @param {*} row 行数
 * @param {*} col 列数
 * @returns boolean 在true  不在false
 */
function isRightPoint(row, col) {
  return (
    Map.correctPoint.find((item) => row === item.row && col === item.col) !==
    undefined
  );
}

// 设置总容器
function createContainer() {
  ogame.style.width = Map.gameWidth + "px";
  ogame.style.height = Map.gameHeight + "px";
}

//设置dom内容
function setDom() {
  ogame.innerHTML = "";

  Map.mapPoint.forEach((_rowItem, rowIndex) => {
    _rowItem.forEach((_colItem, colIndex) => {
      // console.log(rowIndex, colIndex);
      setOneItem(rowIndex, colIndex);
    });
  });
}

export default function () {
  createContainer();
  setDom();
}

MIT License