C++之自编控制台程序——贪吃蛇(原创)

初学C++,利用C的基础完成了控制台程序贪吃蛇。代码如下

#include <ctime>
#include <conio.h>
#include <iostream>
#include <windows.h>
#include <process.h>

#define random(x) (rand()%x)

using namespace std;

HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
struct Snake {
	COORD P;
	short direc;
}snakebd[1000];

short length=0;			//	蛇身长度
short score = 0;		//	当前得分
short record = 0;		//	得分最高记录
bool pause = false;		//	暂停标识
bool GameOver = false;		//	游戏结束标识
bool interrupt = false;		//	moving函数暂停标识
int chr;			//	按键键码
short level;			//	难度
COORD FoodPost;			//	食物坐标
COORD Eat[100];			//	用来记录吃下的还在身体内的食物坐标
short eati = 0;			//	对应Eat,记录吃下还在身体内的食物数量

bool operator==(COORD p1, COORD p2)		//	重载运算符==用于类型COORD
{
	if (p1.X == p2.X&&p1.Y == p2.Y)		return true;
	else	return false;
}

void printxy(short x, short y,const char ch[])	//	在(x,y)处打印字符 
{
	COORD c;
	c.X = x; c.Y = y;
	SetConsoleCursorPosition(handle, c);
	cout << ch;
}

void printxy(short x, short y, short n)		//	重载printxy 在(x,y)处打印整型 
{
	COORD c;
	c.X = x; c.Y = y;
	SetConsoleCursorPosition(handle, c);
	cout << n;
}

void color(int a)	//	改变输出的颜色
{
	SetConsoleTextAttribute(handle, a);
	/*
	1   深蓝色
	2   深绿色
	3   深青色
	4   深红色
	5   深粉色
	6   黄色
	7   深白色
	8   灰色
	9   浅蓝色
	10  浅绿色
	11  浅青色
	12  浅红色
	13  浅粉色
	14  浅黄色
	15  浅白色
	*/
}

void food()	//	生成食物
{
	bool err;
	do 
	{
		err = false;
		srand((unsigned int)(clock()));
		FoodPost.X = random(40) + 2;
		srand((unsigned int)(clock()));
		FoodPost.Y = random(25) + 2;

		for (int i = 0; i < length; i++)
		{
			if (snakebd[i].P == FoodPost)
			{
				err = true; 
				break;
			}
		}
	} while (err);
	color(14);
	printxy(2* FoodPost.X-2, FoodPost.Y-1, "●");
	color(4);
}

void initialize()	//	初始化及绘制界面
{
	int i;
	score = 0;
	level = 1;
	length = 3;
	eati = 0;
	memset(Eat, NULL, sizeof(Eat));

	snakebd[0] = { 20,14,3 };
	snakebd[1] = { 21,14,3 };
	snakebd[2] = { 22,14,3 };

	color(2);
	for (i = 1; i <= 27; i++)
	{
		if (i == 1 || i == 27)
			cout << "██████████████████████████████████████████" << endl;
		else if (i == 14)
		{
			cout << "█                                    ";
			color(4);
			cout << "●██";
			color(2);
			cout << "                                      █" << endl;
		}
		else
			cout << "█                                                                                █" << endl;
	}
	
	color(6);
	printxy(84, 0,  "█████████████████");
	printxy(84, 1,  "█                              █");
	printxy(84, 2,  "█  改变窗口尺寸会导致光标出现  █");
	printxy(84, 3,  "█      按'V'可以隐藏光标       █");
	printxy(84, 4,  "█    请切换输入法至英文输入    █");
	printxy(84, 5,  "█         否则无法控制         █");
	printxy(84, 6,  "█                              █");
	printxy(84, 7,  "█████████████████");
	printxy(84, 8,  "█              █              █");
	printxy(84, 9,  "█  最高分:"); cout << record ;
	printxy(100, 9, "█   得分: "); cout << score ;
	printxy(116, 9, "█");
	printxy(84, 10, "█              █              █");
	printxy(84, 11, "█████████████████");
	printxy(84, 12, "█                              █");
	printxy(84, 13, "█  WASD:控制方向 Space:暂停  █");
	printxy(84, 14, "█        长按可加速移动        █");
	printxy(84, 15, "█       分数越高难度越大       █");
	printxy(84, 16, "█      贪吃蛇   制作:YJH      █");
	printxy(84, 17, "█                              █");
	printxy(84, 18, "█████████████████");
	printxy(40, 27, "Level-"); cout <<level;

	color(4);
	food();
}

