加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
俄罗斯方块大作业.cpp 15.65 KB
一键复制 编辑 原始数据 按行查看 历史
不在学习 提交于 2023-01-07 14:40 . 俄罗斯方块
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675

//代码参考:https://github.com/chenlong-cxy/small-project/tree/master/Tetris
#include<stdio.h>
#include<graphics.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <conio.h>
#include <string.h>
#include<mmsystem.h>
#pragma comment(lib,"winmm.lib")
#define DOWN 80//方向键
#define RIGHT 77
#define LEFT 75
#define UP 72
#define I 20
#define SPACE 32//空格键
#define ESC 27//ESC 键
#undef UNICODE
#undef _UNICODE
struct Button {
int x;
int y;
int w;
int h;
int curColor;
int inColor;
int outColor;
char* text;
};
struct Block {
int space[4][4];
}block[7][4];
struct Flag {
int value[33][33] = { 0 };//明确二维数组与坐标轴的对应
int color[33][33] = { 0 };
}flag;
int max, grade;
int t;
//生成按钮
struct Button* createButton(int x, int y, int w, int h, const char* str, int inColor, int outColor) {
struct Button* pb = (struct Button*)malloc(sizeof(struct Button));
assert(pb);
pb->x = x;
pb->y = y;
pb->w = w;
pb->h = h;
pb->inColor = inColor;
pb->curColor = outColor;
pb->outColor = outColor;
int length = strlen(str) + 1;
pb->text = (char*)malloc(sizeof(char) * length);
assert(pb->text);
strcpy_s(pb->text, length, str);
return pb;
}
//画按钮
void DrawButton(struct Button* pb) {
setfillcolor(pb->curColor);
fillroundrect(pb->x, pb->y, pb->x + pb->w, pb->y + pb->h,30,30);
settextcolor(BLACK);
setbkmode(TRANSPARENT);
settextstyle(40, 0, "楷体");
//文字居中
int wt=textwidth(pb->text);
int ht=textheight(pb->text);
int xt =pb-> x + (pb->w - wt) / 2;
int yt = pb->y + (pb->h - ht) / 2;
outtextxy(xt, yt, pb->text);
}
//判断是否在按钮中
int inButton(struct Button* pb, ExMessage m) {
if (m.x > pb->x && m.x<(pb->x + pb->w) && m.y>pb->y && m.y < (pb->y + pb->h)) {
pb->curColor = pb->inColor;
return 1;
}
else {
pb->curColor = pb->outColor;
return 0;
}
}
//判断是否点击按钮
int clickButton(struct Button* pb, ExMessage m) {
if (inButton(pb, m) && m.message == WM_LBUTTONDOWN) {
return 1;
}
else {
return 0;
}
}
int main();
//初始化方块颜色
int color(int type) {
int c;
switch (type) {
case 0:c = RGB(169, 124, 219); break;
case 1:c = RGB(245, 192, 163); break;
case 2:c = RGB(250, 246, 158); break;
case 3:c = RGB(122, 158, 230); break;
case 4:c = RGB(127, 202, 100); break;
case 5:c = RGB(236, 172, 187); break;
case 6:c = RGB(200, 142, 102); break;
}
return c;
}
//初始化方块
void initBlock() {
block[0][0] = { 0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0 };//T
block[1][0] = { 0,0,0,0,0,1,0,0,0,1,0,0,0,1,1,0 };//L
block[2][0] = { 0,0,0,0,0,0,1,0,0,0,1,0,0,1,1,0 };//J
block[3][0] = { 0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0 };//1
block[4][0] = { 0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0 };//田
block[5][0] = { 0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0 };//z
block[6][0] = { 0,0,0,0,0,1,1,0,1,1,0,0,0,0,0,0 };//s
for (int type = 0; type < 7; type++) {
for (int form = 1; form < 4; form++) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
block[type][form].space[i][j] = block[type][form - 1].space[j][3 - i];
}
}
}
}
}
//判断是否还能继续下落
int Judgedown(int type, int form, int x, int y) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
//是否有方格为障碍物
if ((block[type][form].space[i][j] == 1) && (flag.value[y / 20 + i][x / 20 + j]) == 1)//横纵坐标区分开
return 0;
}
}
return 1;
}
//画方块
void Drawblock(int type, int form, int x, int y) {
settextcolor(color(type));
settextstyle(20, 0, _T("楷体"));
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (block[type][form].space[i][j] == 1) {
outtextxy(x + 20 * j, y + i * 20, _T("■"));
}
}
}
}
//清除方块
void Clearblock(int type, int form, int x, int y) {
settextstyle(20, 0, _T("楷体"));
settextcolor(BLACK);
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (block[type][form].space[i][j] == 1) {
outtextxy(x + 20 * j, y + i * 20, _T("■"));
}
}
}
}
//读取最高分
void ReadGrade()
{
FILE* pf;
errno_t err = fopen_s(&pf, "俄罗斯方块最高得分记录.txt", " r"); //以只读方式打开文件
if (pf == NULL) //打开文件失败
{
err = fopen_s(&pf, "俄罗斯方块最高得分记录.txt", "w"); //以只写方式打开文件(文件不存在可以自动创建该文件)
fwrite(&grade, sizeof(int), 1, pf); //将max写入文件(此时max为0),即将最高历史得分初始化为0
}
fseek(pf, 0, SEEK_SET); //使文件指针pf指向文件开头
fread(&max, sizeof(int), 1, pf); //读取文件中的最高历史得分到max当中
fclose(pf); //关闭文件
pf = NULL; //文件指针及时置空
}
//更新最高分到文件
void Breakgrade()
{
FILE* pf;
errno_t err = fopen_s(&pf, "俄罗斯方块最高得分记录.txt", "w"); //以只写方式打开文件
if (pf == NULL) {//打开文件失败
printf("保存最高得分记录失败\n");
exit(0);
}
fwrite(&grade, sizeof(int), 1, pf); //将本局游戏得分写入文件当中(更新最高历史得分)
fclose(pf); //关闭文件
pf = NULL; //文件指针及时置空
}
//更新当前得分到视图
void Refreshscore(int grade) {
settextcolor(BLACK);
settextstyle(40, 0, _T("楷体"));
outtextxy(530, 530, _T("■"));
settextstyle(20, 0, _T("楷体"));
char str[32];
sprintf_s(str, 32, "%d", grade);
settextcolor(WHITE);
outtextxy(540, 530, str);
}
//是否重开
void Overchoice() {
HWND hwnd = GetHWnd();
SetWindowText(hwnd, _T("俄罗斯方块"));
int isyes = MessageBox(hwnd, _T("是否重新开始游戏"), _T("俄罗斯方块"), MB_YESNO);
if (isyes = IDYES) {
for (int i = 0; i < 33; i++) {
for (int j = 0; j < 33; j++) {
flag.value[i][j] = 0;
}
}
main();
}
else {
exit(0);
}
}
void clearlines(int line) {
for (int k = 1; k < 21; k++) {//把消除的一行的信息全部消除
flag.value[line][k] = 0;
settextcolor(BLACK);
outtextxy(k * 20, line * 20, _T("■"));
}
for (int m = line; m > 1; m--) {//全体下移
for (int n = 1; n < 21; n++) {
flag.value[m][n] = flag.value[m - 1][n];
flag.color[m][n] = flag.color[m - 1][n];
if (flag.value[m][n] == 1)
{
settextcolor(color(flag.color[m][n])); //颜色设置为还方块的颜色
outtextxy(n * 20, m * 20, _T("■"));
}
else //上一行移下来的是空格,打印空格
{
settextcolor(BLACK);
outtextxy(n * 20, m * 20, _T("■"));
}
}
}
Sleep(450);
}
//加入消行音乐
void BGM2() {
mciSendString(_T("open xiaohang.mp3 alias BGM2"), 0, 0, 0);
mciSendString(_T("play BGM2"), 0, 0, 0);
Sleep(250);
}
//判断是否消行并且得分
void Gradejudge() {
for (int i = 31; i > 4; i--)//统计得分
{
int sum = 0; //记录第i行的方块个数
for (int j = 1; j < 21; j++) {
sum += flag.value[i][j]; //统计第i行的方块个数
}
if (sum == 0)//统计到了没有方块的行,可跳出循环
break;
if (sum == 20) { //行满加分
BGM2();
grade += 1;
Refreshscore(grade);//刷新当前分数
clearlines(i);
i++;
mciSendString(_T("close BGM2"), 0, 0, 0);
}
}
}
//判断游戏是否结束
void Gameover() {
for (int j = 1; j < 21; j++)//判断游戏是否结束
{
if (flag.value[2][j] == 1) //顶层有方块存在(以第1行为顶层,不是第0行)
{
Sleep(1000); //留给玩家反应时间
cleardevice(); //清空屏幕
settextcolor(WHITE); //颜色设置为白色
settextstyle(40, 0, _T("楷体"));
if (grade > max) {
Breakgrade();
IMAGE image;
loadimage(&image, _T("./高.jpg"), 660, 660);
putimage(0, 0, &image);
}
else if (grade == max) {
IMAGE image;
loadimage(&image, _T("./平.jpg"), 660, 660);
putimage(0, 0, &image);
}
else {
IMAGE image;
loadimage(&image, _T("./低.jpg"), 660, 660);
putimage(0, 0, &image);
}
Sleep(1000);
Overchoice();
}
}
}
//游戏进行函数
void Gameing() {
int type = rand() % 7;
int form = rand() % 4;
//首方块循环界面
while (1)
{
int nexttype = rand() % 7;
int nextform = rand() % 4;
Drawblock(nexttype, nextform, 500, 80);//画出下一方块
int x = 180, y = 20;
while (1)
{
int T = t;
Drawblock(type, form, x, y);
while (1)
{
T--;
if (T == 0) {
break;
}
if (_kbhit() != 0)
{
char ch = _getch();
switch (ch) {
case DOWN:
if (Judgedown(type, form, x, y + 20) == 1) {
Clearblock(type, form, x, y);
y = y + 20;//覆盖后下移动
}
break;
case RIGHT:
if (Judgedown(type, form, x + 20, y) == 1) {
Clearblock(type, form, x, y);
x = x + 20;//覆盖后左移动
}
break;
case LEFT:
if (Judgedown(type, form, x - 20, y) == 1) {
Clearblock(type, form, x, y);
x = x - 20;//覆盖后右移动
}
break;
case UP://旋转操作
if (Judgedown(type, (form + 1) % 4, x, y + 20) == 1) {//判断旋转是否可以
Clearblock(type, form, x, y);
y = y + 20;//下移着旋转
form = (form + 1) % 4;
}
break;
case SPACE://暂停操作
system("pause>nul");
break;
case 'r':
case 'R'://重新开始
FlushBatchDraw();
for (int i = 0; i < 33; i++) {
for (int j = 0; j < 33; j++) {
flag.value[i][j] = 0;
}
}
main();
case 'S':
case 's'://清屏退出游戏
cleardevice();
settextcolor(WHITE);
settextstyle(40, 0, _T("楷体"));
outtextxy(250, 280, _T("GAME OVER"));
outtextxy(260, 340, _T("游戏结束"));
Sleep(2000);
exit(0);
}
}
Drawblock(type, form, x, y);
}
//下移操作
if (Judgedown(type, form, x, y + 20) == 1) {
Clearblock(type, form, x, y);
y = y + 20;
}
else {//无法下移
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (block[type][form].space[i][j] == 1) {
flag.value[y / 20 + i][x / 20 + j] = 1;//在界面上全部记录
flag.color[y / 20 + i][x / 20 + j] = type; //记录该方块的颜色数值
}
}
}
Gradejudge();
Gameover();
break;
}
}
type = nexttype, form = nextform;
Clearblock(nexttype, nextform, 500, 80);//清空右上角
}
}
//音乐播放
void BGM() {
mciSendString(_T("open su.mp3 alias BGM"), 0, 0, 0);
mciSendString(_T("play BGM repeat"), 0, 0, 0);
if (0) {
mciSendString(_T("close BGM"), 0, 0, 0);
}
}
//欢迎界面
void welcome() {
IMAGE image;
loadimage(&image, _T("./背景.jpg"), 660, 660);
putimage(0, 0, &image);
settextstyle(50, 0, _T("隶书"));
settextcolor(BLACK);
setbkmode(TRANSPARENT);
Sleep(2000);
}
void beginGame();
void Choose(){
IMAGE image;
ExMessage m;
cleardevice();
struct Button* jd = createButton(220, 250, 200, 80, "简单模式", RGB(194, 194, 164), RGB(235, 231, 213));
struct Button* kn = createButton(220, 350, 200, 80, "困难模式", RGB(194, 194, 164), RGB(235, 231, 213));
struct Button* dy = createButton(220, 450, 200, 80, "地狱模式", RGB(194, 194, 164), RGB(235, 231, 213));
loadimage(&image, _T("./难度选择.jpg"), 180, 240);
putimage(460, 400, &image);
loadimage(&image, _T("./难度选择2.jpg") ,320,100,true);
putimage(180, 140, &image);
BeginBatchDraw();
while (1) {
peekmessage(&m, EM_MOUSE);
if (clickButton(jd, m)) {
t = 4000;
break;
}
else if (clickButton(kn, m)) {
t = 3500;
break;
}
else if (clickButton(dy, m)) {
t = 2500;
break;
}
DrawButton(jd);
DrawButton(kn);
DrawButton(dy);
FlushBatchDraw();
}
EndBatchDraw();
beginGame();
}
void beginGame(){
IMAGE image;
struct Button* Begin = createButton(220, 200, 200, 80, "开始游戏", RGB(194, 194, 164), RGB(235, 231, 213));
struct Button* End = createButton(220, 350, 200, 80, "结束游戏", RGB(194, 194, 164), RGB(235, 231, 213));
struct Button* Find= createButton(220,500, 200, 80, "查看说明", RGB(194, 194, 164), RGB(235, 231, 213));
struct Button*Return= createButton(20, 20, 100, 50, "返回", RGB(194, 194, 164), RGB(235, 231, 213));
cleardevice();
ExMessage n;
BeginBatchDraw();
while (1) {
loadimage(&image, _T("./girl2.jpg"), 180, 120);
putimage(430, 80, &image);
loadimage(&image, _T("./girl1.jpg"), 150, 150);
putimage(30, 500, &image);
DrawButton(Begin);
DrawButton(End);
DrawButton(Find);
DrawButton(Return);
while (peekmessage(&n, EM_MOUSE)) {
if (clickButton(Begin, n) == 1) {
break;
}else if (clickButton(End,n)==1) {
exit(0);
}else if (clickButton(Return, n)) {
Choose();
goto label;
}else if (clickButton(Find, n) == 1) {
cleardevice();
settextcolor(WHITE);
setbkmode(TRANSPARENT);
outtextxy(240, 220, _T("游戏说明:"));
settextstyle(30, 0, _T("楷体"));
outtextxy(220, 300, _T("1.中间随机掉落方块"));
outtextxy(220, 340, _T("2.右上角预告下一方块"));
outtextxy(220, 380, _T("3.方块满一行可得一分"));
outtextxy(220, 420, _T("4.消除越多得分越高"));
BeginBatchDraw();
while (1) {
ExMessage k;
loadimage(&image, _T("./猫猫.jpg"), 215, 364,true);
putimage(0, 345, &image);
DrawButton(Return);
while (peekmessage(&k, EM_MOUSE)) {
if (clickButton(Return, k)) {
beginGame();
break;
}
}
FlushBatchDraw();
if (clickButton(Return, k)) {
return;
}
}
EndBatchDraw();
break;
}
}
if (clickButton(Begin, n) == 1) {
break;
}
FlushBatchDraw();
}
label:
EndBatchDraw();
}
//初始化游戏视图
void Gameview() {
cleardevice();
settextstyle(20, 0, _T("楷体"));
settextcolor(WHITE);
IMAGE image;
loadimage(&image, _T("./彩虹.jpg"), 40, 20);
putimage(580, 40, &image);
for (int i = 0; i < 33; i++) {
outtextxy(460, 40, _T("下一个方块:"));
outtextxy(0, 0 + i * 20, _T("■"));
flag.value[0 + i][0] = 1;
outtextxy(640, 0 + i * 20, _T("■"));
flag.value[0 + i][32] = 1;
outtextxy(0 + 20 * i, 0, _T("■"));
flag.value[0][0 + i] = 1;
outtextxy(420, 0 + i * 20, _T("■"));
flag.value[0 + i][21] = 1;
outtextxy(0 + i * 20, 640, _T("■"));
flag.value[32][0 + i] = 1;
}
for (int i = 0; i < 10; i++) {
outtextxy(440 + i * 20, 180, _T("■"));
flag.value[9][22 + i] = 1;
}
settextstyle(25, 0, _T("仿宋"));
outtextxy(480, 220, _T("加速: ↓"));
outtextxy(480, 260, _T("左移:←"));
outtextxy(480, 300, _T("右移:→"));
outtextxy(480, 340, _T("旋转:↑"));
outtextxy(480, 380, _T("暂停:空格"));
outtextxy(480, 420, _T("退出:S"));
outtextxy(480, 460, _T("重新开始:R"));
outtextxy(480, 500, _T("目前分数:"));
outtextxy(460, 570, _T("历史最高分:"));
settextstyle(20, 0, _T("仿宋"));
char mmax[4];
sprintf_s(mmax, 4, "%d", max);
outtextxy(540, 600, mmax);
char current[4];
sprintf_s(current, 4, "%d", grade);
outtextxy(540, 540, current);
}
int main() {
BGM();
grade = 0;
ReadGrade();
srand((unsigned int)time(0));
initgraph(660, 660);
welcome();
Choose();
Gameview();
initBlock();
Gameing();
Breakgrade();
getchar();
return 0;
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化