c++编写消消乐游戏

2023-10-28 16:10
文章标签 c++ 编写 游戏 消消

本文主要是介绍c++编写消消乐游戏,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <time.h>
using namespace sf;#define GAME_ROWS_COUNT  8
#define GAME_COLS_COUNT  8int ts = 57;  // 每一个游戏小方块区域的大小bool isMoving = false;
bool isSwap = false;// 相邻位置的第几次单击,第2次单击才交换方块
int click = 0;Vector2i pos; //鼠标单击时的位置
Vector2i offset(15, 273);int posX1, posY1; //第一次单击的位置(记录行和列的序号)
int posX2, posY2; //第二次单击的位置(记录行和列的序号)struct Block {int x, y; //坐标值     x ==  col * ts   y == row * ts;int row, col;  //第几行,第几列int kind; //表示第几种小方块bool match; //表示是否成三int alpha; //透明度Block() {match = false;alpha = 255;kind = -1;}
} grid[GAME_ROWS_COUNT + 2][GAME_ROWS_COUNT + 2];void swap(Block p1, Block p2) {std::swap(p1.col, p2.col);std::swap(p1.row, p2.row);grid[p1.row][p1.col] = p1;grid[p2.row][p2.col] = p2;
}void doEvent(RenderWindow *window) {Event e;while (window->pollEvent(e)) {if (e.type == Event::Closed) {window->close();}if (e.type == Event::MouseButtonPressed) {if (e.key.code == Mouse::Left) {if (!isSwap && !isMoving) click++;pos = Mouse::getPosition(*window)- offset;}}}if (click == 1) {posX1 = pos.x / ts + 1;posY1 = pos.y / ts + 1;}else if (click == 2) {posX2 = pos.x / ts + 1;posY2 = pos.y / ts + 1;// 是相邻方块就交换位置if (abs(posX2 - posX1) + abs(posY2 - posY1) == 1) {// 交换相邻的两个小方块// 消消乐的方块,怎么表示?swap(grid[posY1][posX1], grid[posY2][posX2]);isSwap = 1;click = 0;}else {click = 1;}}
}void check() {for (int i = 1; i <= GAME_ROWS_COUNT; i++) {for (int j = 1; j <= GAME_COLS_COUNT; j++) {if (grid[i][j].kind == grid[i + 1][j].kind &&grid[i][j].kind == grid[i - 1][j].kind) {//grid[i - 1][j].match++;//grid[i][j].match++;//grid[i + 1][j].match++;for (int k = -1; k <= 1; k++) grid[i+k][j].match++;}if (grid[i][j].kind == grid[i][j - 1].kind &&grid[i][j].kind == grid[i][j + 1].kind) {//grid[i][j - 1].match++;//grid[i][j + 1].match++;//grid[i][j].match++;for (int k = -1; k <= 1; k++) grid[i][j + k].match++;}}}
}void doMoving() {isMoving = false;for (int i = 1; i <= GAME_ROWS_COUNT; i++) {for (int j = 1; j <= GAME_COLS_COUNT; j++) {Block& p = grid[i][j]; // 引用p, 就是grid[i][j]的别名int dx, dy;for (int k = 0; k < 4; k++) {dx = p.x - p.col * ts;dy = p.y - p.row * ts;if (dx) p.x -= dx / abs(dx);if (dy) p.y -= dy / abs(dy);}if (dx || dy) isMoving = true;}}
}void xiaochu() {for (int i = 1; i <= GAME_ROWS_COUNT; i++) {for (int j = 1; j <= GAME_COLS_COUNT; j++) {if (grid[i][j].match && grid[i][j].alpha > 10) {grid[i][j].alpha -= 10;isMoving = true;}}}
}void huanYuan() {if (isSwap && !isMoving) {// 如果此时没有产生匹配效果,就要还原int score = 0;for (int i = 1; i <= GAME_ROWS_COUNT; i++) {for (int j = 1; j <= GAME_COLS_COUNT; j++) {score += grid[i][j].match;}}if (score == 0) {swap(grid[posY1][posX1], grid[posY2][posX2]);}isSwap = false;}
}void updateGrid() {for (int i = GAME_ROWS_COUNT; i > 0; i--) {for (int j = 1; j <= GAME_COLS_COUNT; j++) {if (grid[i][j].match) {for (int k = i - 1; k > 0; k--) {if (grid[k][j].match == 0) {swap(grid[k][j], grid[i][j]);break;}}}}}for (int j = 1; j <= GAME_COLS_COUNT; j++) {int n = 0;for (int i = GAME_ROWS_COUNT; i > 0; i--) {if (grid[i][j].match) {grid[i][j].kind = rand() % 7;grid[i][j].y = -ts * n;n++;grid[i][j].match = false;grid[i][j].alpha = 255;}}}
}void drawBlocks(Sprite * sprite, RenderWindow *window) {for (int i = 1; i <= GAME_ROWS_COUNT; i++) {for (int j = 1; j <= GAME_COLS_COUNT; j++) {Block p = grid[i][j];sprite->setTextureRect(IntRect(p.kind * 52, 0, 52, 52));// 设置透明度sprite->setColor(Color(255, 255, 255, p.alpha));sprite->setPosition(p.x, p.y);// 因为数组gird中的Block, 每个Block的行标,列标是从1计算的,// 并根据行标和列表来计算的x,y坐标// 所以坐标的偏移,需要少便宜一些,也就是相当于在正方形区域的左上角的左上角方向偏移一个单位// 在这个位置开发存放第0行第0列(实际不绘制第0行第0列)sprite->move(offset.x-ts, offset.y-ts);  // to dowindow->draw(*sprite);}}
}void initGrid() {for (int i = 1; i <= GAME_ROWS_COUNT; i++) {for (int j = 1; j <= GAME_COLS_COUNT; j++) {grid[i][j].kind = rand() % 3; grid[i][j].col = j;grid[i][j].row = i;grid[i][j].x = j * ts;grid[i][j].y = i * ts;}}
}int main(void) {srand(time(0));RenderWindow window(VideoMode(485, 917), "Rock-xiaoxiaole");// 设置刷新的最大帧率window.setFramerateLimit(60);Texture t1, t2;t1.loadFromFile("images/bg2.png");if (! t2.loadFromFile("images/t4.png")) {return -1;}Sprite spriteBg(t1);Sprite spriteBlock(t2);initGrid();while (window.isOpen()) {// 处理用户的点击事件doEvent(&window);// 检查匹配情况check();// 移动处理doMoving();// 消除if (!isMoving) {xiaochu();}// 还原处理huanYuan();if (!isMoving) {updateGrid();}// 渲染游戏画面window.draw(spriteBg);// 渲染所有的小方块drawBlocks(&spriteBlock, &window);// 显示window.display();}return 0;
}

  • <SFML/Graphics.hpp>:SFML 图形模块的头文件,用于创建窗口、渲染精灵等图形相关操作。
  • <SFML/Audio.hpp>:SFML 音频模块的头文件,用于音频播放和处理。
  • <time.h>:C 语言标准库中的时间头文件,在此代码中用于生成随机数种子

这段代码需要依赖其他 SFML 库文件和资源文件才能正常编译和运行。在编译和执行之前,请确保已正确配置 SFML 开发环境并添加了必要的依赖项。

  1. swap(Block p1, Block p2): This function swaps the position of two blocks (p1 and p2) by swapping their row and column values.

  2. doEvent(RenderWindow *window): This function handles user events, such as mouse clicks and window closures. It checks for mouse button presses and updates the positions of the clicked blocks accordingly.

  3. check(): This function checks for matches in the game grid. It iterates through each block and checks if there are three identical blocks in a row or column. If a match is found, it increments the match counter for those blocks.

  4. doMoving(): This function moves the blocks to their appropriate positions after a swap or match has occurred. It checks each block's position and adjusts it if it is not aligned with its row or column. It sets the isMoving flag to true if any blocks are still moving.

  5. xiaochu(): This function handles the removal of matched blocks by decreasing their alpha value (transparency). It sets the isMoving flag to true if any blocks are still being removed.

  6. huanYuan(): This function reverts the last swap if no match occurs as a result of the swap. It checks if a swap has occurred (isSwap flag) and if all blocks have finished moving (isMoving flag).

  7. updateGrid(): This function updates the game grid by moving blocks down if there are empty spaces below them and generating new random blocks at the top. It iterates through each column from bottom to top and replaces matched blocks with new random blocks.

  8. drawBlocks(Sprite *sprite, RenderWindow *window): This function draws the blocks on the game window using the provided sprite. It iterates through each block in the game grid, sets the sprite's texture rectangle and color based on the block's properties, and then draws the sprite on the window.

  9. initGrid(): This function initializes the game grid by assigning random block types to each block and setting their initial positions.

  10. main(): The main function of the program. It initializes the window, loads textures for the background and block sprites, calls initGrid() to initialize the game grid, and enters the main game loop. Inside the game loop, it calls the various functions in the correct order to handle events, update the game state, and render the game screen.

These functions together implement the logic and rendering of a basic match-three puzzle game using C++ and SFML.

这篇关于c++编写消消乐游戏的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/294370

相关文章

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

一文详解Python如何开发游戏

《一文详解Python如何开发游戏》Python是一种非常流行的编程语言,也可以用来开发游戏模组,:本文主要介绍Python如何开发游戏的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录一、python简介二、Python 开发 2D 游戏的优劣势优势缺点三、Python 开发 3D

C++读写word文档(.docx)DuckX库的使用详解

《C++读写word文档(.docx)DuckX库的使用详解》DuckX是C++库,用于创建/编辑.docx文件,支持读取文档、添加段落/片段、编辑表格,解决中文乱码需更改编码方案,进阶功能含文本替换... 目录一、基本用法1. 读取文档3. 添加段落4. 添加片段3. 编辑表格二、进阶用法1. 文本替换2

C++中处理文本数据char与string的终极对比指南

《C++中处理文本数据char与string的终极对比指南》在C++编程中char和string是两种用于处理字符数据的类型,但它们在使用方式和功能上有显著的不同,:本文主要介绍C++中处理文本数... 目录1. 基本定义与本质2. 内存管理3. 操作与功能4. 性能特点5. 使用场景6. 相互转换核心区别

docker编写java的jar完整步骤记录

《docker编写java的jar完整步骤记录》在平常的开发工作中,我们经常需要部署项目,开发测试完成后,最关键的一步就是部署,:本文主要介绍docker编写java的jar的相关资料,文中通过代... 目录all-docker/生成Docker打包部署文件配置服务A的Dockerfile (a/Docke

C++右移运算符的一个小坑及解决

《C++右移运算符的一个小坑及解决》文章指出右移运算符处理负数时左侧补1导致死循环,与除法行为不同,强调需注意补码机制以正确统计二进制1的个数... 目录我遇到了这么一个www.chinasem.cn函数由此可以看到也很好理解总结我遇到了这么一个函数template<typename T>unsigned

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数