✨ 写在前面
上周我们实通过前端基础实现了扫雷游戏,本日照旧继承按照我们原定的节奏来领导大家完成俄罗斯方块游戏,功能也比较简朴简朴,也是想借助如许一个简朴的功能,然厥后帮助大家相识我们JavaScript在前端中的作用, 在前面的文章当中我们也提及到我们在本系列的专栏是循规蹈矩从简朴到复杂的过程,后续会领导大家用前端实现翻卡片、贪吃蛇、井字游戏、拼图、连连看扫雷等风趣的小游戏,纯前端语言实现,都会陆续带给大家。接待大家订阅我们这份前端小游戏的专栏。订阅链接:https://blog.csdn.net/jhxl_/category_12261013.html
✨ 功能先容
游戏开始时,会出现一个空的游戏区域,以及一个正在下落的方块(俄罗斯方块)。使用方向键控制方块的移动和旋转,目标是将方块填满游戏区域的水平行,使其消除。消除水平行的方式是将一整行填满方块,当一行被填满时,该行将被清除并得到得分。游戏结束条件是当方块堆叠到游戏区域的顶部时无法继承移动。(为大家尝试了一波,嗯。。。请不要讽刺我,哈哈大家可以尝试下,我在这方面实在是。。。。)

游戏区域是一个矩形,由一系列格子构成。初始状态下,游戏区域是空的。方块由四个小方块构成,可以是差别的形状,每个小方块可以向下、向左、向右移动,以及顺时针旋转。方块从游戏区域的顶部开始下落,玩家可以控制方块的移动和旋转,直到方块无法继承下落或旋转。当方块下落到游戏区域的底部或着陆在其他方块上时,它将固定在该位置,成为游戏区域的一部分。当方块固定在游戏区域中时,查抄是否有任何水平行被完全填满。假如有,这些行将被清除,并玩家将得分。游戏继承举行,新的方块会不停从顶部天生,玩家需要不停操纵方块,尽大概消除更多的水平行。游戏难度大概会渐渐增长,例如方块下落的速度加快或出现更复杂的方块形状。游戏的目标是得到尽大概高的得分,通过消除更多的行来实现。这是一个简化版的俄罗斯方块,玩家可以通过操纵方块的移动和旋转,尽大概地消除水平行并得到高分。随着游戏的举行,速度大概会渐渐增长挑衅玩家的反应和计谋能力。祝您玩得开心!
✨ 页面搭建
创建文件
起首呢我们创建我们的HTML文件,这里我就直接定名为 俄罗斯方块.html 了,大家可以随意定名, 文件创建天生后我们通过编辑器打开,这里我用的是VScode, 然后初始化我们的代码布局,那在这里告诉大家一个快捷键,就是我们敲上我们英文的一个 ! 我们敲击回车直接就会给我们天生基础版本的前端代码布局。

