本次作业要求 | 我罗斯作业要求 |
本次作业属于 | 2020面向对象程序设计 |
本次作业具体要求 |
|
本次作业目标 |
|
本次作业正文 | https://www.cnblogs.com/smallgrape/p/13122112.html |
小组成员 |
031902534 陈妍羽 031902541 许雅萍 |
代码仓库 | 完整代码 |
一.代码仓库
二.运行截图/运行的视频
游戏封面:
游戏开始:
游戏结束,可选择再来一局
三.代码要点
//游戏类
class Game { public: void Move();//每个玩家操作的大函数 void SetWindow();//初始界面 void GameOver(Player& player, Player& opponent);//游戏结束再来一局的函数 void GamePause();//游戏暂停 int step2(Player& player1, Player& player2);//方块生命过程的第二个步骤 };
int Game::step2(Player& player1, Player& player2)//读取按键,进行相应方块变化的函数 { int flag = 0; if (_kbhit()) { switch (_getch()) { case 'w':case 'W': player1.BlockUp(player1.OriginX); break; case 'a':case 'A': player1.BlockLeft(player1.OriginX); break; case 'd':case 'D': player1.BlockRight(player1.OriginX); break; case 's':case 'S': switch (player1.BlockDown(player1.OriginY)) { case 0: player1.check = false; break; case 1: player1.check = true; break; case 2: GameOver(player1, player2); flag = 1; //goto initial; } break; case 72: player2.BlockUp(player2.OriginX); break; case 75: player2.BlockLeft(player2.OriginX); break; case 77: player2.BlockRight(player2.OriginX); break; case 80: switch (player2.BlockDown(player2.OriginY)) { case 0: player2.check = false; break; case 1: player2.check = true; break; case 2: GameOver(player2, player1); flag = 1; //goto initial; default: break; } break; case 32: GamePause(); break; case 27: exit(0); default: break; } } return flag; }
gameover函数:
void Game::GameOver(Player& player, Player& opponent)//gameover函数,一轮游戏的结束,可以敲击空格键再来一局 { SetConsoleTextAttribute(hOut, BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY); SetPos(player.x0 + 10, 8); cout << "LOSE"; SetPos(48 - player.x0 + 10, 8); cout << "WIN"; SetConsoleTextAttribute(hOut, BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN | FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE); SetPos(38, 22); cout << "空格键重新开始"; SetPos(40, 23); cout << "Esc键退出"; char key; while (true) { key = _getch(); if (key == 32) { SetConsoleTextAttribute(hOut, BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN | FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE); player.PrintScreen(); opponent.PrintScreen(); return; } if (key == 27) { exit(0); } } }
//玩家类
//随机生成,打印,清除方块的操作函数 { void randBlock(); void printBlock(int block[4][4], int a, int b);//打印 void clearBlock(int block[4][4], int a, int b); } //对运动中的方块的四种操作 { int BlockDown(int y); void BlockLeft(int x); void BlockRight(int x); void BlockUp(int x); } //检测碰撞,消行,加行的函数 { void Eliminate_Row_Add_Row(int& val, int map2[21][12]); bool Detect_Collision(int block[4][4], int x, int y); } //被大函数调用的两个步骤函数 { bool step1(int& val, Player& opponent); int step3(); } //绘制玩家的游戏页面,初始化地图 { void setMap(); void PrintScreen();//打印窗口 }
检测碰撞
bool Player::Detect_Collision(int block[4][4], int x, int y) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (x + i >= 0 && y + j >= 0 && map[x + i][y + j] && block[i][j] == 1) { return false; } } } return true; }
增减行函数:
void Player::Eliminate_Row_Add_Row(int& val, int map2[21][12])//为玩家自己消一行,为对方增加一行 { int checking = 0;//判断是否需要消行 SetConsoleTextAttribute(hOut, BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY); int i, j, m, n, x, f, k; for (i = 19; i >= 0; i--) { x = 0; for (j = 1; j < 11; j++) { x += map[i][j]; } if (x == 10) { checking = 1; for (m = i; m > 0; m--) { for (n = 1; n < 11; n++) { map[m][n] = map[m - 1][n]; SetPos(2 * (n + x0 / 2), y0 + m); if (map[m][n] == 1) { cout << "█"; } else { cout << " "; } } } i++; } } if (checking == 1) { for (i = 0; i < 20; i++)//寻找方块镇的首行 { f = 0; for (j = 1; j < 11; j++) { if (map2[i][j] != 0) { f = 1; } if (f == 1) break; } if (f == 0)break; } int y = i; for (m = i; m < 19; m++)//地图向上平移 { for (j = 1; j < 11; j++) { map2[m][j] = map2[m + 1][j]; } } map2[19][1] = 1;//为了避免随机生成的凌乱的一行,全是方块,或全是空的 map2[19][10] = 0; for (i = 2; i < 10; i++) { k = rand() % 2; map2[19][i] = k; } for (i = y; i < 20; i++) { for (j = 1; j < 11; j++) { SetPos(2 * (j + (48 - x0) / 2), y0 + i); if (map2[i][j] == 1) { cout << "█"; } else { cout << " "; } } } } }
//实现双人游戏
网上查询到的资料,要实现两个玩家各玩各的,互不影响,要用双线程。双线程学了一些知识,也用了进去,但是有出现问题;了解到双线程,看起来是双人同时玩,但是实际上,同一个时刻其实还是只会执行其中一个玩家的代码,只不过是时间够短,“看不出来”;实际上,是错开时间执行两个玩家各自的代码,于是思考到了另外的方式,实现双人模式,就真的是两个玩家交替执行,实现还可以。
player1.setMap(); player2.setMap(); srand((unsigned)time(NULL)); player1.randBlock(); player2.randBlock(); while (true) { if (player1.step1(val, player2)) { GameOver(player1, player2); goto initial; } player1.printBlock(player1.newblock, player1.OriginX, player1.OriginY); if (player2.step1(val, player1)) { GameOver(player2, player1); goto initial; } player2.printBlock(player2.newblock, player2.OriginX, player2.OriginY); if (step2(player1, player2)) goto initial; Sleep(20); if (!(--times)) { if (player1.step3()) { GameOver(player1, player2); goto initial; } if (player2.step3()) { GameOver(player2, player1); goto initial; } times = val; } } cin.get();
双线程设计背景音乐与我罗斯游戏并行
void music() { while (1) { PlaySound(LPWSTR(IDR_WAVE2), GetModuleHandle(NULL), SND_RESOURCE | SND_LOOP); PlaySound(LPWSTR(IDR_WAVE3), GetModuleHandle(NULL), SND_RESOURCE | SND_LOOP); PlaySound(LPWSTR(IDR_WAVE4), GetModuleHandle(NULL), SND_RESOURCE | SND_LOOP); PlaySound(LPWSTR(IDR_WAVE5), GetModuleHandle(NULL), SND_RESOURCE | SND_LOOP); } } int main() { // SetConsoleTextAttribute(hOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); Game game; game.SetWindow(); initgraph(840, 560); IMAGE a; loadimage(&a, L"jpg", MAKEINTRESOURCE(IDB_BITMAP1)); putimage(0, 0, &a); _getch(); closegraph(); // thread t1(music); thread t2((&Game::Move), game); t1.join(); t2.join(); return 0; }
四.收获与心得
1、收获最大的肯定是找代码bug的能力,不得不说,最困难的事,本来以为是实现双人模式,但是实际上最困难的莫过于,修改优化代码后,出现的令人措手不及的一系列bug。最叫人难受的是,每次犯了一些搞笑的错误,比如该是玩家1的时候,写成了玩家2,导致游戏实现的乱七八糟,结果不停调试不停找,分析应该是哪里出现了错误,有时候找了几个钟头,最后猛然发现是某些惊为天人的愚蠢的错误。感觉有些时候,不知名地方的一个小错误,像是蝴蝶效应一样,会因为代码的庞大,函数之间,类之间错综复杂的关系,反映在看起来毫不相关的地方。果然,还是要努力打好基础,提升能力,才不会因为代码的越来越长,修改bug越来越吃力,费劲。
2、还有一点,要实现我罗斯,要学会了解好多东西,比如做界面的一系列函数,制作封面,设计背景音乐,时间的函数。要在短的时间,迅速掌握一些方法的使用,并不容易,尤其是网络上的信息真的太乱了,有时候开了几十个窗口,搜寻到的有效信息还是不足以实现相应的功能,要了解到有用的信息真是不容易。
3、最后一点,能实现这个游戏,在一开始知晓这个学习任务的时候,是没有料到会做成的,尤其是要实现双人模式,但是当那个夜晚,实现了双人玩耍,两只手玩着双人的俄罗斯的时候,原来我们真的可以做成,真是不可思议。后来我们还设计了一个封面,封面的图片是画出来的,还加了背景音乐,虽然,还有好多可以改进的地方,但是亲手做出来的东西,还是很喜欢的。
五.依然存在的问题
1、原设想是,我罗斯游戏的背景要设计成颜色丰富,更好看的样子,暂时还不会实现背景嵌套;
2、我罗斯的方块的下降速度,还没有设计成可以根据玩家自己的意愿更改速度,因为我们的游戏只分玩家胜负,没有限制玩一盘的时间,所以并不需要,分数,后续要改进成,即使两个玩家不分伯仲都可以保持方块不到顶,也要根据一轮游戏,有限的时间,分数的高低,来确定输赢的局面。
3、因为,使用的是检测按键的函数,再区分那个键是哪一种键,来实现方块的运动;所以当一个玩家长按某个键,另一个玩家的按键会失灵;
4、还没来得及,设计输入玩家的名字,或是直接固定玩家的名字(主要是还没想到理想的游戏玩家昵称);
5、因为双人模式就是从单人模式发展过来的,我罗斯是一个双人游戏,就没有设计单双人模式可供选择,任意切换,后期会尝试改进。