2025年纯C++版俄罗斯方块

纯C++版俄罗斯方块目录 1 概述 2 模块设计 5 设计 Block 的主要接口 6 启动游戏 7 实现游戏的主体架构 7 1 实现游戏的主体架构 7 2 补充私有数据成员 7 3 补充私有成员函数 7 4 完善游戏主体架构 9 绘制方块 10 实现游戏场景 10 1 游戏过程中数据的存储 10 2 数据数据的初始化

大家好,我是讯享网,很高兴认识大家。

目录

1. 概述

2. 模块设计

 5. 设计Block的主要接口

6. 启动游戏

7. 实现游戏的主体架构

7.1 实现游戏的主体架构

7.2 补充私有数据成员

7. 3 补充私有成员函数

7.4 完善游戏主体架构

 9. 绘制方块

10. 实现游戏场景

10.1 游戏过程中数据的存储

10.2 数据数据的初始化

10.4 测试游戏场景

11. 完善方块的渲染

11.1 新方块和预告方块的创建

11.2 渲染方块

12. 俄罗斯方块的降落

 13. 实现俄罗斯方块的左右移动



讯享网

 本教程配套视频

1. 概述

使用C++面向对象思想开发俄罗斯方块游戏。

2. 模块设计

3. 创建项目

本教程配套视频  

添加类Block和Tetris

 4. 设计Tetris的主要接口

本教程配套视频  

Tetris.h 

class Tetris { public: Tetris(int rows, int cols, int left, int top, int blockSize); void init(); void play(); };

讯享网

 

 5. 设计Block的主要接口

Block.h

讯享网#include <graphics.h> class Block { public: Block(); void drop(); void moveLeftRight(int offset); void retate(); //旋转 void draw(int leftMargin, int topMargin); };

6. 启动游戏

main.cpp

#include "Tetris.h" int main() { Tetris game(20, 10, 56, 58, 36); game.play(); return 0; }

7. 实现游戏的主体架构

7.1 实现游戏的主体架构

Tetris.cpp