文档声明和编码设置: 在HTML文档的头部,使用声明HTML文档类型,确保欣赏器以精确的方式渲染网页内容。同时,设置UTF-8编码,以确保欣赏器能够精确地解析和表现中笔墨符。下面我就开始搭建我们的DOM布局了!
DOM布局搭建
下面这段 HTML 代码界说了一个俄罗斯方块游戏的根本布局。
- 俄罗斯方块
:这是一个 标题标签,用于表现游戏的标题,即“俄罗斯方块”。
- :这是一个 容器,用于包裹整个游戏区域。
- :这是一个空的 容器,它具有 id 属性为 “game-board”。这个容器将用于表现俄罗斯方块游戏的主要游戏区域。
- Score: 0:这是一个用于表现得分的 容器,它具有 id 属性为 “score”。此中包罗文本 "Score: ",以及一个 元素用于表现现实的得分值。初始得分为 0,它被包罗在具有 id 属性为 “score-value” 的 元素中。
这段 HTML 代码界说了一个根本的俄罗斯方块游戏界面,包罗游戏标题、游戏区域和得分表现。通过 JavaScript 代码的联合,将实现游戏逻辑和交互功能。
- <body>
- <h2>俄罗斯方块</h2>
-
-
- Score: <span id="score-value">0</span>
-
- </body>
复制代码
✨ 样式设置
我们看到了上面的的DOM已经搭建好了,但是页面什么都看不出来,下面我们简朴的来设置一下样式吧,其实我们本专栏也是想领导大家把握一些逻辑以是样式方面我们就齐备从简;下面这段 CSS 代码为俄罗斯方块游戏提供了样式和布局:
- [/code] 这些样式规则的含义如下:
-
- [list]
- [*]h2:设置 [size=5] 标签的字体巨细为 19 像素,居中对齐。
- [*]#tetris:设置俄罗斯方块游戏容器的宽度为 240 像素,水平居中对齐,配景致为 #d5d5d5,边框半径为 10 像素,内边距为 25 像素。
- [*]#game-board:设置游戏面板容器的宽度为 200 像素,高度为 400 像素,添加 4 像素宽度、颜色为 #4b6014 的实线边框,相对定位,边框半径为 10 像素,配景致为 #f4f126,水平居中对齐。
- [*]#score:设置分数容器的文本居中对齐,上外边距为 10 像素。
- [*].block:设置方块元素的宽度和高度为 20 像素,绝对定位,配景致为 #000,边框为 1 像素宽度、颜色为 #3a3a3a 的实线边框,使用盒模型的 “border-box” 举行盒子尺寸盘算。
- [/list] 这些样式规则使得俄罗斯方块游戏界面具有一致的外观和布局。我们看下结果;
- [img]https://img-blog.csdnimg.cn/cf2161a5a11d4ade86ff3a0e214af203.png[/img]
- [hr] [size=6]✨ 逻辑部分[/size]
- 上面我们搭建了根本的样式,下面呢我们就通过js代码,实现我们游戏的功能吧,下面是对代码的简化表明:以下是每个变量和方法的含义:
- [code]const board = document.getElementById('game-board');
- const scoreValue = document.getElementById('score-value');
- const blockSize = 20;
- const rows = 20;
- const cols = 10;
- let score = 0;
- let boardGrid = Array.from(Array(rows), () => new Array(cols).fill(0));
- let currentShape;
- let currentRow;
- let currentCol;
复制代码
- board: 表现游戏区域的 DOM 元素,用于表现方块的容器。
- scoreValue: 表现当前分数的 DOM 元素,用于更新分数表现。
- blockSize: 方块的巨细,即每个小方块的宽度和高度。
- rows: 游戏区域的行数,表现游戏区域的垂直方向上方块的数目。
- cols: 游戏区域的列数,表现游戏区域的水平方向上方块的数目。
- score: 当前的分数,表现玩家在游戏中得到的得分。
- boardGrid: 表现游戏区域的二维数组,用于记录方块的位置和状态。
- currentShape: 当前正在移动的方块的形状,以二维数组的情势表现。
- currentRow: 当前正在移动的方块的所在行数。
- currentCol: 当前正在移动的方块的所在列数。
这些变量在游戏过程中被用于存储和追踪游戏的状态和数据。例如,board 和 scoreValue 用于更新游戏界面上的分数表现;boardGrid 用于记录方块的位置和状态;currentShape 用于存储当前正在移动的方块的形状等等。通过这些变量,游戏能够及时更新和管理游戏状态,从而提供正常的游戏体验。
- <script>
- document.addEventListener('DOMContentLoaded', () => {
- function createShape() {
- const shapes = [
- [[1, 1, 1, 1]],
- [[1, 1], [1, 1]],
- [[1, 1, 0], [0, 1, 1]],
- [[0, 1, 1], [1, 1, 0]],
- [[1, 1, 1], [0, 1, 0]],
- [[1, 1, 1], [1, 0, 0]],
- [[1, 1, 1], [0, 0, 1]]
- ];
- const randomIndex = Math.floor(Math.random() * shapes.length);
- const shape = shapes[randomIndex];
- currentShape = shape;
- currentRow = 0;
- currentCol = Math.floor(cols / 2) - Math.floor(shape[0].length / 2);
- }
- function drawBoard() {
- board.innerHTML = '';
- for (let row = 0; row < rows; row++) {
- for (let col = 0; col < cols; col++) {
- if (boardGrid[row][col]) {
- const block = document.createElement('div');
- block.className = 'block';
- block.style.top = row * blockSize + 'px';
- block.style.left = col * blockSize + 'px';
- board.appendChild(block);
- }
- }
- }
- }
- function drawCurrentShape() {
- for (let row = 0; row < currentShape.length; row++) {
- for (let col = 0; col < currentShape[row].length; col++) {
- if (currentShape[row][col]) {
- const block = document.createElement('div');
- block.className = 'block';
- block.style.top = (currentRow + row) * blockSize + 'px';
- block.style.left = (currentCol + col) * blockSize + 'px';
- board.appendChild(block);
- }
- }
- }
- }
- function checkCollision() {
- for (let row = 0; row < currentShape.length; row++) {
- for (let col = 0; col < currentShape[row].length; col++) {
- if (currentShape[row][col]) {
- const newRow = currentRow + row;
- const newCol = currentCol + col;
- if (
- newRow >= rows ||
- newCol < 0 ||
- newCol >= cols ||
- boardGrid[newRow][newCol]
- ) {
- return true;
- }
- }
- }
- }
- return false;
- }
- function mergeShape() {
- for (let row = 0; row < currentShape.length; row++) {
- for (let col = 0; col < currentShape[row].length; col++) {
- if (currentShape[row][col]) {
- const newRow = currentRow + row;
- const newCol = currentCol + col;
- boardGrid[newRow][newCol] = 1;
- }
- }
- }
- }
- function clearRows() {
- for (let row = rows - 1; row >= 0; row--) {
- if (boardGrid[row].every((cell) => cell)) {
- boardGrid.splice(row, 1);
- boardGrid.unshift(new Array(cols).fill(0));
- score++;
- }
- }
- }
- function updateScore() {
- scoreValue.textContent = score;
- }
- function moveDown() {
- currentRow++;
- if (checkCollision()) {
- currentRow--;
- mergeShape();
- clearRows();
- updateScore();
- createShape();
- if (checkCollision()) {
- gameOver();
- }
- }
- }
- function moveLeft() {
- currentCol--;
- if (checkCollision()) {
- currentCol++;
- }
- }
- function moveRight() {
- currentCol++;
- if (checkCollision()) {
- currentCol--;
- }
- }
- function rotateShape() {
- const rotatedShape = currentShape[0].map((_, colIndex) =>
- currentShape.map((row) => row[colIndex]).reverse()
- );
- const prevShape = currentShape;
- currentShape = rotatedShape;
- if (checkCollision()) {
- currentShape = prevShape;
- }
- }
- function gameOver() {
- alert('Game Over');
- resetGame();
- }
- function resetGame() {
- score = 0;
- boardGrid = Array.from(Array(rows), () => new Array(cols).fill(0));
- updateScore();
- createShape();
- }
- function handleKeyPress(event) {
- switch (event.key) {
- case 'ArrowDown':
- moveDown();
- break;
- case 'ArrowLeft':
- moveLeft();
- break;
- case 'ArrowRight':
- moveRight();
- break;
- case 'ArrowUp':
- rotateShape();
- break;
- }
- drawBoard();
- drawCurrentShape();
- }
- function startGame() {
- createShape();
- setInterval(() => {
- moveDown();
- drawBoard();
- drawCurrentShape();
- }, 500);
- document.addEventListener('keydown', handleKeyPress);
- }
- startGame();
- });
- </script>
复制代码
- createShape(): 创建一个随机的俄罗斯方块形状,并将其设置为当前形状。还会初始化当前形状的行和列。
- drawBoard(): 在游戏面板上绘制当前的方块状态和已放置的方块。通过遍历游戏面板的二维数组 boardGrid,根据数组中的值来确定是否绘制方块。
- drawCurrentShape(): 在游戏面板上绘制当前的方块形状。遍历当前形状的二维数组,根据数组中的值来确定绘制方块的位置。
- checkCollision(): 查抄当前的方块是否与已放置的方块或游戏界限发生碰撞。遍历当前形状的二维数组,查抄当火线块的每个单元格是否与已放置的方块或界限发生碰撞。
- mergeShape(): 将当火线块归并到已放置方块的游戏面板中。遍历当前形状的二维数组,将当火线块的每个单元格的值设置为1,表现已放置方块。
- clearRows(): 查抄游戏面板的每一行是否已满。假如某一行已满,则将该行删除,并在顶部添加新的空行。同时,增长玩家的分数。
- updateScore(): 更新分数表现。将分数的值更新到分数元素中。
- moveDown(): 将当火线块向下移动一行。假如发生碰撞,则将当火线块归并到游戏面板中,并查抄是否有已满的行需要清除。假如当火线块无法再向下移动,则天生一个新的随机方块。
- moveLeft(): 将当火线块向左移动一列。假如发生碰撞,则取消移动操纵。
- moveRight(): 将当火线块向右移动一列。假如发生碰撞,则取消移动操纵。
- rotateShape(): 旋转当火线块的形状。通过交换二维数组的行和列来实现方块的旋转。假如旋转后发生碰撞,则取消旋转操纵。
- gameOver(): 游戏结束。表现游戏结束的提示框,并重置游戏。
- resetGame(): 重置游戏状态。将分数、游戏面板和已放置方块的二维数组重置为初始状态,然后创建一个新的随机方块。
- handleKeyPress(event): 处置处罚按键事故。根据按下的按键来调用相应的移动或旋转方法,并重新绘制游戏面板和当前形状。
- startGame(): 启动游戏。在游戏开始时,创建一个新的随机方块,并以肯定的时间隔断不停向下移动方块。同时,监听键盘按键事故。
- DOMContentLoaded 事故监听器:在 HTML 文档加载完成后实验代码。这是游戏逻辑的入口点。
以上就是这段 JavaScript 代码的主要方法和功能的表明。通过这些方法,实现了俄罗斯方块游戏的核心逻辑,包罗天生随机方块、移动方块、检测碰撞、归并方块、清除满行等。同时,它还提供了游戏的初始化、分数盘算、游戏结束和重置等功能。
完备代码
- 多少⚡️俄罗斯方块 <body>
- <h2>俄罗斯方块</h2>
-
-
- Score: <span id="score-value">0</span>
-
- </body>
- <script> document.addEventListener('DOMContentLoaded', () => { const board = document.getElementById('game-board'); const scoreValue = document.getElementById('score-value'); const blockSize = 20; const rows = 20; const cols = 10; let score = 0; let boardGrid = Array.from(Array(rows), () => new Array(cols).fill(0)); let currentShape; let currentRow; let currentCol; function createShape() { const shapes = [ [[1, 1, 1, 1]], [[1, 1], [1, 1]], [[1, 1, 0], [0, 1, 1]], [[0, 1, 1], [1, 1, 0]], [[1, 1, 1], [0, 1, 0]], [[1, 1, 1], [1, 0, 0]], [[1, 1, 1], [0, 0, 1]] ]; const randomIndex = Math.floor(Math.random() * shapes.length); const shape = shapes[randomIndex]; currentShape = shape; currentRow = 0; currentCol = Math.floor(cols / 2) - Math.floor(shape[0].length / 2); } function drawBoard() { board.innerHTML = ''; for (let row = 0; row < rows; row++) { for (let col = 0; col < cols; col++) { if (boardGrid[row][col]) { const block = document.createElement('div'); block.className = 'block'; block.style.top = row * blockSize + 'px'; block.style.left = col * blockSize + 'px'; board.appendChild(block); } } } } function drawCurrentShape() { for (let row = 0; row < currentShape.length; row++) { for (let col = 0; col < currentShape[row].length; col++) { if (currentShape[row][col]) { const block = document.createElement('div'); block.className = 'block'; block.style.top = (currentRow + row) * blockSize + 'px'; block.style.left = (currentCol + col) * blockSize + 'px'; board.appendChild(block); } } } } function checkCollision() { for (let row = 0; row < currentShape.length; row++) { for (let col = 0; col < currentShape[row].length; col++) { if (currentShape[row][col]) { const newRow = currentRow + row; const newCol = currentCol + col; if ( newRow >= rows || newCol < 0 || newCol >= cols || boardGrid[newRow][newCol] ) { return true; } } } } return false; } function mergeShape() { for (let row = 0; row < currentShape.length; row++) { for (let col = 0; col < currentShape[row].length; col++) { if (currentShape[row][col]) { const newRow = currentRow + row; const newCol = currentCol + col; boardGrid[newRow][newCol] = 1; } } } } function clearRows() { for (let row = rows - 1; row >= 0; row--) { if (boardGrid[row].every((cell) => cell)) { boardGrid.splice(row, 1); boardGrid.unshift(new Array(cols).fill(0)); score++; } } } function updateScore() { scoreValue.textContent = score; } function moveDown() { currentRow++; if (checkCollision()) { currentRow--; mergeShape(); clearRows(); updateScore(); createShape(); if (checkCollision()) { gameOver(); } } } function moveLeft() { currentCol--; if (checkCollision()) { currentCol++; } } function moveRight() { currentCol++; if (checkCollision()) { currentCol--; } } function rotateShape() { const rotatedShape = currentShape[0].map((_, colIndex) => currentShape.map((row) => row[colIndex]).reverse() ); const prevShape = currentShape; currentShape = rotatedShape; if (checkCollision()) { currentShape = prevShape; } } function gameOver() { alert('Game Over'); resetGame(); } function resetGame() { score = 0; boardGrid = Array.from(Array(rows), () => new Array(cols).fill(0)); updateScore(); createShape(); } function handleKeyPress(event) { switch (event.key) { case 'ArrowDown': moveDown(); break; case 'ArrowLeft': moveLeft(); break; case 'ArrowRight': moveRight(); break; case 'ArrowUp': rotateShape(); break; } drawBoard(); drawCurrentShape(); } function startGame() { createShape(); setInterval(() => { moveDown(); drawBoard(); drawCurrentShape(); }, 500); document.addEventListener('keydown', handleKeyPress); } startGame(); });</script>
复制代码 多少送书第六十六期 检察详情
参加方式:本博客中举行批评即可,只要批评内容不被折叠都可以参加抽奖;
抽奖方式:步调自动拉取未折叠的批评随机抽取4位搭档,每人最多可批评三次;
抽奖时间:2023-06-06 17:00
本期获奖者各送实体书《码上举措:零基础学会Python编程(ChatGPT版)》一本(包邮抵家)

✨ 原创不易,还渴望各位大佬支持一下 \textcolor{blue}{原创不易,还渴望各位大佬支持一下} 原创不易,还渴望各位大佬支持一下
点赞,你的承认是我创作的动力! \textcolor{green}{点赞,你的承认是我创作的动力!} 点赞,你的承认是我创作的动力!
⭐️ 收藏,你的青睐是我积极的方向! \textcolor{green}{收藏,你的青睐是我积极的方向!} 收藏,你的青睐是我积极的方向!
✏️ 批评,你的意见是我进步的产业! \textcolor{green}{批评,你的意见是我进步的产业!} 批评,你的意见是我进步的产业!
来源:https://blog.csdn.net/JHXL_/article/details/131030790
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |