1.    简介

本次作业的内容是找一个已有的软件项目,阅读分析,找出软件尚存的缺陷, 改进其软件做二次开发。我找到了一个简单的C++俄罗斯方块小程序,并为其添加一些功能。

 原作者信息:

GitHub:https://github.com/maodeshu/c-work

2.    准备工作

首先要下载SFML多媒体库。这个程序使用的SFML版本是2.5.1 - Visual C++ 15 (2017) – 64位,再按照原文章中的步骤进行属性配置。不过,在我的电脑上,光是将bin文件夹中的所有.dll文件复制到项目的Debug文件夹中,程序仍无法运行。参照网上查找的方法将这些文件复制到C:\Windows\System32 和 C:\Windows\SysWOW64 后,程序才能正常运行。

此外,我还修改了原先的代码中的文件路径,使得后续不再需要因为上级文件夹的名称变动等事项而修改代码。

3.    功能添加

(1) 难度选择

一般来说一款游戏都会有难度选择系统,俄罗斯方块也不例外。我为程序新增了难度选择系统,分为三个等级。不同的难度有不同的收益,因此在不同难度下消除一行的得分也有所区别,分别为5分、10分和15分。

1 //各难度有不同的下降速度
 2 const float SPEED_EASY = 0.5;
 3 const float SPEED_NORMAL = 0.4;
 4 const float SPEED_HARD= 0.3;
 5 const float SPEED_QUICK = 0.05;//快速下降
 6 float CURRENT_SPEED = SPEED_NORMAL;//玩家所选难度的速度
 7 float delay = CURRENT_SPEED;
 8 //各难度得分不同
 9 const int SCORE_EASY = 5;
10 const int SCORE_NORMAL = 10;
11 const int SCORE_HARD = 15;
12 int CURRENT_SCORE = SCORE_NORMAL;

然后,在main函数中添加一个简单的难度选择界面:

1 /* 修改:添加难度选择 */
 2     int difficulty;
 3     bool flag_difficulty = false;
 4     cout << "请选择难度:\n1:简单\n2:普通\n3:困难" << endl;
 5     while (flag_difficulty == false)
 6     {
 7         cin >> difficulty;
 8         switch (difficulty)
 9         {
10         case 1:
11             CURRENT_SPEED = SPEED_EASY;
12             CURRENT_SCORE = SCORE_EASY;
13             flag_difficulty = true;
14             break;
15         case 2:
16             CURRENT_SPEED = SPEED_NORMAL;
17             CURRENT_SCORE = SCORE_NORMAL;
18             flag_difficulty = true;
19             break;
20         case 3:
21             CURRENT_SPEED = SPEED_HARD;
22             CURRENT_SCORE = SCORE_HARD;
23             flag_difficulty = true;
24             break;
25         default:
26             cout << "无效选择,请重选。" << endl;
27             break;
28         }
29     }

同时对消除时的得分进行修改:

1 if (count < COL_COUNT)
2         {
3             k--;//拿去覆盖
4         }
5         else
6         {
7             score += CURRENT_SCORE;
8             sou.play();//放消除音效
9         }

这样,就完成了一个简单的难度系统。

下方可见选择简单难度时,消除了两行共获得10分。

 

俄罗斯方块小游戏python源码 俄罗斯方块游戏小程序_i++

俄罗斯方块小游戏python源码 俄罗斯方块游戏小程序_i++_02

(2) 旋转优化

原作者使用了check()函数来判断方块在移动后是否处于游戏区域内。这一函数在方块左右平移、方块落地、和方块旋转的函数中都有被调用。而在平移和旋转(doRotate()函数)

的操作中是这样使用check()的:

