1.程序介绍
按上下左右键实现移动,空格键会瞬移一段距离,但有冷却时间(5s)。游戏时按回车键暂停,ESC键结束游戏,程序会自动记录每次最长的存活时间。可选择游戏难度,还有自定义模式。
(介于博主能力有限,花了3天时间才做成这样,其中也有一些思路是借鉴其他博主的,但绝大多数还是自己死磕脑子想出来的,还请勿喷~)
2.代码
编译环境:VS 2022
#include<stdio.h>
#include<conio.h>
#include<Windows.h>
#include<pthread.h>
#include<time.h>
#define Length 80
#define Width 40
#define startx Width-5
#define starty Length/2-2
#define blank -1
#define plane 2
#define Stone 4
int x, y;
int DropSpeed = 1;
int Over = 0;
int Time;
int Pause;
int Cool = 0;
int CoolTimeRecord;
int Scene;
FILE* fp;
pthread_t th1;
pthread_t th2;
typedef struct
{
int x;
int y;
}Record;
Record record[Length * Width]; //记录陨石位置消息
typedef struct
{
int density; //行密度(隔多少行出现一排) 越小越难(1为每行都输出)
int nums; //列密度 (一行出现多少个) 越大越难
int DropSpeed; //下降速度 越小越难(最小为0)
}Difficult;
Difficult Difficulty[3] = { {8,1,5},{5,2,3},{3,4,0} };
Difficult GameDifficulty;
int game[Width][Length];
void goto_xy(int x, int y) //移动光标
{
COORD cursor;
cursor.X = x;
cursor.Y = y;
HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(output, cursor);
}
void HideCursor() //隐藏光标
{
CONSOLE_CURSOR_INFO cursor;
cursor.bVisible = FALSE;
cursor.dwSize = 1;
HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorInfo(output, &cursor);
}
void ClearPartWord() //清除选项文字
{
goto_xy(starty - 2, 3); printf(" ");
goto_xy(starty - 2, 4); printf(" ");
goto_xy(starty - 2, 5); printf(" ");
goto_xy(starty - 2, 6); printf(" ");
goto_xy(starty - 2, 7); printf(" ");
}
void* CoolingTime(void* argc) //冷却时间线程函数,需要使用时才会被使用
{
CoolTimeRecord = 5;
while (CoolTimeRecord && !Over)
{
if (Pause == 1)continue;
Sleep(1000);
CoolTimeRecord--;
}
Cool = 0;
return NULL;
}
void GetFileDataAndPut() //获取文件中的分数信息
{
int score;
fp = fopen("c:\\Users\\lenovo\\Desktop\\CFILE\\HighestTimeRecord.txt", "r"); //自行创建文件存储数据
rewind(fp);
fread(&score, 4, 1, fp);
fclose(fp);
goto_xy(0, 0);
printf("当前最高存活时间: %d 秒", score);
}
void ChangeFileData() //修改文件分数信息
{
int Recent_Score;
fp = fopen("c:\\Users\\lenovo\\Desktop\\CFILE\\HighestTimeRecord.txt", "r+");
fread(&Recent_Score, 4, 1, fp);
rewind(fp);
if (Time > Recent_Score)fwrite(&Time, 4, 1, fp);
fclose(fp);
}
void CreateStone(int nums) //生成陨石(参数为每次生成数量)
{
int m;
int n;
int chance = rand() % nums + 1;
for (int i = 0; i < chance; i++)
{
n = rand() % Length;
m = 0;
game[m][n] = Stone;
}
}
void* TimeRecord(void* argc) //计时线程函数
{
Time = 0;
while (!Over)
{
if (Pause == 1)continue;
Time++;
Sleep(1000);
}
return NULL;
}
void PlaneMoveCrush(char n) //判断该次移动是否会与陨石碰撞
{
if (n == 'W')
{
if (game[x - 1][y - 2] == Stone || game[x - 1][y - 1] == Stone || game[x - 1][y + 1] == Stone || game[x - 1][y + 2] == Stone || game[x - 2][y] == Stone)
{
Over = 1;
}
}
else if (n == 'A')
{
if (game[x][y - 3] == Stone || game[x + 1][y - 1] == Stone || game[x - 1][y - 1] == Stone || game[x + 2][y - 2] == Stone)
{
Over = 1;
}
}
else if (n == 'D')
{
if (game[x][y + 3] == Stone || game[x + 1][y + 1] == Stone || game[x - 1][y + 1] == Stone || game[x + 2][y + 2] == Stone)
{
Over = 1;
}
}
else if (n == 'S')
{
if (game[x + 1][y + 2] == Stone || game[x + 1][y + 1] == Stone || game[x + 1][y - 1] == Stone || game[x + 1][y - 2] == Stone || game[x + 3][y - 1] == Stone || game[x + 3][y] == Stone || game[x + 3][y + 1] == Stone)
{
Over = 1;
}
}
}
void PlanePositon(int x, int y, char move) //优化后的飞机定位
{
if (move == '0')
{
game[x][y - 2] = plane;
game[x][y - 1] = plane;
game[x][y] = plane;
game[x][y + 1] = plane;
game[x][y + 2] = plane;
game[x + 1][y] = plane;
game[x + 2][y - 1] = plane;
game[x + 2][y] = plane;
game[x + 2][y + 1] = plane;
game[x - 1][y] = plane;
}
else if (move == 'W')
{
game[x - 1][y] = plane;
game[x][y - 2] = plane;
game[x][y - 1] = plane;
game[x][y + 1] = plane;
game[x][y + 2] = plane;
game[x + 2][y - 1] = plane;
game[x + 2][y] = plane;
game[x + 2][y + 1] = plane;
}
else if (move == 'S')
{
game[x + 2][y] = plane;
game[x][y - 2] = plane;
game[x][y - 1] = plane;
game[x][y + 1] = plane;
game[x][y + 2] = plane;
game[x + 2][y - 1] = plane;
game[x + 2][y] = plane;
game[x + 2][y + 1] = plane;
}
else if (move == 'A')
{
game[x - 1][y] = plane;
game[x][y - 2] = plane;
game[x + 1][y] = plane;
game[x + 2][y - 1] = plane;
}
else if (move == 'D')
{
game[x - 1][y] = plane;
game[x][y + 2] = plane;
game[x + 1][y] = plane;
game[x + 2][y + 1] = plane;
}
}
void Show()
{
goto_xy(0, 0);
if (Pause != 1)
{
for (int i = 0; i < Width; i++)
{
for (int j = 0; j < Length; j++)
{
if (game[i][j] == blank)printf(" ");
else if (game[i][j] == plane)printf("■");
else if (game[i][j] == Stone)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 4);
printf("●");
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}
}
printf("\n");
}
printf("存活时间:%-2d秒", Time);
if (Cool == 1)printf(" 技能冷却时间:%d", CoolTimeRecord);
if (CoolTimeRecord == 0)printf(" ");
}
else
{
goto_xy(Length / 2 - 5, Width / 2 - 10);
printf("按移动键以继续");
}
}
void Init()
{
x = startx;
y = starty;
Over = 0;
int i, j;
for (i = 0; i < Width; i++)
for (j = 0; j < Length; j++)game[i][j] = blank;
PlanePositon(startx, starty, '0');
}
void DeletePlane(int x, int y, char move)//优化后的消除飞机(依据移动的方向删除必要的飞机部分)
{
if (move == ' ')
{
game[x][y - 2] = blank;
game[x][y - 1] = blank;
game[x][y] = blank;
game[x][y + 1] = blank;
game[x][y + 2] = blank;
game[x + 1][y] = blank;
game[x + 2][y - 1] = blank;
game[x + 2][y] = blank;
game[x + 2][y + 1] = blank;
game[x - 1][y] = blank;
}
if (move == 'W') //0代表W,1代表S,2代表A,3代表D
{
game[x + 2][y] = blank;
game[x + 2][y - 1] = blank;
game[x + 2][y + 1] = blank;
game[x][y - 2] = blank;
game[x][y - 1] = blank;
game[x][y + 1] = blank;
game[x][y + 2] = blank;
}
else if (move == 'S')
{
game[x - 1][y] = blank;
game[x + 2][y - 1] = blank;
game[x + 2][y + 1] = blank;
game[x][y - 2] = blank;
game[x][y - 1] = blank;
game[x][y + 1] = blank;
game[x][y + 2] = blank;
}
else if (move == 'A')
{
game[x + 1][y] = blank;
game[x - 1][y] = blank;
game[x][y + 2] = blank;
game[x + 2][y + 1] = blank;
}
else if (move == 'D')
{
game[x + 1][y] = blank;
game[x - 1][y] = blank;
game[x][y - 2] = blank;
game[x + 2][y - 1] = blank;
}
}
void RevealState() //更新陨石下落状态
{
int i = 0;
int sum = 0;
if (Pause == 1)return;
for (int i = 0; i < Width; i++)
{
for (int j = 0; j < Length; j++)
{
if (game[i][j] == Stone)
{
game[i][j] = blank;
record[sum].x = i + 1;
record[sum++].y = j;
}
}
}
record[sum].x = -1; record[sum].y = -1; i = 0;
while (record[i].x != -1)
{
if (game[record[i].x][record[i].y] == plane)
{
game[record[i].x][record[i].y] = Stone;
Over = 1;
break;
}
game[record[i].x][record[i].y] = Stone;
i++;
}
}
void GetKeyBoard() //键盘输入
{
char key_W = GetKeyState(VK_UP),
key_S = GetKeyState(VK_DOWN),
key_A = GetKeyState(VK_LEFT),
key_D = GetKeyState(VK_RIGHT),
key_Space = GetKeyState(VK_SPACE),
key_Pause = GetKeyState(VK_RETURN),
key_Exit = GetKeyState(VK_ESCAPE);
if (kbhit())
{
if (key_W < 0)
{
Pause = 0;
if (x - 1 == 0)return;
PlaneMoveCrush('W');
DeletePlane(x, y, 'W');
PlanePositon(--x, y, 'W');
}
if (key_S < 0)
{
Pause = 0;
if (x + 2 == Width - 2)return;
PlaneMoveCrush('S');
DeletePlane(x, y, 'S');
PlanePositon(++x, y, 'S');
}
if (key_A < 0)
{
Pause = 0;
if (y - 2 == 0)return;
PlaneMoveCrush('A');
DeletePlane(x, y, 'A');
PlanePositon(x, --y, 'A');
}
if (key_D < 0)
{
Pause = 0;
if (y + 2 == Length - 2)return;
PlaneMoveCrush('D');
DeletePlane(x, y, 'D');
PlanePositon(x, ++y, 'D');
}
if (key_Space < 0 && Cool == 0)
{
Cool = 1; //进入冷却
Pause = 0;
if (x - 3 <= 0)return;
DeletePlane(x, y, ' ');
PlanePositon(x - 7, y, '0');
x = x - 7;
pthread_create(&th2, NULL, CoolingTime, NULL);
}
if (key_Pause < 0)Pause = 1;
if (key_Exit < 0)Over = 1;
}
}
void GameOver() //游戏结束界面(包括选择是否重新游戏界面)
{
ChangeFileData();
Sleep(1000);
goto_xy(4, 3); printf(" /---- /\\ |\\ /||----- --- \\ /|----- ----");
goto_xy(4, 4); printf("| / \\ | \\ / || / \\ \\ / | | |");
goto_xy(4, 5); printf("| --- /____\\ | \\ / ||----- | | \\ / |----- |____/");
goto_xy(4, 6); printf("| | / \\ | \\ / || | | \\ / | | \\");
goto_xy(4, 7); printf(" \\----/ \\| \\/ ||----- \\___/ \\/ |----- | \\");
Sleep(2000);
system("cls");
printf("\n\n\n\n 你存活了%-2d秒,再接再厉!", Time);
Sleep(2000);
printf("\n\n 是否重新游戏?");
printf("\n\n y/n(输入y以重新开始)");
while (kbhit()) //清除由于敲击键盘移动产生的积累在缓冲区的无用数据(会影响getch()的使用)
{
getch();
}
}
void WaitAndChoice() //等待页面的背景显示
{
int i = 0;
while (i != 30)
{
int m = rand() % Length;
int n = rand() % Width;
goto_xy(m, n);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 4);
printf("●");
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
i++;
}
GetFileDataAndPut();
while (1)
{
if (!kbhit())
{
if (Scene == 0)
{
goto_xy(starty - 2, 3); printf("请选择游戏难度:");
goto_xy(starty - 2, 4); printf("1.简单");
goto_xy(starty - 2, 5); printf("2.正常");
goto_xy(starty - 2, 6); printf("3.困难");
goto_xy(starty - 2, 7); printf("4.自定义模式");
}
if (Scene == 1)
{
goto_xy(starty - 2, 3); printf("请选择陨石密集程度:");
goto_xy(starty - 2, 4); printf("1.稀疏(适合新手游玩)");
goto_xy(starty - 2, 5); printf("2.拥挤");
goto_xy(starty - 2, 6); printf("3.密集(不太建议)");
goto_xy(starty - 2, 7); printf("4.返回上一个选择界面");
}
if (Scene == 2)
{
goto_xy(starty - 2, 3); printf("请选择陨石下降速度:");
goto_xy(starty - 2, 4); printf("1.慢");
goto_xy(starty - 2, 5); printf("2.快");
goto_xy(starty - 2, 6); printf("3.非常快");
goto_xy(starty - 2, 7); printf("4.返回上一个选择界面");
}
}
else
{
char ch = getch();
if ((ch == '1' || ch == '2' || ch == '3') && Scene == 0)
{
if (ch == '1') { GameDifficulty.density = Difficulty[0].density; GameDifficulty.nums = Difficulty[0].nums; GameDifficulty.DropSpeed = Difficulty[0].DropSpeed; break; }
else if (ch == '2') { GameDifficulty.density = Difficulty[1].density; GameDifficulty.nums = Difficulty[1].nums; GameDifficulty.DropSpeed = Difficulty[1].DropSpeed; break; }
else if (ch == '3') { GameDifficulty.density = Difficulty[2].density; GameDifficulty.nums = Difficulty[2].nums; GameDifficulty.DropSpeed = Difficulty[2].DropSpeed; break; }
}
else if (ch == '4' && Scene == 0) {
Scene = 1; ClearPartWord();
}
else if ((ch == '1' || ch == '2' || ch == '3') && Scene == 1)
{
Scene = 2; ClearPartWord();
if (ch == '1') { GameDifficulty.density = Difficulty[0].density; GameDifficulty.nums = Difficulty[0].nums; }
else if (ch == '2') { GameDifficulty.density = Difficulty[1].density; GameDifficulty.nums = Difficulty[1].nums; }
else if (ch == '3') { GameDifficulty.density = Difficulty[2].density; GameDifficulty.nums = Difficulty[2].nums; }
}
else if ((ch == '1' || ch == '2' || ch == '3') && Scene == 2)
{
if (ch == '1') { GameDifficulty.DropSpeed = Difficulty[0].DropSpeed; break; }
else if (ch == '2') { GameDifficulty.DropSpeed = Difficulty[1].DropSpeed; break; }
else if (ch == '3') { GameDifficulty.DropSpeed = Difficulty[2].DropSpeed; break; }
}
else if (ch == '4' && Scene == 1) {
Scene = 0; ClearPartWord();
}
else if (ch == '4' && Scene == 2) {
Scene = 1; ClearPartWord();
}
else if (ch == 27)exit(0);
}
}
}
void Start() //游戏开始前需要显示和输入的所有操作
{
WaitAndChoice();
ClearPartWord();
Init();
goto_xy(starty - 2, 3); printf("-----");
goto_xy(starty - 2, 4); printf(" |");
goto_xy(starty - 2, 5); printf("----|");
goto_xy(starty - 2, 6); printf(" |");
goto_xy(starty - 2, 7); printf("-----");
Sleep(1000);
goto_xy(starty - 2, 3); printf(" ");
goto_xy(starty - 2, 4); printf(" ");
goto_xy(starty - 2, 5); printf(" ");
goto_xy(starty - 2, 6); printf(" ");
goto_xy(starty - 2, 7); printf(" ");
goto_xy(starty - 2, 3); printf("-----");
goto_xy(starty - 2, 4); printf(" |");
goto_xy(starty - 2, 5); printf("---- ");
goto_xy(starty - 2, 6); printf("| ");
goto_xy(starty - 2, 7); printf("-----");
Sleep(1000);
goto_xy(starty - 2, 3); printf(" ");
goto_xy(starty - 2, 4); printf(" ");
goto_xy(starty - 2, 5); printf(" ");
goto_xy(starty - 2, 6); printf(" ");
goto_xy(starty - 2, 7); printf(" ");
goto_xy(starty - 2, 3); printf(" |");
goto_xy(starty - 2, 4); printf(" |");
goto_xy(starty - 2, 5); printf(" |");
goto_xy(starty - 2, 6); printf(" |");
goto_xy(starty - 2, 7); printf(" |");
Sleep(1000);
goto_xy(starty - 2, 3); printf(" ");
goto_xy(starty - 2, 4); printf(" ");
goto_xy(starty - 2, 5); printf(" ");
goto_xy(starty - 2, 6); printf(" ");
goto_xy(starty - 2, 7); printf(" ");
goto_xy(starty - 17, 3); printf("_____ _______ _ _____ _______ |");
goto_xy(starty - 17, 4); printf("| | / \\ | | | |");
goto_xy(starty - 17, 5); printf("|____ | /___\\ |____/ | |");
goto_xy(starty - 17, 6); printf(" | | / \\ | \\ | |");
goto_xy(starty - 17, 7); printf("_____| | / \\| \\ | .");
Sleep(1000);
pthread_create(&th1, NULL, TimeRecord, NULL);
}
int main()
{
HideCursor();
while (1)
{
srand(time(0));
Start();
int Chance = GameDifficulty.DropSpeed;
int Create = 0;
int CreateRecord = rand() % GameDifficulty.density + 1;
while (!Over)
{
Show();
GetKeyBoard();
if (Over == 1)break;
if (!Pause)
{
if (Chance == 0) //控制速度
{
RevealState();
Chance = GameDifficulty.DropSpeed;
Create++;
}
else Chance--;
if (Create == CreateRecord) //控制密度
{
CreateStone(GameDifficulty.nums);
Create = 0;
CreateRecord = rand() % GameDifficulty.density + 1;
}
}
}
GameOver();
if (getch() == 'y')
{
system("cls");
continue;
}
else break;
}
}
3.注意
运行本程序需要引用pthread.h线程库(主要用于计时与一些具体功能的实现)。如果没有线程函数库去找其他博主的帖子自己配置就行啦。(当然也可以删掉有关线程的代码部分,不会影响代码运行,但会少掉一些功能~~自己开心就好)