如何使用Javascript创建水果狂热游戏

95 阅读4分钟

使用Javascript创建水果狂热游戏

在这个教学练习中,你将学习如何制作一个以水果为主题的经典街机游戏(水果忍者)的版本。主要目的是看看你对javaScript的专业程度能有多大的创造性。

前提条件

在我们开始制作游戏本身之前,我们应该了解一些将用于实现我们项目目标的方法。

这些方法包括。

  • addEventListener()
  • setAttribute()
  • setTimeout()
  • setInterval()
  • createElement()
  • appendChild()
  • every()
  • includes()

水果狂热游戏

首先,创建三个文件,即。

  1. index.html
  2. style.css
  3. app.js

index.html

我们的目标是用这个文件创建一个scoreboard ,它将记录我们的进度,同时也是一个网格,我们所有的糖果将被放置在这里。

在你的html 文件中,粘贴如下所示的代码。

<div class="score-board">
  <h3>score</h3>
  <h1 id="score"></h1>
</div>
<div class="grid"></div>

style.css

由于主要目的是了解游戏的逻辑,我们不会花太多时间在样式设计上。

我们将只有一些基本的样式,你可以根据你的愿望添加更多的样式。

移除令人厌恶的默认边距和填充,如下面的例子所示。

* {
  margin: 0;
  padding: 0;
}

对于正文,我们要确保内容公平地分散在可用的区域内,因此我们将对正文进行如下样式设计。

body {
  display: flex;
  justify-content: space-evenly;
  align-items: center;
  font-family: "Trebuchet MS", "Lucida Sans Unicode", "Lucida Grande",
    "Lucida Sans", Arial, sans-serif;
}

我们将能够在这个grid 盒子里储存我们的糖果。我们将有以下的样式来使它更吸引人。

.grid {
  margin-top: 34px;
  height: 560px;
  width: 560px;
  display: flex;
  flex-wrap: wrap;
}

.grid div {
  height: 70px;
  width: 70px;
}

app.js

首先,我们有一个名为DOMContentLoaded 的事件监听器作为我们模板设置的一部分,这只是在屏幕上显示HTML元素时检查我们的脚本文件是否被加载。

document.addEventListener("DOMContentLoaded", () => {});

这个事件监听器将是我们所有的javascript代码的容器。

下一步是设计一个宽为8 英寸的板子,为我们提供70 小格子,这将是储存糖果的理想选择。

为此,建立一个名为'createBoard()'的函数,它看起来就像下面所示。

// create Board
let createBoard = () => {
  for (let i = 0; i < width * width; i++) {
    const square = document.createElement("div");
    square.setAttribute("draggable", true);
    square.setAttribute("id", i);
    let randomColor = Math.floor(Math.random() * candyColors.length);
    square.style.backgroundImage = candyColors[randomColor];
    grid.appendChild(square);
    squares.push(square);
  }
};

createBoard();

它还将使小格子可以拖动,并为它们分配随机的颜色,以及这个函数的其他功能。

我们定义了四个变量来拖动糖果以及替换它们。

  1. let colorBeingDragged.
  2. let colorBeingReplaced.
  3. let squareIdBeingDragged.
  4. let squareIdBeindReplaced.

我们采用了事件监听器来协助我们完成这项任务,每个事件都与一个函数相关联,例如,一个方法dragOver()与事件dragover, ,以此类推。

检查一下下面的代码。

//drag the candies
    let colorBeingDragged;
    let colorBeingReplaced;
    let squareIdBeingDragged;
    let squareIdBeindReplaced;
    squares.forEach(square => square.addEventListener('dragstart', dragstart))
    squares.forEach(square => square.addEventListener('dragEnd', dragEnd))
    squares.forEach(square => square.addEventListener('dragOver', dragOver))
    squares.forEach(square => square.addEventListener('dragEnter', dragEnter))
    squares.forEach(square => square.addEventListener('dragLeave', dragLeave))
    squares.forEach(square => square.addEventListener('dragDrop', dragDrop))


    function dragstart() {
        colorBeingDragged = this.style.backgroundImage;
        squareIdBeingDragged = parseInt(this.id);
        console.log(colorBeingDragged);
        console.log(this.id, 'dragstart');
    }

    function dragOver(e) {
        e.preventDefault();
        console.log(this.id, 'dragover');
    }

    function dragEnter(e) {
        e.preventDefault();
        console.log(this.id, 'dragenter');
    }

    function dragLeave() {
        console.log(this.id, 'dragleave');
    }

    function dragDrop() {
        console.log(this.id, 'dragdrop');
        colorBeingReplaced = this.style.backgroundImage;
        squareIdBeindReplaced = parseInt(this.id);
        this.style.backgroundImage = colorBeingDragged;
        squares[squareIdBeingDragged].style.backgroundImage = colorBeingReplaced;
    }

    function dragEnd()