讯享网void Tetris::play() { init(); int timer = 0; while (1) { keyEvent(); //待定义 timer += getDelay(); //待定义 if (timer > delay) { //delay待定义 timer = 0; drop(); //待定义 update = true; //待定义 } if (update) { update = false; updateWindow(); //待定义 clearLine(); //待定义 } } }

7.2 补充私有数据成员

Tetris.h

private: int delay; bool update;

7. 3 补充私有成员函数

Tetris.cpp

讯享网private: void keyEvent(); int getDelay(); void drop(); void updateWindow(); void clearLine();

7.4 完善游戏主体架构

游戏开始时,需要创建新方块,以及下一个方块的预告。

添加新的数据成员

Tetris.h

 Block* curBlock; Block* nextBlock; //方块预告

以上两个数据成员都是private权限,并需要补充头文件Block.h

Tetris.h

讯享网#include "Block.h"

 完善游戏主题架构

void Tetris::play() { init(); nextBlock = new Block; curBlock = nextBlock; nextBlock = new Block; // ... }

8. 创建新方块

在调用 new Block 时,会自动调用Block的默认构造函数,所以我们需要在这个构造函数里面完成新方块的创建。

俄罗斯方块的表示方法有很多,最常见的是使用一个二维数组,表示一种俄罗斯方块的某种形态,也就是说,一个俄罗斯方块,需要使用4个二维数组来表示各个形态(4个方向)。我们这里使用一个更灵巧的方式:

 

Block.h

讯享网struct Point { int row; int col; }; class Block { public: Block(); void drop(); void moveLeftRight(int offset); void retate(); //旋转 void draw(int leftMargin, int topMargin); int getBlockType(); private: int x; int y; int blockType; Point smallBlocks[4]; IMAGE* img; private: static int size; static IMAGE* imgs[7]; };

 注意,在这里,我们把所有的方块图像,定义为Block类的static数据成员.

IMAGE* Block::imgs[7] = { NULL, }; int Block::size = 36; Block::Block() { // 仅初始化一次 if (imgs[0] == NULL) { IMAGE imgTmp; loadimage(&imgTmp, "res/tiles.png"); SetWorkingImage(&imgTmp); for (int i = 0; i < 7; i++) { imgs[i] = new IMAGE; getimage(imgs[i], i * size, 0, size, size); } SetWorkingImage(); srand(time(NULL)); } // 以下,对每个新创建的方块,都要执行: blockType = 1 + rand() % 7; img = imgs[blockType - 1]; int blocks[7][4] = { 1,3,5,7, // I 2,4,5,7, // Z 1型 3,5,4,6, // Z 2型 3,5,4,7, // T 2,3,5,7, // L 3,5,7,6, // J 2,3,4,5, // 田 }; for (int i = 0; i < 4; i++) { smallBlocks[i].row = blocks[blockType - 1][i] / 2; smallBlocks[i].col = blocks[blockType - 1][i] % 2; } }

同时把项目属性的字符集,修改为多字节字符集。

 9. 绘制方块

绘制正在降落过程中的方块。

讯享网void Block::draw(int leftMargin, int topMargin) { for (int i = 0; i < 4; i++) { int x = smallBlocks[i].col * size + leftMargin; int y = smallBlocks[i].row * size + topMargin; putimage(x, y, img); } }

 

10. 实现游戏场景

10.1 游戏过程中数据的存储

添加以下数据成员,用来表示游戏的状态数据,用一个二维数组来表示各个位置的状态。

 int rows; int cols; int leftMargin; int topMargin; int blockSize; IMAGE imgBg; vector<vector<int>> map;

10.2 数据数据的初始化

在Tetris类的构造函数中,对游戏数据进行初始化。

讯享网Tetris::Tetris(int rows, int cols, int left, int top, int blockSize) { this->rows = rows; this->cols = cols; this->leftMargin = left; this->topMargin = top; this->blockSize = blockSize; for (int i = 0; i < rows; i++) { vector<int> row; for (int j = 0; j < cols; j++) { row.push_back(0); } map.push_back(row); } }

10.3 初始化游戏场景

const int SPEED_NORMAL = 500; //普通速度 const int SPEED_QUICK = 50; //快速降落速度 void Tetris::init() { initgraph(640, 832); loadimage(&imgBg, "res/bg.jpg"); delay = SPEED_NORMAL; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { map[i][j] = 0; } } }

 

10.4 测试游戏场景

已经定义很多成员函数,但是大部分都还没有做具体的实现,现在把这些成员函数都补充一个空的函数体,以便测试,后面再详细实现各个函数接口。

修改main函数,添加测试代码:

讯享网int main() { Tetris game(20, 10, 56, 58, 36); //game.play(); game.init(); Block block; block.draw(56, 58); system("pause"); return 0; }

执行效果如下:

 

11. 完善方块的渲染

11.1 新方块和预告方块的创建

在7.4中已经实现了新方块和预告方块的定义和创建。

11.2 渲染方块

在Block类中添加接口getImages, 以获取各种方块的图形纹理。

//Block.h class Block { public: static IMAGE getImages(); ...... }

  添加getImages的实现:

讯享网//Block.cpp IMAGE Block::getImages() { return imgs; }

渲染俄罗斯方块:

void Tetris::updateWindow() { BeginBatchDraw(); putimage(0, 0, &imgBg); IMAGE imgs = Block::getImages(); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { if (map[i][j] == 0) continue; int x = j * blockSize + leftMargin; int y = i * blockSize + topMargin; putimage(x, y, imgs[map[i][j] - 1]); } } curBlock->draw(leftMargin, topMargin); nextBlock->draw(689, 150); //绘制预告方块 EndBatchDraw(); }

 

12. 俄罗斯方块的降落

在Tetris类中添加数据成员,用来备份当前正在降落的俄罗斯方块,以便让俄罗斯方块进入非法位置后进行还原。

讯享网Block bakBlock;

实现俄罗斯方块的降落操作:

void Tetris::drop() { bakBlock = *curBlock; curBlock->drop(); if (!curBlock->blockInMap(map)) { bakBlock.solidify(map); delete curBlock; //curBlock = new Block; curBlock = nextBlock; nextBlock = new Block; } delay = SPEED_NORMAL; //每下将一次,就把降落速度还原成普通速度 }

补充实现Block的赋值构造函数:

讯享网Block& Block::operator=(const Block& other) { if (this == &other) return *this; this->blockType = other.blockType; for (int i = 0; i < 4; i++) { this->smallBlocks[i] = other.smallBlocks[i]; } return *this; }

 补充实现Block的固化功能:

void Block::solidify(vector<vector<int>>& map) { for (int i = 0; i < 4; i++) { // 设置标记,“固化”对应位置 map[smallBlocks[i].row][smallBlocks[i].col] = blockType; } }

测试效果:

 

 13. 实现俄罗斯方块的左右移动

在之前的按键事件处理中,实现左右移动:

讯享网void Tetris::keyEvent() { int dx = 0; bool rotateFlag = false; unsigned char ch = 0; while (_kbhit()) { unsigned char ch = _getch(); if (ch == 224) { ch = _getch(); switch (ch) { case 72: rotateFlag = true; break; case 80: delay = SPEED_QUICK; //快速降落 break; case 75: dx = -1; break; case 77: dx = 1; break; default: break; } } } if (dx != 0) { moveLeftRight(dx); update = true; } if (rotateFlag) { //rotate(); //update = true; } }

添加内部成员函数moveLeftRight:

void Tetris::moveLeftRight(int offset) { bakBlock = *curBlock; curBlock->moveLeftRight(offset); if (!curBlock->blockInMap(map)) { *curBlock = bakBlock; } }

实现Block类的moveLeftRight

讯享网void Block::moveLeftRight(int offset) { for (int i = 0; i < 4; i++) { smallBlocks[i].col += offset; } }

 测试效果:

 14. 实现旋转变形(待更新)


 

今天的分享就到这里了,大家要好好学C语言/C++哟~

欢迎转行和学习编程的伙伴,利用更多的资料学习成长比自己琢磨更快哦!
对于准备学习C/C++编程的小伙伴,如果你想更好的提升你的编程核心能力(内功)不妨从现在开始!
整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程)加下方群获取哦~
C语言C++编程学习交流圈子,:【点击进入】
C语言从入门到精通(C语言入门C语言教程C语言零基础C语言基础C语言学习C




 

 

小讯
上一篇 2025-04-11 15:51
下一篇 2025-01-04 22:52

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/18786.html