C/C++贪吃蛇游戏(彩色版)

比较简单,罗列用到的一些知识:

  • 指定控制台光标
  • 设置控制台文字颜色
  • 监听键盘的函数kbhit
  • 生成随机数
  • 暂停函数Sleep
  • 函数cin.get()

思路:

  1. 初始化边界墙,初始化蛇,生成第一个食物
  2. 进入循环:通过键盘得到方向移动蛇(打印时只需要修改原蛇蛇尾、原蛇蛇头和新蛇蛇头)并判断蛇头和食物坐标是否相等,是则产生新食物,更新分数、速度、蛇长度。

在这里插入图片描述


最新代码:https://github.com/hellomuyi/Snake

以下为原始代码

/*
 *Author: Jin
 *Time  : 2020/11/10
 */
#include<cstdio>
#include<iostream>
#include<windows.h>
#include<ctime>
#include<conio.h>	//kbhit 

//定义坐标结构体
struct node{
	int x;
	int y;
	node(int _x, int _y):x(_x), y(_y){}
	node(){}
};
//自定义形状
const char* wallshape = "#";		//边界墙形状 
const char* headshape = "O";		//蛇头形状 
const char* bodyshape = "o";		//蛇尾形状 
const char* foodshape = "$";		//食物形状 
int len = 3;					//蛇的当前长度 
const int MAX_X_ = 20;			//逻辑边界长度(X轴),实际长度为2*MAX_X_-1,下标为0-MAX_X_-2,各点坐标都在偶数点上 
const int MAX_X = 2*MAX_X_-1;	//实际边界长度,边界点坐标都在偶数点上,0:2:MAX_X-1 
const int MAX_Y = 20;			//边界宽度(Y轴),0-MAX_Y-1
int speed = 400;				//移动速度、延时毫秒数 
const node scorexy = node(MAX_X+2,MAX_Y/2);	//实时记录分数的位置
//颜色值
const int defacol = 10;		//default默认颜色 
const int wallcol = 9;		//边界墙的颜色 
const int foodcol = 11;		//食物和蛇的颜色 

bool gameflag = true;	//游戏开始结束标志 
int score = 0;			//游戏得分 
const int MAX = 100;	//蛇的最大长度
node snake[MAX];		//各蛇节点的坐标
node food;				//食物坐标 
int dx, dy;				//下一步蛇移动的x\y分量

void gotoxy(short x, short y);	//控制台光标位置,并隐藏光标
void setColor(int color=defacol);//设置控制台文字颜色 ,注意不能同时在函数的声明和定义中使用默认形参,对比下文函数定义 
void welcome();			//欢迎界面 
void initMap();			//打印边界墙、操作说明和初始分数 
void initSnake();		//初始化蛇并打印 
void generateFood();	//随机生成食物 ,食物不能在蛇身上 
void moveSnake();		//移动蛇:更新蛇头方向、蛇节点坐标,并打印 
void tellFood();		//判断是否吃食物,是则更新分数、更新速度、更新蛇、产生下一个食物 
void tellDeath();		//判断死亡 
void gameOver();		//结束界面 
 
int main(){
	setColor();		//设置控制台文字颜色,默认形参 
	welcome();		
	initMap(); 
	initSnake();
	generateFood();
	while(gameflag){
		moveSnake();
		tellFood();
		tellDeath();
	}
	gameOver();
	return 0;
}

void gotoxy(short x, short y){//指定控制台光标
 
	COORD pos;
	pos.X = x;
	pos.Y = y;
	HANDLE hOutput=GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(hOutput,pos); 
	// 隐藏光标 
    CONSOLE_CURSOR_INFO cursor;
	cursor.bVisible = FALSE;    
	cursor.dwSize = sizeof(cursor);
	SetConsoleCursorInfo(hOutput, &cursor);
}

void setColor(int color){//设置控制台文字颜色 
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),color);
}