由于我们现在能够拖动糖果,现在是时候进入游戏中更耐人寻味的方面了:确定一个动作是否有效。

结果将是一个额外的函数来验证糖果在某一列或某一行是否匹配,这取决于它们是如何分组的。在匹配的情况下有可能获得分数。

function dragEnd() {
  console.log(this.id, "dragend");
  //what is a valid move
  let validMoves = [
    squareIdBeingDragged - 1,
    squareIdBeingDragged - width,
    squareIdBeingDragged + 1,
    squareIdBeingDragged + width,
  ];

  let validMove = validMoves.includes(squareIdBeindReplaced);
  if (squareIdBeindReplaced && validMove) {
    squareIdBeindReplaced = null;
  } else if (squareIdBeindReplaced && !validMove) {
    squares[squareIdBeindReplaced].style.backgroundImage = colorBeingReplaced;
    squares[squareIdBeingDragged].style.backgroundImage = colorBeingDragged;
  } else {
    squares[squareIdBeingDragged].style.backgroundImage = colorBeingDragged;
  }
}

现在我们已经确定了一个有效的动作,我们可以亲切地搜索一个匹配,在这种情况下,我们将找到一个匹配的数字3 糖果。

如果你愿意,你可以搜索任何你想要的数字的匹配。当找到匹配的时候,分数就会被更新,并且会产生一批新的糖果。

 const checkRowForThree = () => {
        for (i = 0; 1 < 61; i++) {
            let rowOfThree = [i, i + 1, i + 2];
            let decidedColor = squares[i].style.backgroundImage;
            const isBlank = squares[i].style.backgroundImage === '';
            const notValid = [6, 7, 14, 15, 22, 23, 30, 31, 38, 39, 46, 47, 54, 55];
            if (notValid.includes(i)) continue;
            if (rowOfThree.every(index => squares[index].style.backgroundImage === decidedColor && !isBlank)) {
                score += 3;
                scoreDisplay.innerHTML = score;
                rowOfThree.forEach(index => {
                    squares[index].style.backgroundImage = '';
                })
            }
        }
    }
    checkRowForThree();

    const checkColumnForThree = () => {
        for (i = 0; 1 < 47; i++) {
            let columnOfThree = [i, i + width, i + width * 2];
            let decidedColor = squares[i].style.backgroundImage;
            const isBlank = squares[i].style.backgroundImage === '';
            if (columnOfThree.every(index => squares[index].style.backgroundImage === decidedColor && !isBlank)) {
                score += 3;
                scoreDisplay.innerHTML = score;
                columnOfThree.forEach(index => {
                    squares[index].style.backgroundImage = '';
                })
            }
        }
    }
    checkColumnForThree();

    function moveDown() {
        for (i = 0; i < 55; i++) {
            if (squares[i + width].style.backgroundImage === '') {
                squares[i + width].style.backgroundImage = squares[i].style.backgroundImage;
                squares[i].style.backgroundImage = '';
                const firstRow = [0, 1, 2, 3, 4, 5, 6, 7];
                let isFirstRow = firstRow.includes(i);
                if (isFirstRow && squares[1].style.backgroundImage === '') {
                    let randomColor = Math.floor(Math.random() * candyColors.length);
                    squares[1].style.backgroundImage = candyColors[randomColor];
                }
            }
        }

以下是源代码的完整参考。

HTML文件。

<div class="score-board">
  <h3>score</h3>
  <h1 id="score"></h1>
</div>
<div class="grid"></div>

样式表。

* {
  margin: 0;
  padding: 0;
}

body {
  display: flex;
  justify-content: space-evenly;
  align-items: center;
  font-family: "Trebuchet MS", "Lucida Sans Unicode", "Lucida Grande",
    "Lucida Sans", Arial, sans-serif;
}

.grid {
  margin-top: 34px;
  height: 560px;
  width: 560px;
  display: flex;
  flex-wrap: wrap;
}

.grid div {
  height: 70px;
  width: 70px;
}

JavaScript文件。

document.addEventListener("DOMContentLoaded", () => {
  const grid = document.querySelector(".grid");
  const width = 8;
  const squares = [];
  let scoreDisplay = document.getElementById("score");
  let score = 0;
  const candyColors = ["red", "yellow", "orange", "purple", "green", "blue"];

  // create Board
  let createBoard = () => {
    for (let i = 0; i < width * width; i++) {
      const square = document.createElement("div");
      square.setAttribute("draggable", true);
      square.setAttribute("id", i);
      let randomColor = Math.floor(Math.random() * candyColors.length);
      square.style.backgroundImage = candyColors[randomColor];
      grid.appendChild(square);
      squares.push(square);
    }
  };

  createBoard();
  //drag the candies
  let colorBeingDragged;
  let colorBeingReplaced;
  let squareIdBeingDragged;
  let squareIdBeindReplaced;
  squares.forEach((square) => square.addEventListener("dragstart", dragstart));
  squares.forEach((square) => square.addEventListener("dragEnd", dragEnd));
  squares.forEach((square) => square.addEventListener("dragOver", dragOver));
  squares.forEach((square) => square.addEventListener("dragEnter", dragEnter));
  squares.forEach((square) => square.addEventListener("dragLeave", dragLeave));
  squares.forEach((square) => square.addEventListener("dragDrop", dragDrop));

  function dragstart() {
    colorBeingDragged = this.style.backgroundImage;
    squareIdBeingDragged = parseInt(this.id);
    console.log(colorBeingDragged);
    console.log(this.id, "dragstart");
  }

  function dragOver(e) {
    e.preventDefault();
    console.log(this.id, "dragover");
  }

  function dragEnter(e) {
    e.preventDefault();
    console.log(this.id, "dragenter");
  }

  function dragLeave() {
    console.log(this.id, "dragleave");
  }

  function dragDrop() {
    console.log(this.id, "dragdrop");
    colorBeingReplaced = this.style.backgroundImage;
    squareIdBeindReplaced = parseInt(this.id);
    this.style.backgroundImage = colorBeingDragged;
    squares[squareIdBeingDragged].style.backgroundImage = colorBeingReplaced;
  }

  function dragEnd() {
    console.log(this.id, "dragend");
    //what is a valid move
    let validMoves = [
      squareIdBeingDragged - 1,
      squareIdBeingDragged - width,
      squareIdBeingDragged + 1,
      squareIdBeingDragged + width,
    ];

    let validMove = validMoves.includes(squareIdBeindReplaced);
    if (squareIdBeindReplaced && validMove) {
      squareIdBeindReplaced = null;
    } else if (squareIdBeindReplaced && !validMove) {
      squares[squareIdBeindReplaced].style.backgroundImage = colorBeingReplaced;
      squares[squareIdBeingDragged].style.backgroundImage = colorBeingDragged;
    } else {
      squares[squareIdBeingDragged].style.backgroundImage = colorBeingDragged;
    }
  }

  const checkRowForThree = () => {
    for (i = 0; 1 < 61; i++) {
      let rowOfThree = [i, i + 1, i + 2];
      let decidedColor = squares[i].style.backgroundImage;
      const isBlank = squares[i].style.backgroundImage === "";
      const notValid = [6, 7, 14, 15, 22, 23, 30, 31, 38, 39, 46, 47, 54, 55];
      if (notValid.includes(i)) continue;
      if (
        rowOfThree.every(
          (index) =>
            squares[index].style.backgroundImage === decidedColor && !isBlank
        )
      ) {
        score += 3;
        scoreDisplay.innerHTML = score;
        rowOfThree.forEach((index) => {
          squares[index].style.backgroundImage = "";
        });
      }
    }
  };
  checkRowForThree();

  const checkColumnForThree = () => {
    for (i = 0; 1 < 47; i++) {
      let columnOfThree = [i, i + width, i + width * 2];
      let decidedColor = squares[i].style.backgroundImage;
      const isBlank = squares[i].style.backgroundImage === "";
      if (
        columnOfThree.every(
          (index) =>
            squares[index].style.backgroundImage === decidedColor && !isBlank
        )
      ) {
        score += 3;
        scoreDisplay.innerHTML = score;
        columnOfThree.forEach((index) => {
          squares[index].style.backgroundImage = "";
        });
      }
    }
  };
  checkColumnForThree();

  function moveDown() {
    for (i = 0; i < 55; i++) {
      if (squares[i + width].style.backgroundImage === "") {
        squares[i + width].style.backgroundImage =
          squares[i].style.backgroundImage;
        squares[i].style.backgroundImage = "";
        const firstRow = [0, 1, 2, 3, 4, 5, 6, 7];
        let isFirstRow = firstRow.includes(i);
        if (isFirstRow && squares[1].style.backgroundImage === "") {
          let randomColor = Math.floor(Math.random() * candyColors.length);
          squares[1].style.backgroundImage = candyColors[randomColor];
        }
      }
    }
  }

  window.setInterval(() => {
    moveDown();
    checkRowForThree();
    checkColumnForThree();
  }, 100);
});

输出。

fruit-mania-game

结论

通过所提供的知识,你现在明白了如何设置HTML元素的属性,如何创建HTML元素,如何使用计时器,以及最重要的是,如何使用javascript进行游戏开发。

还有其他的方法来创建本帖所讨论的游戏,这只是一种直接的方法。你可以尝试不同的方法,使其更加吸引人。为了更多的练习,你可以用javascript开发一个俄罗斯方块游戏。