bool JGameover()	//	判断是否结束游戏
{
	if (snakebd[0].P.X == 1 || snakebd[0].P.X == 42 || snakebd[0].P.Y == 1 || snakebd[0].P.Y == 27)		//	边界判断
		return true;
	for (int i = 2; i < length; i++)
	{
		if (snakebd[0].P == snakebd[i].P)
			return true;
	}
	return false;
}

void moving(void*)	//	实现画面的移动
{
	COORD TailPost;
	while (1)
	{
		if (!pause&&!GameOver)
		{
			interrupt = false;
			TailPost = snakebd[length - 1].P ;
			for (int i = length; i > 1; i--)
			{
				snakebd[i - 1].direc = snakebd[i - 2].direc;
				snakebd[i - 1].P = snakebd[i - 2].P;
			}	//	每次移动,第n块蛇身体信息跟随前一块(第n-1)蛇身体的信息,故每次只需改变蛇头的方向和位置即可

			if (chr == 119 && snakebd[0].direc != 4) { snakebd[0].direc = 2; }
			else if (chr == 97 && snakebd[0].direc != 1 ) { snakebd[0].direc = 3; }
			else if (chr == 115 && snakebd[0].direc != 2 ) { snakebd[0].direc = 4; }
			else if (chr == 100 && snakebd[0].direc != 3 ) { snakebd[0].direc = 1; }	//	蛇头的转向

			switch (snakebd[0].direc)	//	蛇头的位置移动
			{
			case 1:
				snakebd[0].P.X++; break;
			case 2:
				snakebd[0].P.Y--; break;
			case 3:
				snakebd[0].P.X--; break;
			case 4:
				snakebd[0].P.Y++;
			}	

			if (JGameover())	//	判断游戏结束
			{
				printxy(0, 27, "GAME OVER!!");
				printxy(0, 28, "Press R to Play Again...");
				GameOver = true;
			}	
			else
			{
				if (TailPost == Eat[0])	//	如果此刻尾巴的位置是曾经吃掉食物的位置,则“长”一块身体
				{
					length++;
					snakebd[length - 1].P = TailPost;
					for (int j = 0; j < eati; j++)
					{
						Eat[j] = Eat[j + 1];
					}
					eati--;
				}
				else	printxy(2 *TailPost.X - 2, TailPost.Y - 1, "  ");
				
				printxy(2 * snakebd[1].P.X - 2, snakebd[1].P.Y - 1, "█");
				printxy(2 * snakebd[0].P.X - 2, snakebd[0].P.Y - 1, "●");	//	否则擦掉尾巴,重画蛇头
				
				if (snakebd[0].P == FoodPost)	//	如果吃到了食物,则记录食物的位置
				{
					score++;
					Eat[eati++] = FoodPost;
					score / 3 + 1 > 23 ? level = 23 : level = score / 3 + 1;
					color(6);			
					printxy(46, 27, level);
					printxy(112, 9, score);				
					if (score > record)		
						printxy(96, 9, record = score);	
					food();
				}
				chr = 0;
				for (int k = 1; k <= 26-level; k++) 	//	等待刷新,如果有按键则跳过等待,实现加速功能
				{
					if (chr == 119 || chr == 97 || chr == 115 || chr == 100)	break;
					Sleep(20);
				}
			}		
		}
		else	interrupt = true;
	}
}

int main()
{
	
	CONSOLE_CURSOR_INFO CursorInfo;
	GetConsoleCursorInfo(handle, &CursorInfo);	//	获取控制台光标信息
	CursorInfo.bVisible = false; 
	SetConsoleCursorInfo(handle, &CursorInfo);	//	隐藏控制台光标

	initialize();

	_beginthread(moving, 0, NULL);	//	新建一个线程用以循环显示画面的变化
		
	while (1)	//	循环监听键盘消息
	{
		if (_kbhit())
		{			
			chr = _getch();
			if (chr == 32 && GameOver == false)
			{ 
				if (!pause )	// 空格暂停游戏
				{
					pause = !pause;
					while (!interrupt) {}
					printxy(99, 23, "PAUSE!");		// 这里是等待moving函数进入pause,避免子线程同时调用printxy
				}
				else
				{
					printxy(99, 23, "      ");
					pause = !pause;
				}
			}
			else if (chr == 114 && GameOver == true)	// R键重新开始
			{
				system("cls");
				initialize();
				GameOver = false;	
			}
			else if (chr == 118)	//	隐藏控制台光标
				SetConsoleCursorInfo(handle, &CursorInfo);		
		}		
	}
	return 0;
}

运行效果图:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值