C语言程序小游戏:太空躲陨石

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线程库(主要用于计时与一些具体功能的实现)。如果没有线程函数库去找其他博主的帖子自己配置就行啦。(当然也可以删掉有关线程的代码部分,不会影响代码运行,但会少掉一些功能~~自己开心就好)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值