最近正在学习C语言,于是自己就写了个俄罗斯方块小游戏,本想找一篇博文借鉴一下的,粗略的找了一圈并没有找到,于是花了2天搞了一下。初学者,代码粗陋,大佬勿喷。有哪里不对的,请不吝赐教,谢谢~ 废话不多说,上图:  代码开始运行检测C:\GameTetris.dat文件是否是合法的存档,如果是则提示用户游戏有存档,是否读取。 按下N,则删除存档,新建新的游戏,重新开始。 按下Y,则读取文档,从上次状态保存的状态开始运 我按下了Y,所以程序读取了存档。
1、键盘信号获取 由 _kbhit(),_getch() ,函数获取 _kbhit()检测有没有键按下 _getch()读取键值
2、方块的产生 通过srand,与rand 函数实现随机产生
3、控制台 一个方块占2个横向空格长度,1个纵向空格长度,所以代码中会频繁出现横坐标 * 2的代码
4、旋转方块 我的方法是选一个中心点作为坐标原点,根据这个原点画一个坐标系,其余4个子方块在这个坐标系中相对原点的位置偏移存储在BlockXY blockXY[4];中,centerXY结构体就是原点的实际坐标,那么其余3个子方块的实际坐标就可以根据这个中心点算出来。 而左移,右移,下移都只需要移动这个中心点的实际坐标即可。 下方堆积的方块是使用一个二维数组在存储,二维数组的成员等于1,则在对应坐标上就有一个堆积方块。
一些代码函数什么的参考了如下博文(一篇讲C语言贪吃蛇的): https://blog.csdn.net/qq_40953281/article/details/79315254
接下来上代码:(我是用VC6.0写的)
#include "stdafx.h"
#include "string.h"
#include "stdlib.h"
#include "windows.h"
#include "conio.h"
#include "time.h"
#define FilePath "C:\\GameTetris.dat"
#define GameX 24
#define GameY 36
#define SPEED 5
enum
{
BLACK,
BLUE,
GREEN,
CYAN,
RED,
MAGENTA,
BROWN,
LIGHTGRAY,
DARKGRAY,
LIGHTBLUE,
LIGHTGREEN,
LIGHTCYAN,
LIGHTRED,
LIGHTMAGENTA,
YELLOW,
WHITE
};
struct BlockXY
{
int x;
int y;
int xiangXian;
};
struct BlockShape
{
BlockXY blockXY[4];
BlockXY center;
int type;
};
BlockShape* G_pBlockShape1 = NULL, *G_pBlockShape2 = NULL;
char name[200];
int score;
char KEYVALUESET[] = {'w', 'a', 's', 'd', 'o', 'p', ' '};
int G_BlockScreenArr[GameX][GameY] = {0};
void gotoxy(int x, int y, int ForgC)
{
if(ForgC == -1)
{
ForgC = LIGHTGREEN;
}
COORD pos;
WORD wColor;
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(hOutput, pos);
CONSOLE_SCREEN_BUFFER_INFO csbi;
if(GetConsoleScreenBufferInfo(hOutput, &csbi))
{
wColor = (csbi.wAttributes & 0xF0) + (ForgC & 0x0F);
SetConsoleTextAttribute(hOutput, wColor);
}
CONSOLE_CURSOR_INFO cursor;
cursor.bVisible = FALSE;
cursor.dwSize = 1;
SetConsoleCursorInfo(hOutput, &cursor);
}
void gotoxy(int x, int y)
{
gotoxy(x, y, -1);
}
int switchFlag = 0;
void gotoprint(int x, int y)
{
int color = (switchFlag = ! switchFlag) ? LIGHTGRAY : LIGHTRED;
gotoxy(x * 2, y, color);
printf("■");
}
void gotodelete(int x, int y, int length)
{
int i;
for (i = 0; i < length; i++)
{
gotoxy(x + i, y);
printf(" ");
}
}
void gotodelete(int x, int y)
{
gotodelete(x, y, 1);
}
void drawGameMap()
{
int i;
for (i = 0; i < GameX; i++)
{
gotoprint(i, 0);
}
for (i = 0; i < GameX; i++)
{
gotoprint(i, GameY);
}
for (i = 0; i < GameY; i++)
{
gotoprint(0, i);
}
for (i = 0; i < GameY; i++)
{
gotoprint(GameX, i);
}
for (i = 0; i < 8; i++)
{
gotoprint(i + GameX + 2, 0);
}
for (i = 0; i < 8; i++)
{
gotoprint(i + GameX + 2, 7);
}
for (i = 0; i < 8; i++)
{
gotoprint(GameX + 2, i);
}
for (i = 0; i < 8; i++)
{
gotoprint(GameX + 2 + 7, i);
}
}
void showBlockShape(BlockShape* pBlockShape)
{
int i;
BlockXY *pBlockXY = pBlockShape->blockXY;
for (i = 0; i < 4; i++)
{
gotoxy(pBlockXY[i].x + pBlockShape->center.x, pBlockXY[i].y * -1 + pBlockShape->center.y);
printf("■");
}
}
bool initGameScreen(int state)
{
int i, j;
bool result;
char keyValue;
system("title 俄罗斯方块 by 机智蛋");
result = false;
gotoxy(15, 10);
printf("/**********************************************/");
gotoxy(15, 22);
printf("/**********************************************/");
gotoxy(20, 13);
printf("WELCOME TO THE GAME OF TETRIS");
gotoxy(14, 16);
printf("W:左移 D:右移 S:下移 空格:下落到底部 P暂停 O结束游戏并保存");
gotoxy(20, 18);
if(state)
{
printf("游戏有存档,是否读取?Y/N");
while(1)
{
keyValue = _getch();
if(keyValue == 'Y' || keyValue == 'y')
{
result = true;
break;
}
else if(keyValue == 'N' || keyValue == 'n')
{
DeleteFileA(FilePath);
score = 0;
free(G_pBlockShape1);
free(G_pBlockShape2);
G_pBlockShape1 = NULL;
G_pBlockShape2 = NULL;
for (i = 0; i < GameX; i++)
{
for (j = 0; j < GameY; j++)
{
G_BlockScreenArr[i][j] = 0;
}
}
result = false;
break;
}
}
}
if(! result)
{
gotodelete(20, 18, 30);
gotoxy(20, 18);
printf("PLEASE ENTER YOUR NAME:");
scanf("%s", name);
}
system("CLS");
gotoxy(53, 20);
printf("hello %s,Welcome To Play", name);
gotoxy(53, 25);
printf("Your Score Is:%d = ̄ω ̄= ", score);
gotoxy(53, 30);
printf("This Game Is Created By 机智蛋");
if(result)
{
for (i = 0; i < GameX; i++)
{
for (j = 0; j < GameY; j++)
{
if(G_BlockScreenArr[i][j] == 1)
{
gotoxy(i * 2, j);
printf("■");
}
}
}
showBlockShape(G_pBlockShape1);
G_pBlockShape2->center.x = (GameX + 5) * 2;
G_pBlockShape2->center.y +=2;
showBlockShape(G_pBlockShape2);
}
return result;
}
int initGameScreen()
{
return initGameScreen(0);
}
void FinishGame()
{
system("CLS");
gotoxy(15, 10);
printf("/**********************************************/");
gotoxy(15, 20);
printf("/**********************************************/");
gotoxy(18, 14);
printf("GAME OVER o(* ̄▽ ̄*)o");
gotoxy(20, 16);
printf("Your Score is %d ", score);
gotoxy(18, 18);
printf("还不错哦, 继续努力O(∩_∩)O");
gotoxy(0, 27);
gotoxy(0, 27);
system("pause");
}
void rotateBlock(BlockShape* pBlockShape)
{
int i, tmp, realX, realY;
bool forbit;
BlockXY blockXY;
BlockXY centerXY;
centerXY = pBlockShape->center;
forbit = false;
if(pBlockShape->type == 3)
{
return;
}
for (i = 0; i < 4; i++)
{
blockXY.x = pBlockShape->blockXY[i].x;
blockXY.y = pBlockShape->blockXY[i].y;
gotodelete(blockXY.x + pBlockShape->center.x, blockXY.y * -1 + pBlockShape->center.y);
}
for (i = 0; i < 4; i++)
{
blockXY.x = pBlockShape->blockXY[i].x;
blockXY.y = pBlockShape->blockXY[i].y;
blockXY.xiangXian = pBlockShape->blockXY[i].xiangXian;
switch(blockXY.xiangXian)
{
case 1:
{
tmp = blockXY.x;
blockXY.x = blockXY.y * 2;
blockXY.y = tmp / 2;
blockXY.y *= -1;
blockXY.xiangXian = 4;
break;
}
case 2:
{
tmp = blockXY.x * -1;
blockXY.x = blockXY.y * 2;
blockXY.y = tmp / 2;
blockXY.xiangXian = 1;
break;
}
case 3:
{
tmp = blockXY.x;
blockXY.x = blockXY.y * 2;
blockXY.y = tmp / 2 * -1;
blockXY.xiangXian = 2;
break;
}
case 4:
{
tmp = blockXY.x;
blockXY.x = blockXY.y * 2;
blockXY.y = tmp / 2 * -1;
blockXY.xiangXian = 3;
break;
}
}
realX = blockXY.x + centerXY.x;
if(realX <= 0)
{
centerXY.x += realX * -1 + 2;
}
else if(realX >= GameX * 2)
{
centerXY.x -= realX - GameX * 2 + 2;
}
realY = blockXY.y * -1 + centerXY.y;
if(realY <= 0)
{
centerXY.y += realY * -1 + 1;
}
else if(realY >= GameY)
{
forbit = true;
break;
}
if(G_BlockScreenArr[realX /2 ][realY] == 1)
{
forbit = true;
break;
}
if(! forbit)
{
pBlockShape->center = centerXY;
pBlockShape->blockXY[i].x = blockXY.x;
pBlockShape->blockXY[i].y = blockXY.y;
pBlockShape->blockXY[i].xiangXian = blockXY.xiangXian;
}
}
showBlockShape(pBlockShape);
}
bool dropBlockShape(BlockShape* pBlockShape, int type)
{
int i, realX, realY;
BlockXY blockXY;
bool forbit = false;
BlockXY centerXY;
centerXY = pBlockShape->center;
switch(type)
{
case 0:
{
centerXY.y++;
break;
}
case 1:
{
centerXY.x-=2;
break;
}
case 2:
{
centerXY.x+=2;
break;
}
default:
{
return false;
}
}
for (i = 0; i < 4; i++)
{
blockXY.x = pBlockShape->blockXY[i].x;
blockXY.y = pBlockShape->blockXY[i].y;
realX = blockXY.x + centerXY.x;
if(realX <= 0)
{
return false;
}
else if(realX >= GameX * 2)
{
return false;
}
realY = blockXY.y * -1 + centerXY.y;
if(realY >= GameY)
{
return true;
}
else if(G_BlockScreenArr[realX / 2][realY] == 1)
{
return true;
}
}
for (i = 0; i < 4; i++)
{
blockXY.x = pBlockShape->blockXY[i].x;
blockXY.y = pBlockShape->blockXY[i].y;
gotodelete(blockXY.x + pBlockShape->center.x, blockXY.y * -1 + pBlockShape->center.y);
}
pBlockShape->center = centerXY;
showBlockShape(pBlockShape);
return false;
}
BlockShape* creatBlockShape()
{
BlockShape* pBlockShape = (BlockShape*)malloc(sizeof(BlockShape));
pBlockShape->type = rand() % 7;
switch (pBlockShape->type)
{
case 0:
{
pBlockShape->center.x = GameX;
pBlockShape->center.y = 1;
pBlockShape->blockXY[0].x = -2;
pBlockShape->blockXY[0].y = 0;
pBlockShape->blockXY[0].xiangXian = 3;
pBlockShape->blockXY[1].x = 0;
pBlockShape->blockXY[1].y = 0;
pBlockShape->blockXY[1].xiangXian = 0;
pBlockShape->blockXY[2].x = 2;
pBlockShape->blockXY[2].y = 0;
pBlockShape->blockXY[2].xiangXian = 1;
pBlockShape->blockXY[3].x = 4;
pBlockShape->blockXY[3].y = 0;
pBlockShape->blockXY[3].xiangXian = 1;
break;
}
case 1 :
{
pBlockShape->center.x = GameX;
pBlockShape->center.y = 1;
pBlockShape->blockXY[0].x = -2;
pBlockShape->blockXY[0].y = 0;
pBlockShape->blockXY[0].xiangXian = 3;
pBlockShape->blockXY[1].x = 0;
pBlockShape->blockXY[1].y = 0;
pBlockShape->blockXY[1].xiangXian = 0;
pBlockShape->blockXY[2].x = 2;
pBlockShape->blockXY[2].y = 0;
pBlockShape->blockXY[2].xiangXian = 1;
pBlockShape->blockXY[3].x = -2;
pBlockShape->blockXY[3].y = -1;
pBlockShape->blockXY[3].xiangXian = 3;
break;
}
case 2:
{
pBlockShape->center.x = GameX;
pBlockShape->center.y = 1;
pBlockShape->blockXY[0].x = -2;
pBlockShape->blockXY[0].y = 0;
pBlockShape->blockXY[0].xiangXian = 3;
pBlockShape->blockXY[1].x = 0;
pBlockShape->blockXY[1].y = 0;
pBlockShape->blockXY[1].xiangXian = 0;
pBlockShape->blockXY[2].x = 2;
pBlockShape->blockXY[2].y = 0;
pBlockShape->blockXY[2].xiangXian = 1;
pBlockShape->blockXY[3].x = 2;
pBlockShape->blockXY[3].y = -1;
pBlockShape->blockXY[3].xiangXian = 4;
break;
}
case 3:
{
pBlockShape->center.x = GameX;
pBlockShape->center.y = 1;
pBlockShape->blockXY[0].x = -2;
pBlockShape->blockXY[0].y = 0;
pBlockShape->blockXY[0].xiangXian = 3;
pBlockShape->blockXY[1].x = 0;
pBlockShape->blockXY[1].y = 0;
pBlockShape->blockXY[1].xiangXian = 0;
pBlockShape->blockXY[2].x = -2;
pBlockShape->blockXY[2].y = -1;
pBlockShape->blockXY[2].xiangXian = 3;
pBlockShape->blockXY[3].x = 0;
pBlockShape->blockXY[3].y = -1;
pBlockShape->blockXY[3].xiangXian = 4;
break;
}
case 4:
{
pBlockShape->center.x = GameX;
pBlockShape->center.y = 2;
pBlockShape->blockXY[0].x = -2;
pBlockShape->blockXY[0].y = 0;
pBlockShape->blockXY[0].xiangXian = 3;
pBlockShape->blockXY[1].x = 0;
pBlockShape->blockXY[1].y = 0;
pBlockShape->blockXY[1].xiangXian = 0;
pBlockShape->blockXY[2].x = 0;
pBlockShape->blockXY[2].y = 1;
pBlockShape->blockXY[2].xiangXian = 2;
pBlockShape->blockXY[3].x = 2;
pBlockShape->blockXY[3].y = 1;
pBlockShape->blockXY[3].xiangXian = 1;
break;
}
case 5:
{
pBlockShape->center.x = GameX;
pBlockShape->center.y = 1;
pBlockShape->blockXY[0].x = -2;
pBlockShape->blockXY[0].y = 0;
pBlockShape->blockXY[0].xiangXian = 3;
pBlockShape->blockXY[1].x = 0;
pBlockShape->blockXY[1].y = 0;
pBlockShape->blockXY[1].xiangXian = 0;
pBlockShape->blockXY[2].x = 0;
pBlockShape->blockXY[2].y = -1;
pBlockShape->blockXY[2].xiangXian = 4;
pBlockShape->blockXY[3].x = 2;
pBlockShape->blockXY[3].y = -1;
pBlockShape->blockXY[3].xiangXian = 4;
break;
}
case 6:
{
pBlockShape->center.x = GameX;
pBlockShape->center.y = 2;
pBlockShape->blockXY[0].x = -2;
pBlockShape->blockXY[0].y = 0;
pBlockShape->blockXY[0].xiangXian = 3;
pBlockShape->blockXY[1].x = 0;
pBlockShape->blockXY[1].y = 0;
pBlockShape->blockXY[1].xiangXian = 0;
pBlockShape->blockXY[2].x = 2;
pBlockShape->blockXY[2].y = 0;
pBlockShape->blockXY[2].xiangXian = 1;
pBlockShape->blockXY[3].x = 0;
pBlockShape->blockXY[3].y = 1;
pBlockShape->blockXY[3].xiangXian = 2;
break;
}
}
return pBlockShape;
}
bool readGameFile()
{
FILE *fp;
int blockScreenArr[GameX][GameY] = {0};
int s, i, j;
BlockShape *pBlockShape1, *pBlockShape2;
if((fp = fopen(FilePath, "rb")) == NULL)
{
return 0;
}
pBlockShape1 = (BlockShape*)malloc(sizeof(BlockShape));
pBlockShape2 = (BlockShape*)malloc(sizeof(BlockShape));
fread(blockScreenArr, sizeof(blockScreenArr), 1, fp);
fread(pBlockShape1, sizeof(BlockShape), 1, fp);
fread(pBlockShape2, sizeof(BlockShape), 1, fp);
fread(&s, sizeof(int), 1, fp);
fread(name, sizeof(name), 1, fp);
fclose(fp);
if(pBlockShape1->type > 6 || pBlockShape1->type < 0 || pBlockShape2->type> 6 || pBlockShape2->type < 0 || s < 0)
{
free(pBlockShape1);
free(pBlockShape2);
return false;
}
G_pBlockShape1 = pBlockShape1;
G_pBlockShape2 = pBlockShape2;
score = s;
for (i = 0; i < GameX; i++)
{
for (j = 0; j < GameY; j++)
{
G_BlockScreenArr[i][j] = blockScreenArr[i][j];
}
}
return true;
}
void saveGame()
{
FILE *fp;
if((fp = fopen(FilePath, "wb")) == NULL)
{
gotoxy(0, 27);
printf("游戏保存失败\n");
return;
}
fwrite(G_BlockScreenArr, sizeof(G_BlockScreenArr), 1, fp);
fwrite(G_pBlockShape1, sizeof(BlockShape), 1, fp);
fwrite(G_pBlockShape2, sizeof(BlockShape), 1, fp);
fwrite(&score, sizeof(score), 1, fp);
fwrite(name, sizeof(name), 1, fp);
fclose(fp);
}
bool jugeKeyValue(char key)
{
int i;
for (i = 0; i < sizeof(KEYVALUESET); i++)
{
if(key == KEYVALUESET[i])
{
break;
}
}
if(i >= sizeof(KEYVALUESET))
{
return true;
}
if(key == 'o')
{
saveGame();
FinishGame();
return false;
}
else if(key == 'p')
{
gotoxy(0, GameY + 2);
printf("按任意键继续......");
_getch();
gotodelete(0, GameY + 2, 20);
}
else if(key == 'w')
{
rotateBlock(G_pBlockShape1);
}
else if(key == 'a')
{
dropBlockShape(G_pBlockShape1, 1);
}
else if(key == 'd')
{
dropBlockShape(G_pBlockShape1, 2);
}
return true;
}
void addInBlockScreenArr(BlockShape* pBlockShape)
{
int i;
for (i = 0; i < 4; i++)
{
G_BlockScreenArr[(pBlockShape->blockXY[i].x + pBlockShape->center.x) / 2][pBlockShape->blockXY[i].y * -1 + pBlockShape->center.y]
= 1;
}
}
bool checkBlockReachTop()
{
int i;
for (i = 1; i < GameX; i++)
{
if(G_BlockScreenArr[i][1] == 1)
{
return true;
}
}
return false;
}
bool checkBlockLineIsFull()
{
int i, j, count;
for (j = GameY - 1; j > 0; j--)
{
count = 0;
for (i = 1; i < GameX; i++)
{
if(G_BlockScreenArr[i][j] == 1)
{
count++;
}
}
if(count == GameX - 1)
{
score++;
gotoxy(67, 25);
printf("%d", score);
for (i = 1; i < GameX; i++)
{
gotodelete(i * 2, j);
G_BlockScreenArr[i][j] = 0;
}
Sleep(300);
for (j = j - 1; j > 0; j--)
{
count = 0;
for (i = 1; i < GameX; i++)
{
gotodelete(i * 2, j);
if(G_BlockScreenArr[i][j] == 1)
{
G_BlockScreenArr[i][j] = 0;
count++;
G_BlockScreenArr[i][j + 1] = 1;
gotoxy(i * 2, j + 1);
printf("■");
}
}
if(count == 0)
{
break;
}
}
return true;
}
else if(count == 0)
{
return false;
}
}
return false;
}
int main(int argc, char* argv[])
{
char c;
bool onBottom, dropFast;
int speedCount = 0;
int i;
dropFast = false;
srand(time(0));
initGameScreen(readGameFile());
drawGameMap();
while(1)
{
if (_kbhit())
{
c = _getch();
if(! jugeKeyValue(c))
{
return 0;
}
}
if(G_pBlockShape2 == NULL)
{
G_pBlockShape2 = creatBlockShape();
if(G_pBlockShape1 == NULL)
{
G_pBlockShape1 = G_pBlockShape2;
G_pBlockShape2 = NULL;
}
else
{
G_pBlockShape2->center.x = (GameX + 5) * 2;
G_pBlockShape2->center.y +=2;
showBlockShape(G_pBlockShape2);
}
showBlockShape(G_pBlockShape1);
}
if(c == ' ')
{
dropFast = true;
}
if(c == 's' || dropFast || speedCount++ == SPEED)
{
speedCount = 0;
onBottom = dropBlockShape(G_pBlockShape1, 0);
if(onBottom)
{
dropFast = false;
if(checkBlockReachTop())
{
FinishGame();
return 0;
}
addInBlockScreenArr(G_pBlockShape1);
while(checkBlockLineIsFull()){};
free(G_pBlockShape1);
for (i = 0; i < 4; i++)
{
gotodelete(G_pBlockShape2->center.x + G_pBlockShape2->blockXY[i].x, G_pBlockShape2->center.y + G_pBlockShape2->blockXY[i].y * -1);
}
G_pBlockShape1 = G_pBlockShape2;
G_pBlockShape1->center.x = GameX;
G_pBlockShape2->center.y -=2;
G_pBlockShape2 = NULL;
}
}
Sleep(100);
c = '\0';
}
return 0;
}
全篇完~
|