1 void doRotate() {
 2     if (blockIndex == 7) {  // 田字形,不需要旋转
 3         return;
 4     }
 5     //备份当前方块,出问题再回退
 6     for (int i = 0; i < 4; i++) {
 7         bakBlock[i] = curBlock[i];  
 8     }
 9 
10     Point p = curBlock[1]; //旋转中心
11     //a[i].x=p.x-a[i].y+p.x
12     //a[i].y=p.y+a[i].x-p.x;
13     for (int i = 0; i < 4; i++)
14     {
15         struct Point tmp = curBlock[i];
16         curBlock[i].x = p.x - tmp.y + p.y;
17         curBlock[i].y = p.y + tmp.x - p.x;
18     }
19     if (!check()) {
20                 for (int i = 0; i < 4; i++) {
21             curBlock[i] = bakBlock[i];//备份
22         }
23     }
24 }

在判断到方块在位置变化后会部分离开游戏区域时,会调用此前创建的方块备份,等同于无效掉玩家试图将方块移出游戏区域的操作。

但这样的使用方式有一个缺陷:当我们在游戏区域的边缘进行方块的旋转时,对于部分摆放方式的方块会出现按下旋转按键,但方块却不旋转的情况。对于俄罗斯方块来讲,在边缘无法旋转方块无疑是降低操作性和游戏体验的。我对旋转部分调用check()的部分做了优化,引入了rotateAdjuster()函数来解决这一问题:

 

1 void rotateAdjuster() {//防止因旋转后超过边界而导致旋转不生效的问题。
 2     for (int i = 0; i < 4; i++) {
 3         if (curBlock[i].x < 0 )
 4         {
 5             for (int cx = 0; cx < 4; cx++)
 6             {
 7                 ++curBlock[cx].x;
 8             }
 9         }
10         else if (curBlock[i].x >= COL_COUNT)
11         {
12             for (int cx = 0; cx < 4; cx++)
13             {
14                 --curBlock[cx].x;
15             }
16         }
17     }
18 }

 

此外,还新增了checkLegit ()函数,将是否接触顶边或和现有方块重叠的判断拆分出来,在旋转部分单独判断,以防止不正常的旋转结果。

1 bool checkLegit() //检查是否接触顶边/重叠
 2 {
 3     for (int i = 0; i < 4; i++) {
 4         if (curBlock[i].y <= 0 || table[curBlock[i].y][curBlock[i].x])
 5         {
 6             return true;
 7         }
 8     }
 9     return false;
10 }

 

修改后的doRotate()函数:

1 void doRotate() {
 2     if (blockIndex == 7) {  // 田字形,不需要旋转
 3         return;
 4     }
 5     //备份当前方块,出问题再回退
 6     for (int i = 0; i < 4; i++) {
 7         bakBlock[i] = curBlock[i];  
 8     }
 9 
10     Point p = curBlock[1]; //旋转中心
11     //a[i].x=p.x-a[i].y+p.x
12     //a[i].y=p.y+a[i].x-p.x;
13     for (int i = 0; i < 4; i++)
14     {
15         struct Point tmp = curBlock[i];
16         curBlock[i].x = p.x - tmp.y + p.y;
17         curBlock[i].y = p.y + tmp.x - p.x;
18     }
19     if (!check()) {
20         rotateAdjuster();
21         if (checkLegit())
22         {
23             for (int i = 0; i < 4; i++) {
24                 curBlock[i] = bakBlock[i];//备份
25             }
26         }
27     }
28 }

 

修改后效果:

俄罗斯方块小游戏python源码 俄罗斯方块游戏小程序_俄罗斯方块_03

俄罗斯方块小游戏python源码 俄罗斯方块游戏小程序_俄罗斯方块小游戏python源码_04

4.    总结

以上就是我对这一开源的俄罗斯方块小程序做的二次开发。通过源代码和游玩,我找到了一个可改善事项和一个问题:

(1)游戏可以设置难度分级

(2)方块位于区域侧边时,无法旋转方块

当然,这一程序还可进行一些改进,例如为其添加下一个下落的方块的预览图。这次实践,我主要是为了探索与思考寻找软件缺陷与尝试二次开发的流程。在这一过程中,我锻炼了自己解决问题和设计功能的能力。

修改后的项目文件:https://wwqu.lanzoum.com/i8qMe0pkc4xa