JavaScript 教程:使用现代 JavaScript 构建俄罗斯方块
学习一门新的编程语言并非易事,而且每个人的学习方式也不尽相同。对许多人来说,通过项目实践或互动式教程进行探索是持久学习的关键。
尤其对于像 JavaScript 这样直观的语言来说,构建项目有助于理解如何在不同的应用程序中使用基本概念及其原因。此外,它还能丰富你的简历,因为你可以向招聘人员展示一系列优秀的项目,以此证明你的积极性和开发技能。
今天,我们将帮助你入门一个 JavaScript 游戏开发项目,构建一个俄罗斯方块游戏。读完本文,你将掌握所有必要的基础知识,可以继续独立开发了。
今天我们将讨论以下内容:
用你自己的方式,在一半的时间内学习 JavaScript
在构建一个有趣且功能齐全的项目以丰富你的作品集的过程中,掌握现代 JavaScript 技能。
什么是俄罗斯方块?
俄罗斯方块是一款经典的街机游戏,由阿列克谢·帕基特诺夫于1984年创作。游戏中,玩家需要旋转并移动不断下落的方块。玩家通过消除水平方向的方块行来消除方块。如果方块到达顶部,游戏结束。
俄罗斯方块是一个热门项目,它能让有志成为游戏开发者的玩家在简单的环境中练习技能。例如,你可以亲身实践一些基本的游戏设计概念,比如游戏循环设计,以及实现常见的游戏机制,例如用户控制、分数追踪和碰撞检测。与更复杂的游戏不同,俄罗斯方块的行为和视觉效果都非常简单。这让你能够专注于运用 JavaScript 基础知识进行游戏开发,而不是费力地去研究动画或复杂的玩家行为流程图。
在这个例子中,我们将从最简单的工具开始,然后逐步增加复杂性。
要玩俄罗斯方块,你需要知道:
游戏风格
首先,我们来设置基本的用户界面元素:游戏区域、开始按钮以及用于显示分数、行数和关卡的显示屏。我们将使用Flexbox和CSS Grid来正确定位这些元素。
<!-- index.html -->
<div class="grid">
<canvas id="board" class="game-board"></canvas>
<div class="right-column">
<div>
<h1>TETRIS</h1>
<p>Score: <span id="score">0</span></p>
<p>Lines: <span id="lines">0</span></p>
<p>Level: <span id="level">0</span></p>
<canvas id="next" class="next"></canvas>
</div>
<button onclick="play()" class="play-button">Play</button>
</div>
</div>
// styles.css
.grid {
display: grid;
grid-template-columns: 320px 200px;
}
.right-column {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.game-board {
border: solid 2px;
}
.play-button {
background-color: #4caf50;
font-size: 16px;
padding: 15px 30px;
cursor: pointer;
}
80 年代游戏的一大特色就是极具辨识度的位图字体。Press start 2P是一款来自 Google 的免费字体,我们可以用它来模拟那种感觉。
要添加字体,我们需要在<head>HTML 文档的 <head> 部分链接到该字体,并在 CSS 样式表中将其设置为所需的字体。
<!--index.html-->
<link
href="https://fonts.googleapis.com/css?family=Press+Start+2P"
rel="stylesheet"
/>
// styles.css
* {
font-family: 'Press Start 2P', cursive;
}
最后,使用 JavaScript 编写游戏棋盘的基础架构。
您需要<script>在 HTML 文档末尾添加元素来导入 JavaScript 代码。
您的 HTML 文档底部应如下所示:
<script type="text/javascript" src="constants.js"></script>
<script type="text/javascript" src="board.js"></script>
<script type="text/javascript" src="piece.js"></script>
<script type="text/javascript" src="main.js"></script>
</body>
</html>
constants.js这将包含我们静态游戏面板的代码。无论玩家如何操作,这些值都不会改变。游戏面板将由 10 列和 20 行组成,每个方块的大小为 30。
//constants.js
const COLS = 10;
const ROWS = 20;
const BLOCK_SIZE = 30;
然后,main.js我们将在文件中包含一些用于操作文档的代码object,该文档为 HTML 文档提供了一个可编程接口。这种类型的文档称为文档对象模型 (DOM)。
我们可以使用 DOM 来调用 `<div>` 元素,getElementByID从而定位特定元素并自动缩放游戏以适应用户浏览器窗口的大小。这使用了canvasHTML5 新增的 `<div>` 元素,它使我们能够轻松创建和使用 2D 图形。
文件main.js内容应如下所示:
//main.js
const canvas = document.getElementById('board');
const ctx = canvas.getContext('2d');
// Calculate size of canvas from constants.
ctx.canvas.width = COLS * BLOCK_SIZE;
ctx.canvas.height = ROWS * BLOCK_SIZE;
// Scale blocks
ctx.scale(BLOCK_SIZE, BLOCK_SIZE);
最后,您将得到以下文件:
<!--index.html-->
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Press+Start+2P"
rel="stylesheet"
/>
</head>
<body>
<div class="grid">
<canvas id="board" class="game-board"></canvas>
<div class="right-column">
<div>
<h1>TETRIS</h1>
<p>Score: <span id="score">0</span></p>
<p>Lines: <span id="lines">0</span></p>
<p>Level: <span id="level">0</span></p>
<canvas id="next" class="next"></canvas>
</div>
<button onclick="play()" class="play-button">Play</button>
</div>
</div>
</body>
//main.js
const canvas = document.getElementById('board');
const ctx = canvas.getContext('2d');
// Calculate size of canvas from constants.
ctx.canvas.width = COLS * BLOCK_SIZE;
ctx.canvas.height = ROWS * BLOCK_SIZE;
// Scale blocks
ctx.scale(BLOCK_SIZE, BLOCK_SIZE);
//constants.js
const COLS = 10;
const ROWS = 20;
const BLOCK_SIZE = 30;
//styles.css
* {
font-family: 'Press Start 2P', cursive;
}
.grid {
display: grid;
grid-template-columns: 320px 200px;
}
.right-column {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.game-board {
border: solid 2px;
}
.play-button {
background-color: #4caf50;
font-size: 16px;
padding: 15px 30px;
cursor: pointer;
}
通过实践项目不断学习JS。
无需阅读书本,即可掌握热门 JavaScript 技能。Educative 的文字课程易于浏览,并提供实践项目环境,助您以更高效的方式学习,节省一半时间。
设计电路板
现在我们已经创建了游戏容器,接下来就要开始编写逻辑代码了。首先,我们需要让游戏板能够绘制下落的棋子并跟踪游戏状态。
棋盘和棋子都非常适合用类来表示。我们可以Board在开始新游戏时创建一个新的实例,Piece每次有新棋子加入游戏时也创建一个新的实例。
对于这个Board类,我们将创建一个新board.js文件。我们希望棋盘在每次游戏开始时都引用画布,因此我们将ctx在Board构造函数中包含它。我们还会包含this关键字,以便我们可以在棋盘中设置和访问属性ctx。
//board.js
class Board {
constructor(ctx) {
this.ctx = ctx;
}
}
俄罗斯方块棋盘由许多独立的格子组成,这些格子要么是空的,要么是被占据的。我们将用 表示空格子,0用整数 表示被占据的格子,并1-7用 表示颜色。
为了表示棋盘的行和列,我们将使用二维数组(矩阵)。我们将使用整数数组来表示一行,并使用行数组来表示整个棋盘。
由于所有游戏都从空棋盘开始,我们需要一个返回空棋盘的方法。我们可以使用内置的fill()数组方法来填充每一行的所有元素0。构造函数会调用这个方法,这样所有游戏都会从空棋盘开始。
我们的board.js文件现在看起来会像这样:
//board.js
class Board {
constructor(ctx) {
this.ctx = ctx;
this.grid = this.getEmptyBoard();
}
getEmptyBoard() {
return Array.from(
{length: ROWS}, () => Array(COLS).fill(0)
);
}
}
最后,我们将回到main.js游戏按钮,为其添加这项新的游戏功能。
function play() {
board = new Board(ctx);
console.table(board.grid);
}
现在我们的游戏棋盘已经设置好了!你可以用它console.table()来查看控制棋盘的矩阵。
创建画布
现在我们要确保canvas元素已准备就绪。画布为我们的游戏提供了一个空白的载体。
我们还可以在画布上添加一个二维绘图界面,用于绘制形状、文本、图像和其他对象。它的工作方式类似于 MS Paint 等程序,您可以选择画笔类型和颜色,然后使用代码进行绘制。
首先,我们要确保画布大小合适。默认情况下是 300x150 像素,但我们希望它能根据上面添加的代码进行缩放。
为此,我们canvas向其中添加一个元素index.html:
<canvas id="canvas"></canvas>
<canvas>然后使用该方法向 DOM(文档对象模型)中添加对 HTML 元素元素的引用getElementById。
let canvas = document.getElementById('canvas');
现在我们将使用 canvas 上下文来渲染一些元素。
我们可以使用该HTMLCanvasElement.getContext()方法获取用于渲染图形的画布上下文。此方法需要一个参数,因此我们将传递该参数'2d'以获取 2D 渲染上下文。
let ctx = canvas.getContext('2d');
在开始绘画之前,我们需要使用该fillStyle()方法选择颜色。
ctx.fillStyle = 'red';
然后我们可以使用fillRect()上下文 API 中的方法绘制一个简单的矩形,并填充我们选择的红色。fillRect()该方法接受 4 个参数:形状起始位置的 x 和 y 坐标,以及矩形的宽度和高度。
ctx.fillRect(x, y, width, height);
由于所有俄罗斯方块都是由正方形组成的,因此我们可以对所有方块使用这种单一的绘制方法!
动画
现在我们有了绘制图形的工具,接下来我们需要能够移动它们。
Canvas 使用即时渲染:绘制的形状会立即渲染到屏幕上,但不会存储为形状对象。Canvas 只将形状识别为填充的像素,这意味着我们无法整体移动形状。
要显示一个移动的形状,我们需要使用 `Delete` 删除旧形状clearRect(),然后使用 `Redraw` 在新位置重新绘制它fillRect()。Canvas 动画本质上类似于定格动画,因为它们在每一帧中都会移动一点点。
请看这个例子:
const {width, height} = this.ctx.canvas;
ctx.fillStyle = 'blue';
ctx.fillRect(0, 0, 10, 10);
ctx.clearRect(0, 0, width, height);
ctx.fillRect(1, 1, 10, 10);
这里,我们选择蓝色作为颜色,然后在点处填充一个矩形0,0。接着,我们使用 `clear()` 方法清除整个画布clearRect(),并传入画布的宽度和高度。最后,我们在点处绘制一个大小和颜色相同的新矩形1,1。
从用户的角度来看,矩形在屏幕上向下向右移动。
现在你的画布和绘图工具都已设置完毕,你拥有了开始编写游戏代码所需的所有工具以及一系列游戏组件!
接下来你的游戏步骤
这是你下一个作品集项目的绝佳开端。既然你已经搭建好了游戏的基础框架,下一步就是创建能够以各自独特的颜色绘制每个俄罗斯方块游戏方块的对象。
每种类型的棋子都将用一个 3x3 矩阵表示,其中棋子是填充的单元格,周围的空白空间有助于围绕中心单元格旋转。
[2, 0, 0],
[2, 2, 2],
[0, 0, 0];
最好的方法是上课Piece。
您还需要添加键盘支持,以便用户可以控制各个部件。最好的方法是使用现代浏览器内置的键盘事件支持。您可以使用该方法在文档级别设置程序监听键盘事件,例如 `Ctrl+Shift+E`、`Ctrl+Shift+ keydownE`keyup等addEventListener()。
完成以上步骤后,您将继续添加更高级的功能,例如:
- 添加碰撞检测和碎片随机化器
- 如果行已填充,则添加行清除操作。
- 追踪分数、等级和历史最高分
- 使用异步 JavaScript 提高响应速度
为了帮助大家完成这个项目并通过实践学习 JavaScript,Educative 开发了“使用 JavaScript 进行游戏开发:创建俄罗斯方块”课程。本课程将通过构建一个有趣的浏览器游戏,帮助你同时掌握 JavaScript 和游戏开发的基础技能。课程结束时,你将拥有一个功能齐全的俄罗斯方块网页游戏,并且 JavaScript 技能也将从入门到精通。
学习愉快!