void welcome(){			//欢迎界面 
	gotoxy(20, 10);
    std::cout << "Welcome to Retro Snaker!";
    gotoxy(20, 15); 
    std::cout<<"通过方向键或w,a,s,d(英文输入法)改变方向";
    gotoxy(20,16);
    std::cout<<"按 空格键 暂停,按 回车键 继续";
	gotoxy(20, 20);
    std::cout << "Press enter to start the game.";
	std::cin.get();
	system("cls"); 
}

void initMap(){			//初始化地图 
	setColor(wallcol); 
	//画上下边界,X轴 
	for(int i=0; i<MAX_X; i+=2){
		gotoxy(i,0);
		std::cout<<wallshape;
		gotoxy(i,MAX_Y-1);
		std::cout<<wallshape;
	}
	
	//打印左右界,Y轴 
	for(int i=0; i<MAX_Y; i++){
		gotoxy(0,i);
		std::cout<<wallshape;
		gotoxy(MAX_X-1,i);
		std::cout<<wallshape;
	}
	setColor();		 
	gotoxy(scorexy.x,scorexy.y-3);
	std::cout<<"通过方向键或w,a,s,d(英文输入法)改变方向";
	gotoxy(scorexy.x,scorexy.y+3);
	std::cout<<"按 空格键 暂停,按 回车键 继续";
	setColor(foodcol);
	gotoxy(scorexy.x,scorexy.y);
	std::cout<<"score:"<<score; 
	setColor(defacol);	//恢复默认颜色 
}

void initSnake(){		//初始化蛇 
	dx = 0;
	dy = 1;		//初始时蛇往下移动,即Y周正方向
	int tmp_x =  (MAX_X-1)/2;
	if(tmp_x&1)		//蛇头X坐标为偶数 
		tmp_x += 1;
	for(int i=0; i<len; i++)
		snake[i] = node(tmp_x, MAX_Y/len+len-1-i);
	//snake[0] = node(MAX_X/2, MAX_Y/3+2);
	//snake[1] = node(MAX_X/2, MAX_Y/3+1);
	//snake[2] = node(MAX_X/2, MAX_Y/3+0);
	//打印初始蛇
	setColor(foodcol);	
	gotoxy(snake[0].x, snake[0].y);
	std::cout<<headshape; 		//蛇头 
	for(int i=1; i<len; i++){
		gotoxy(snake[i].x, snake[i].y);
		std::cout<<bodyshape; 	//蛇身 
	} 
	setColor(defacol);	//恢复默认颜色 
}

void generateFood(){	//随机产生在边界内且不在蛇身上的食物 
	srand(time(NULL));
	while(1){
		int x = rand()%(MAX_X-4)+2;		//X范围1-MAX_X-2,得是偶数,最大的偶数是MAX_X-3(MAX_X-1是右边界) 
		if(x&1)	//x为奇数 
			x += 1;		// 加一减一都可以 
		int y = rand()%(MAX_Y-2)+1;		//Y范围1-MAX_Y-2
		food = node(x,y);
		//判断食物是否在蛇身上
		bool foodFlag = true;
		for(int i=0; i<len; i++){
			if(food.x==snake[i].x && food.y==snake[i].y){
				foodFlag = false;
				break;
			}
		}
		if(foodFlag)
			break;
	}
	//打印食物
	setColor(foodcol);
	gotoxy(food.x, food.y);
	std::cout<<foodshape; 
	setColor(defacol);	//恢复默认颜色 
}

