C++ 实现俄罗斯方块游戏
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。
🍎个人主页:Java Fans的博客
🍊个人信条:不迁怒,不贰过。小知识,大智慧。
💞当前专栏:Java案例分享专栏
✨特色专栏:国学周更-心性养成之路
🥭本文内容:C++ 实现俄罗斯方块游戏
文章目录
- 一、引言
- 1. 俄罗斯方块的魅力
- 2. 游戏的教育意义
- 3. 项目的目标
- 二、游戏设计
- 1. 游戏界面
- 2. 砖块设计
- 3. 游戏逻辑
- 4. 控制方式
- 5. 用户体验
- 6. 代码结构
- 三、实现过程
- 1. 环境设置
- 2. 创建项目结构
- 3. 设计数据结构
- 4. 实现砖块生成
- 5. 实现砖块移动和旋转
- 6. 实现砖块下落和行消除
- 7. 实现行消除逻辑
- 8. 实现用户输入处理
- 9. 实现游戏主循环
- 10. 绘制游戏界面
- 11. 测试和调试
- 12. 优化和扩展
- 四、完整代码
- 五、结论
一、引言
俄罗斯方块(Tetris)是一款风靡全球的经典益智游戏,自1984年首次发布以来,便吸引了无数玩家。其简单而富有挑战性的玩法使得这款游戏成为了电子游戏历史上的里程碑。玩家通过控制不同形状的砖块(称为“Tetrominoes”),将它们放置在一个由方格组成的游戏区域中,目的是填满水平行。当一行被完全填满时,它会消失,玩家将获得积分。随着游戏的进行,砖块下落的速度逐渐加快,增加了游戏的难度和紧迫感。
在这篇博文中,我们将深入探讨如何用 C++ 编写一个简单的俄罗斯方块游戏。我们将从游戏的基本概念和设计入手,逐步实现游戏的各个功能模块,包括砖块的生成、移动、旋转、行的消除以及分数的计算。通过这个项目,您不仅可以学习到 C++ 编程的基本技巧,还能了解游戏开发的基本原理和逻辑。
1. 俄罗斯方块的魅力
俄罗斯方块的魅力在于其简单易学的规则和深邃的策略性。尽管游戏的操作非常直观,但要在快速下落的砖块中做出正确的决策,仍然需要玩家具备良好的空间想象能力和快速反应能力。随着游戏的进行,玩家需要不断调整自己的策略,以应对不断增加的难度和复杂性。
2. 游戏的教育意义
除了娱乐,俄罗斯方块还具有一定的教育意义。它可以帮助玩家提高逻辑思维能力、手眼协调能力和反应速度。许多研究表明,玩俄罗斯方块可以增强大脑的认知能力,甚至有助于缓解压力和焦虑。因此,开发这样一款游戏不仅是一个有趣的编程项目,也是一个有益于身心健康的活动。
3. 项目的目标
本项目的目标是创建一个基本的俄罗斯方块游戏,具备以下功能:
- 砖块生成:随机生成不同形状的砖块。
- 砖块控制:允许玩家通过键盘控制砖块的移动和旋转。
- 行消除:检测并消除已填满的行,并更新分数。
- 游戏结束条件:当砖块堆叠到游戏区域顶部时,游戏结束。
通过实现这些功能,您将能够掌握游戏开发的基本概念,并为进一步的学习和探索打下坚实的基础。接下来,我们将详细介绍游戏的设计和实现过程。
二、游戏设计
在设计俄罗斯方块游戏时,我们需要考虑多个方面,包括游戏界面、游戏逻辑、控制方式、以及用户体验等。
1. 游戏界面
游戏界面是玩家与游戏互动的主要场所,设计时需要确保其简洁明了,易于操作。游戏界面通常包括以下几个部分:
-
游戏区域:这是一个由方格组成的矩形区域,通常为 10 列和 20 行。砖块将在这个区域内下落和堆叠。可以使用字符或图形来表示砖块和空白区域。
-
分数显示:在游戏区域的上方或旁边,显示当前的分数。分数会随着消除的行数增加而更新。
-
下一个砖块预览:在游戏区域的一侧,可以显示下一个即将出现的砖块,以帮助玩家提前规划。
-
游戏状态信息:可以显示游戏的状态信息,例如“游戏进行中”、“游戏结束”等提示。
2. 砖块设计
俄罗斯方块中的砖块(Tetrominoes)有七种基本形状,每种形状由四个方块组成。它们分别是:
- I 形:一条直线,适合横向或纵向放置。
- O 形:一个正方形,无法旋转。
- T 形:一个“T”字形,具有多种放置方式。
- L 形:一个“L”字形,具有多种放置方式。
- J 形:一个“J”字形,具有多种放置方式。
- S 形:一个“S”字形,具有多种放置方式。
- Z 形:一个“Z”字形,具有多种放置方式。
每种砖块的生成是随机的,玩家在游戏中需要根据当前砖块的形状和位置,灵活调整放置策略。
3. 游戏逻辑
游戏逻辑是游戏的核心部分,主要包括以下几个方面:
-
砖块生成:在游戏开始时和每次消除行后,随机生成一个新的砖块,并将其放置在游戏区域的顶部中心位置。
-
砖块移动:玩家可以通过键盘控制砖块的左右移动和下落。需要检测砖块是否与其他砖块或边界发生碰撞,以确保砖块不会超出游戏区域或重叠。
-
砖块旋转:玩家可以通过键盘旋转砖块。旋转时需要检查砖块的新位置是否有效,避免与其他砖块或边界发生碰撞。
-
行消除:每当砖块下落后,需要检查游戏区域的每一行,判断是否被完全填满。如果一行被填满,则将其消除,并将上方的砖块下移。
-
游戏结束条件:当新的砖块生成时,如果其初始位置与已堆叠的砖块重叠,则游戏结束。
4. 控制方式
为了增强游戏的可玩性,控制方式需要简单直观。通常使用以下键盘控制:
- 左箭头:向左移动当前砖块。
- 右箭头:向右移动当前砖块。
- 下箭头:加速砖块下落。
- 上箭头:旋转当前砖块。
这些控制方式可以通过捕获键盘事件来实现,确保玩家能够快速反应并做出决策。
5. 用户体验
用户体验是游戏设计中不可忽视的一部分。为了提升玩家的体验,可以考虑以下几点:
-
音效和音乐:为游戏添加背景音乐和音效,可以增强游戏的氛围。例如,消除行时的音效和游戏结束时的提示音。
-
视觉效果:使用不同颜色或图案来区分不同形状的砖块,使游戏更加生动有趣。
-
难度调整:可以设计多个难度级别,随着玩家的进步,逐渐增加砖块下落的速度和复杂性。
-
暂停和重启功能:允许玩家在游戏中暂停,或在游戏结束后选择重新开始。
6. 代码结构
在实现游戏时,合理的代码结构可以提高可读性和可维护性。可以将代码分为多个模块,例如:
- 主程序模块:负责游戏的主循环和初始化。
- 游戏逻辑模块:处理砖块的生成、移动、旋转和行消除等逻辑。
- 界面模块:负责绘制游戏界面和更新显示。
- 输入模块:处理键盘输入和用户交互。
通过这样的设计,代码将更加清晰,便于后续的扩展和维护。
三、实现过程
在实现俄罗斯方块游戏的过程中,我们将按照以下步骤进行,确保每个功能模块都能顺利集成。整个过程将涵盖从环境设置到代码实现的各个方面。
1. 环境设置
首先,确保您有一个适合开发 C++ 的环境。推荐使用以下工具:
- 编译器:如 GCC、Clang 或 Microsoft Visual C++。
- IDE:如 Visual Studio、Code::Blocks、CLion 或任何您熟悉的文本编辑器(如 VSCode、Sublime Text)。
- 控制台:由于我们将使用控制台进行游戏显示,确保您的开发环境支持控制台应用程序。
2. 创建项目结构
在您的开发环境中创建一个新的 C++ 项目,并设置基本的文件结构。可以考虑以下文件:
main.cpp
:主程序文件,包含游戏的入口和主循环。Tetris.h
和Tetris.cpp
:游戏逻辑的头文件和实现文件,包含砖块生成、移动、旋转等功能。InputHandler.h
和InputHandler.cpp
:处理用户输入的模块。Renderer.h
和Renderer.cpp
:负责绘制游戏界面的模块。
3. 设计数据结构
在 Tetris.h
中定义必要的数据结构。我们需要一个表示砖块的结构体和一个表示游戏区域的类。
// Point 结构体表示砖块的坐标
struct Point {int x, y;
};// Tetris 类表示游戏逻辑
class Tetris {
public:Tetris();void run();// 其他成员函数...private:vector<vector<char>> board; // 游戏区域vector<Point> currentBlock; // 当前砖块int score; // 当前分数bool gameOver; // 游戏状态// 其他成员变量...
};
4. 实现砖块生成
在 Tetris.cpp
中实现砖块生成逻辑。可以使用随机数生成器来选择砖块的形状,并将其坐标存储在 currentBlock
中。
vector<Point> Tetris::generateBlock() {vector<Point> block;int shape = rand() % 7; // 生成 0 到 6 之间的随机数switch (shape) {case 0: // I 形block = {{4, 0}, {4, 1}, {4, 2}, {4, 3}};break;case 1: // O 形block = {{4, 0}, {5, 0}, {4, 1}, {5, 1}};break;// 其他形状...}return block;
}
5. 实现砖块移动和旋转
在 Tetris.cpp
中实现砖块的移动和旋转逻辑。需要检查砖块的新位置是否有效,避免与其他砖块或边界发生碰撞。
void Tetris::move(int dx) {for (const auto& p : currentBlock) {if (p.x + dx < 0 || p.x + dx >= WIDTH || board[p.y][p.x + dx] != EMPTY) {return; // 碰撞检测}}for (auto& p : currentBlock) {p.x += dx; // 移动砖块}
}void Tetris::rotate() {// 简单的旋转逻辑for (auto& p : currentBlock) {int temp = p.x;p.x = p.y;p.y = -temp + 3; // 调整旋转中心}
}
6. 实现砖块下落和行消除
实现砖块的下落逻辑,并在每次下落后检查是否有行被填满。
void Tetris::drop() {for (const auto& p : currentBlock) {if (p.y + 1 >= HEIGHT || board[p.y + 1][p.x] != EMPTY) {placeBlock(); // 放置砖块return;}}for (auto& p : currentBlock) {p.y++; // 下落砖块}
}void Tetris::placeBlock() {for (const auto& p : currentBlock) {board[p.y][p.x] = BLOCK; // 更新游戏区域}clearLines(); // 检查并消除行currentBlock = generateBlock(); // 生成新砖块
}
7. 实现行消除逻辑
在 Tetris.cpp
中实现行消除的逻辑,检查每一行是否被填满,并更新分数。
void Tetris::clearLines() {for (int y = HEIGHT - 1; y >= 0; y--) {bool fullLine = true;for (int x = 0; x < WIDTH; x++) {if (board[y][x] == EMPTY) {fullLine = false;break;}}if (fullLine) {board.erase(board.begin() + y); // 删除满行board.insert(board.begin(), vector<char>(WIDTH, EMPTY)); // 在顶部插入空行score += 100; // 增加分数}}
}
8. 实现用户输入处理
在 InputHandler.cpp
中实现用户输入的处理逻辑,捕获键盘事件并调用相应的控制函数。
void Tetris::input() {if (_kbhit()) {switch (_getch()) {case 'a': move(-1); break; // 左移case 'd': move(1); break; // 右移case 's': drop(); break; // 加速下落case 'w': rotate(); break; // 旋转}}
}
9. 实现游戏主循环
在 main.cpp
中实现游戏的主循环,负责初始化游戏、调用绘制和逻辑更新函数。
int main() {srand(static_cast<unsigned>(time(0))); // 随机数种子Tetris game;game.run(); // 启动游戏return 0;
}
10. 绘制游戏界面
在 Renderer.cpp
中实现绘制游戏界面的逻辑,使用字符在控制台中显示游戏区域和分数。
void Tetris::draw() {system("cls"); // 清屏for (int y = 0; y < HEIGHT; y++) {for (int x = 0; x < WIDTH; x++) {if (isBlockAt(x, y)) {cout << BLOCK; // 绘制砖块} else {cout << board[y][x]; // 绘制空白}}cout << endl;}cout << "Score: " << score << endl; // 显示分数
}
11. 测试和调试
在完成代码实现后,进行全面的测试和调试。确保所有功能正常工作,包括砖块的生成、移动、旋转、行消除和游戏结束条件。可以通过添加调试信息来帮助识别潜在问题。
12. 优化和扩展
在基本功能实现后,可以考虑优化代码和扩展功能。例如:
- 增加不同难度级别:根据玩家的表现调整砖块下落速度。
- 添加音效和背景音乐:提升游戏的沉浸感。
- 实现暂停和重启功能:增强用户体验。
- 保存高分记录:记录玩家的最高分数。
四、完整代码
以下是一个简单的 C++ 俄罗斯方块游戏的实现代码。你可以将其复制到你的 C++ 开发环境中进行编译和运行。
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <conio.h> // For _kbhit() and _getch()using namespace std;const int WIDTH = 10;
const int HEIGHT = 20;
const char EMPTY = ' ';
const char BLOCK = '#';struct Point {int x, y;
};class Tetris {
public:Tetris() {board.resize(HEIGHT, vector<char>(WIDTH, EMPTY));currentBlock = generateBlock();score = 0;gameOver = false;}void run() {while (!gameOver) {draw();input();logic();}cout << "Game Over! Your score: " << score << endl;}private:vector<vector<char>> board;vector<Point> currentBlock;int score;bool gameOver;vector<Point> generateBlock() {// Generate a random block shapevector<Point> block;int shape = rand() % 7;switch (shape) {case 0: // Iblock = {{4, 0}, {4, 1}, {4, 2}, {4, 3}};break;case 1: // Oblock = {{4, 0}, {5, 0}, {4, 1}, {5, 1}};break;case 2: // Tblock = {{4, 0}, {3, 1}, {4, 1}, {5, 1}};break;case 3: // Lblock = {{4, 0}, {4, 1}, {4, 2}, {5, 2}};break;case 4: // Jblock = {{4, 0}, {4, 1}, {4, 2}, {3, 2}};break;case 5: // Sblock = {{4, 1}, {5, 1}, {3, 0}, {4, 0}};break;case 6: // Zblock = {{4, 0}, {5, 0}, {3, 1}, {4, 1}};break;}return block;}void draw() {system("cls"); // Clear the consolefor (int y = 0; y < HEIGHT; y++) {for (int x = 0; x < WIDTH; x++) {if (isBlockAt(x, y)) {cout << BLOCK;} else {cout << board[y][x];}}cout << endl;}cout << "Score: " << score << endl;}bool isBlockAt(int x, int y) {for (const auto& p : currentBlock) {if (p.x == x && p.y == y) {return true;}}return false;}void input() {if (_kbhit()) {switch (_getch()) {case 'a': move(-1); break; // Move leftcase 'd': move(1); break; // Move rightcase 's': drop(); break; // Drop blockcase 'w': rotate(); break; // Rotate block}}}void move(int dx) {for (auto& p : currentBlock) {if (p.x + dx < 0 || p.x + dx >= WIDTH || board[p.y][p.x + dx] != EMPTY) {return; // Collision detected}}for (auto& p : currentBlock) {p.x += dx;}}void drop() {for (auto& p : currentBlock) {if (p.y + 1 >= HEIGHT || board[p.y + 1][p.x] != EMPTY) {placeBlock();return;}}for (auto& p : currentBlock) {p.y++;}}void rotate() {// Simple rotation logic (not perfect)for (auto& p : currentBlock) {int temp = p.x;p.x = p.y;p.y = -temp + 3; // Adjust rotation center}}void placeBlock() {for (const auto& p : currentBlock) {if (p.y < 0) {gameOver = true; // Game over if block is placed above the board}board[p.y][p.x] = BLOCK;}clearLines();currentBlock = generateBlock();}void clearLines() {for (int y = HEIGHT - 1; y >= 0; y--) {bool fullLine = true;for (int x = 0; x < WIDTH; x++) {if (board[y][x] == EMPTY) {fullLine = false;break;}}if (fullLine) {board.erase(board.begin() + y);board.insert(board.begin(), vector<char>(WIDTH, EMPTY));score += 100; // Increase score}}}
};int main() {srand(static_cast<unsigned>(time(0))); // Seed random number generatorTetris game;game.run();return 0;
}
代码说明:
- 数据结构:使用
Point
结构体表示砖块的坐标,使用二维向量board
表示游戏区域。 - 砖块生成:
generateBlock
函数随机生成砖块的形状。 - 游戏循环:
run
函数包含游戏的主循环,负责绘制界面、处理输入和更新逻辑。 - 输入处理:使用
_kbhit()
和_getch()
函数处理键盘输入。 - 砖块移动和旋转:实现了砖块的移动、下落和旋转逻辑。
- 行消除:
clearLines
函数检查并消除已填满的行。
五、结论
本文展示了如何使用 C++ 实现一个简单的俄罗斯方块游戏。虽然这个实现相对基础,但它提供了一个良好的起点,您可以在此基础上添加更多功能,例如计时器、不同难度级别、音效等。希望您能在这个项目中获得乐趣,并进一步探索游戏开发的世界!
码文不易,本篇文章就介绍到这里,如果想要学习更多Java系列知识,点击关注博主,博主带你零基础学习Java知识。与此同时,对于日常生活有困扰的朋友,欢迎阅读我的第四栏目:《国学周更—心性养成之路》,学习技术的同时,我们也注重了心性的养成。
相关文章:

C++ 实现俄罗斯方块游戏
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...

QT打包Macosx应用发布App Store简易流程
1、QC里编译工程,生成Release版的的app文件; 2、运行macdeployqt把需要的文件打包进app文件中; % ~/Qt/5.15.0/clang_64/bin/macdeployqt {编译的app文件所在路径}/Release/xxxx.app 3、使用codesign对app进行签名,如果要发App…...

untiy mlagents 飞机大战 ai训练
前言 之前那个python源码的飞机大战bug过多,还卡顿,难以继续训练。可直接放弃的话又不甘心,所以找了个unity版本的飞机大战继续(终于不卡了),这次直接使用现成的mlagents库。 过程 前前后后花了两周时间,甚至因此拖…...

从0开始学统计-什么是中心极限定理
引言 中心极限定理(Central Limit Theorem, CLT)是统计学中的一块基石,它揭示了一个难以置信的数学现象:无论一个随机变量的原始分布如何,只要我们取足够大的样本量,这些样本的平均值(或总和&a…...

工具方法 - 个人活动的分类
人类活动的分类是一个复杂的话题,因为人类的活动范围非常广泛且相互交叉。然而,我们可以尝试将人类的活动大致分为以下几个主要类别: 工作活动 工作活动是人类生活中不可或缺的一部分,通常包括以下方面: 1. 职业工作&a…...

11.1组会汇报-基于区块链的安全多方计算研究现状与展望
基础知识 *1.背书,这个词源来自银行票据业务,是指票据转让时,原持有人在票据背面加盖自己的印鉴,证明该票据真实有效、如果有问题就可以找原持有人。 区块链中的背书就好理解了。可以简单的理解为验证交易并声明此交易合法&…...

ubuntu【桌面】 配置NAT模式固定IP
DHCP分配导致虚拟机IP老变,SSH老要重新配置,设成静态方便些 一、设NAT模式 1、设为NAT模式 2、看模式对应的虚拟网卡 - VMnet8 3、共享主机网卡网络到虚拟网卡 - VMnet8 二、为虚拟网卡设置静态IP 记住这个IP 三、设置ubuntu固定IP 1、关闭DHCP并…...

评估 机器学习 回归模型 的性能和准确度
回归 是一种常用的预测模型,用于预测一个连续因变量和一个或多个自变量之间的关系。 那么,最后评估 回归模型 的性能和准确度非常重要,可以帮助我们判断模型是否有效并进行改进。 接下来,和大家分享如何评估 回归模型 的性能和准…...

如何下载安装TestLink?
一、下载TestLink、XAMPP TestLink 下载 |SourceForge.net 备用:GitHub - TestLinkOpenSourceTRMS/testlink-code: TestLink开源测试和需求管理系统 下载XAMPP: Download XAMPP 注意:TestLink与PHP版本有关系,所以XA…...

基于SSM+微信小程序的订餐管理系统(点餐2)
👉文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 基于SSM微信小程序的订餐管理系统实现了管理员和用户。管理端实现了 首页、个人中心、用户管理、菜品分类管理、菜品信息管理、订单信息管理、配送信息管理、菜品评价管理、订单投诉管理、…...

【C++排序 双指针】1996. 游戏中弱角色的数量|1996
本文涉及的基础知识点 排序 C算法:滑动窗口及双指针总结 本题其它解法 【C单调栈 排序】1996. 游戏中弱角色的数量|1996 LeetCode1996. 游戏中弱角色的数量 你正在参加一个多角色游戏,每个角色都有两个主要属性:攻击 和 防御 。给你一个…...

GESP4级考试语法知识(捕捉异常)
参考程序代码: #include <iostream> using namespace std;double divide(double a, double b) {if (b 0) {throw "Division by zero error"; // 抛出异常}return a / b; }int main() {double num1, num2;cout << "Enter two numbers:…...

HTML 基础标签——元数据标签 <meta>
文章目录 1. `<meta>` 标签概述2. 属性详解2.1 `charset` 属性2.2 `name` 属性2.3 `content` 属性2.4 `http-equiv` 属性3. 其他常见属性小结在 HTML 文档中,元数据标签 <meta> 是一种重要的标签,用于提供关于文档的信息,这些信息不直接显示在网页内容中,但对于…...

栈虚拟机和寄存器虚拟机,有什么不同?
本来这节内容是打算直接讲字节码指令的,但讲之前又必须得先讲指令集架构,而指令集架构又分为两种,一种是基于栈的,一种是基于寄存器的。 那不妨我们这节就单独来讲讲栈虚拟机和寄存器虚拟机,它们有什么不同࿰…...

Windows下基于fping进行批量IP测试
fping是Linux下一个很好用的IP测试工具,结合代码可以完成批量的IP测试,在网络调试中用途很广。本文是基于fping for Windows结合bat批处理,定制的测试脚本样例。 一、程序信息 本次测试使用fpingV5.1 for Windows版,版本信息如下…...

一款实用的Word文档图片转换与水印保护工具
目录 前言软件功能简介软件实现方法及关键代码 1. Word 文档转图片的实现2. 图片水印添加功能3. 生成数字指纹(哈希值)4. 保存图片信息到 JSON 文件 软件的实际使用场景软件操作指南 1. 下载和安装2. 操作流程 总结 1,前言 在日常办公和内…...

优化用于传感应用的衬底集成波导技术
ANSYS HFSS 是一款功能强大的电磁仿真软件,支持为微流体生物传感器应用设计和分析衬底集成波导 (SIW) 技术。它为快速设计优化、材料选择、系统集成和虚拟原型制作提供了一个强大的平台。借助 ANSYS HFSS,研究人员和工程师可以高效…...

Java多态特性的向上转型
Java的多态特性通过向上转型来实现。向上转型指的是将子类对象赋值给父类引用变量的操作。这样做的好处是可以使用父类引用变量来调用子类对象的方法。 例如,有一个父类Animal和一个子类Dog,可以这样进行向上转型: Animal animal new Dog(…...

C++ 判断语句的深入解析
C 判断语句的深入解析 C 是一种广泛使用的编程语言,以其高效性和灵活性著称。在 C 中,判断语句是控制程序流程的关键组成部分,它们允许程序根据不同的条件执行不同的代码路径。本文将深入探讨 C 中的判断语句,包括 if、else if、…...

15分钟学 Go 第 33 天:项目结构
第33天:项目结构 目标:了解Go项目的典型结构 在Go语言的开发中,项目结构的合理性直接影响着代码的可维护性、可扩展性和团队协作效率。本篇文章将深入探讨Go语言的典型项目结构,并提供实际示例代码和相关的流程图。 一、Go项目…...

conda迁移虚拟环境路径
方法一:使用软连接 ln -s ~/Anaconda3/envs /new/path/envs 方法二:修改~/.condarc文件 1.打开~/.condarc文件 #添加下面参数 envs_dirs: - /newpath/anaconda3/envs pkgs_dirs: - /newpath/anaconda3/pkgs 2. source ~/.bashrc 3.查看是否成功con…...

(八)JavaWeb后端开发——Tomcat
目录 1.Web服务器概念 2.tomcat 1.Web服务器概念 服务器:安装了服务器软件的计算机服务器软件:接收用户的请求,处理请求,做出响应web服务器软件:在web服务器软件中,可以部署web项目,让用户通…...

yocto中通常不直接修改提供的recipes的bb文件
不直接在 Yocto 官方提供的 recipe 中修改 通常是创建新的 metadata 和 recipe 来配置相关软件编译等过程 主要有以下几个原因: 1. 便于维护和升级 隔离自定义修改:Yocto 官方的 recipe 可能会随着版本更新而变化。如果直接修改官方 recipe࿰…...

智能座舱相关术语全解及多模态交互在智能座舱中的应用
文章目录 座舱相关术语全解1. 智能座舱2. UFS3. 多模态交互4. 3D虚拟引擎5. AR/VR6. GNSS7. TTS8. DPU9. 摄像头10. 屏幕/显示器11. 音频12. 无线连接13. 其他组件 多模态交互在智能座舱中有以下一些应用 座舱相关术语全解 1. 智能座舱 智能座舱(intelligent cabi…...

【Fastjson反序列化漏洞:深入了解与防范】
一、Fastjson反序列化漏洞概述 Fastjson是一款高性能的Java语言JSON处理库,广泛应用于Web开发、数据交换等领域。然而,由于fastjson在解析JSON数据时存在安全漏洞,攻击者可以利用该漏洞执行任意代码,导致严重的安全威胁。 二、F…...

【OJ题解】C++实现反转字符串中的每个单词
💵个人主页: 起名字真南 💵个人专栏:【数据结构初阶】 【C语言】 【C】 【OJ题解】 题目要求:给定一个字符串 s ,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。 题目链接: 反转字符串中的所…...

万字长文详解Hive聚合函数 grouping sets、cube、rollup原理、语法、案例和优化
目录 原理与语法 使用场景 多维度报表生成 复杂的数据分析 实际案例 原理与语法 与GROUPINGSETS的区别 实际案例 原理与语法 与CUBE的对比 实际案例 执行效率比较 优化建议 Hive提供了三个强大的高级聚合函数: GROUPING SETS 、 CUBE 和 ROLLUP ,用于处理复杂的…...
数列分块入门
本期是数列分块入门。其中的大部分题目来自hzwer在LOJ上提供的数列分块入门系列。 Blog:here (其实是对之前分块的 blog 的整理补充) sto hzwer orz %%% [转载] ---------------------------------------------------------------------------------…...

SPRD Android 14 Launcher 3 中添加长按桌面图标启动自由窗口模式功能
本文将介绍如何在SPRD Android 14 Launcher 3 中实现一个功能,使用户可以通过长按应用图标来启动自由窗口模式。这一功能的实现将提升多任务处理能力和应用使用体验。 修改的文件列表 以下是主要涉及的文件及其修改内容: QuickstepLauncher.java:添加自由窗口快捷方式的支…...

WebSocket详解:从前端到后端的全栈理解
文章目录 前言一、WebSocket简介1.1 WebSocket的特点 二、WebSocket的工作原理2.1 握手过程2.2 数据传输 三、WebSocket在前端的应用四、WebSocket在后端的应用五、WebSocket的局限与解决方案结语 前言 随着互联网技术的发展,传统的HTTP协议在某些场景下的局限性逐…...