void moveSnake(){		//监听键盘修改蛇头方向,并打印移动后的蛇 
	if(kbhit()){
		unsigned char c = getch();//对应224,char对应-32 
		switch(c){ 
			case ' ':
				std::cin.get();
				break;
			case 'a': 	//向左移动
				if(0 == dx) {//原方向向上或向下才须改变 
					dx = -1;
					dy = 0;
				}
				break;
			case 'd':	//向右移动
				if(0 == dx) {//方向向上或向下才须改变  
					dx = 1;
					dy = 0;
				}
				break;
			case 'w':	//向上移动
				if(0 == dy) {//原方向向左或向右才须改变 
					dx = 0;
					dy = -1;
				}
				break; 
			case 's': 	//向下移动	
				if(0 ==dy) {//方向向左或向右才须改变 
					dx = 0;
					dy = 1;
				}
				break;
			case 224:	//方向键区的ASCII码 
				c = getch();
				switch(c){
					//向左移动 
					case 75: 
						if(0 == dx) {//原方向向上或向下才须改变 
							dx = -1;
							dy = 0;
						}
						break;
					//向右移动
					case 77:
						if(0 == dx) {//方向向上或向下才须改变  
							dx = 1;
							dy = 0;
						}
						break;
					//向上移动
					case 72:
						if(0 == dy) {//原方向向左或向右才须改变 
							dx = 0;
							dy = -1;
						}
						break;
					//向下移动	 
					case 80: 
						if(0 ==dy) {//方向向左或向右才须改变 
							dx = 0;
							dy = 1;
						}
						break;
					default:
						break;
				}
			default:
				break;
		}
	}
	
	//更新整条蛇,并打印 
	gotoxy(snake[len-1].x, snake[len-1].y);
	std::cout<<" ";				//清除蛇尾 
	setColor(wallcol);
	gotoxy(0,0);		//去除这三条语句,边界墙左上角会空缺 
	std::cout<<"#";
	setColor(foodcol);
	gotoxy(snake[0].x, snake[0].y);
	std::cout<<bodyshape;				//向前移动后,之前的蛇头位置变为蛇身 
	for(int i=len-1; i>0; i--)
		snake[i] = snake[i-1];	//从蛇尾起更新坐标
	 
	snake[0] = node(snake[0].x+dx*2, snake[0].y+dy);	//更新蛇头坐标 ,dx得乘2 
	gotoxy(snake[0].x, snake[0].y);
	std::cout<<headshape; 			//打印蛇头 
	setColor(defacol);	//恢复默认颜色 
	Sleep(speed);
}

void tellFood(){		//判断是否吃食物,并产生新食物,更新速度、分数和蛇长度 
	if(food.x==snake[0].x && food.y==snake[0].y){
		generateFood();	//产生新食物 
		len++; 		//更新蛇,只需要len++,注意理解,moveSnack函数中更新时len已经+1 
		score += 10;					//更新分数
		speed>=130?speed-=30:speed=100;	//更新速度 
		setColor(foodcol);
		gotoxy(scorexy.x,scorexy.y);
		if(score<150)	//刷新分数 
			std::cout<<"score:"<<score; 
		else{
			speed = 50;
			std::cout<<"score:"<<score<<"   终极模式"; 
		} 
			
		
		setColor(defacol);	//恢复默认颜色 
	}
}

void tellDeath(){		//判断死亡 
	//撞墙而死 
	for(int i=0; i<MAX_X; i++)
		if(0==snake[0].y || MAX_Y-1==snake[0].y || 0==snake[0].x || MAX_X-1==snake[0].x){
			gameflag = false;
			return;
		}	
		
	//碰到自己而死(至少有五个点才会可能头碰到身体) 
	for(int i=len-1; i>=4; i--)
		if(snake[0].x==snake[i].x && snake[0].y==snake[i].y){
		 	gameflag = false;
		 	return;
		 }
}

void gameOver(){
	gotoxy(0,MAX_Y+1);
	std::cout<<"Game over! Your score is "<<score<<".";
	gotoxy(0,MAX_Y+3);
	std::cout << "Press Enter to continue.";
	std::cin.get();
}
/*
 *注意点:
 *控制台字符的宽高比为1:2,为了美化也更加真实,边界墙结点、蛇结点、食物的x坐标始终为偶数,蛇头的x轴方向的移动一次为两个单位长度	
 *关于颜色:需要颜色的地方设置且用完后立即设置成默认颜色,这样使用默认颜色时无需再设置	

 *改进:
 *1.蛇头为食物,吃啥蛇头变成啥,哈哈
 *2.输出汉字
 */ 
  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值