当前位置:网站首页>Snake game, C language

Snake game, C language

2022-08-09 07:32:00 hash crazy

效果演示
在这里插入图片描述
Snach.c文件

#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <time.h>
#include "consfun.h"
#include "config.h"

#define NR(x) (sizeof(x)/sizeof(x[0]+0)) /*计算数组长度*/
#define TITLE "**贪吃蛇游戏**"
#define AUTHOR "作者:张某某"
#define DATE "日期:2020年06月10日"
#define WIDTH 54 /*地图宽度*/
#define HEIGHT WIDTH/2 /*地图高度*/
#define SHead "◆" /*蛇头*/
#define SBody "■" /*蛇身体*/


/*定义一条蛇,蛇头方向RIGHT,生命值1,长度0,分数0*/
Snake S;

/*定义食物*/
Point Food;

/*菜单项*/
const char *menu[] = {
    "*开始游戏*","*游戏难度*","*退出游戏*"};
/*游戏难度*/
const char *rank[] = {
    "初级","中级","高级"};
/*Game difficulty marker*/
int lev = 0;

/*Print characters to the specified position*/
int Print(int x, int y,const char str[],short color){
    
	gotoxy(x,y);		/*设置光标位置*/
	textcolor(color);	/*设置前景颜色*/
	printf("%s",str);
	return 0;
}

/*显示菜单*/
int showMenu(){
    
	int i = 0,size = NR(menu),ret = 0, ind = 0;
	consinit(70, 30);
	Print((WIDTH-strlen(TITLE))/2,0,TITLE,2);			/*打印标题*/
	Print(WIDTH+1,0,"游戏难度:",2);						/*Print the game difficulty*/
	Print(WIDTH+11,0,rank[lev],2);
	Print((WIDTH-strlen(AUTHOR))/2,HEIGHT-4,AUTHOR,2);	/*Print the author*/
	Print((WIDTH-strlen(DATE))/2,HEIGHT-3,DATE,2);		/*打印日期*/
	Print(WIDTH,HEIGHT + 1,"按Esc键退出游戏",2);
	while(1){
    											/*Controls menu selections*/
		for(i = 0;i < size;i++)							/*Cycle through the print menu items*/
			Print( (WIDTH-strlen(menu[i]))/2, (HEIGHT-size)/2+i,menu[i], i == ind ? 5 : 2 );
		while((ret = _getch()) != ESC && ret != UP && ret != DOWN && ret != ENTER);/*控制用户输入*/
		ret == UP && ind > 0 ? ind -= 1 : ret == DOWN && ind < size - 1 ? ind += 1 : 0;/*Controls the change of the selected index*/
		if(ret == ENTER){
    /*Determine which option was pressed【回车】*/
			switch(ind){
    
				case 0:{
    							/*开始游戏*/
					/*显示地图*/
					showMap();
					if (!SnakeMove(&S)){
    /*返回值为0It is a reminder that the game is over!*/
						Print(WIDTH/2-5,HEIGHT/2,"Game Over!",12);
						while((ret = _getch()) != ESC);/*控制用户输入*/
					}
					break ;
				}
				case 1:{
    							/*游戏难度*/
					/*Cyclically changing difficulty levels*/
					lev = (lev + 1) % NR(rank);
					/*Printing difficulty level*/
					Print(WIDTH+11,0,rank[lev],2);
					break ;
				}
				case 2:		exit(0);				/*退出游戏*/
			}
		}else if(ret == ESC) exit(0);			/*按ESC键退出游戏*/
	}
	return 0;
}

/*创建地图*/
void showMap(){
    
	char str[20] = {
    0};
	int i,j;
	clrscr();
	Print(WIDTH+1,0, "游戏难度:",2);
	Print(WIDTH+1,2, "游戏时间:",2);
	Print(WIDTH+1,4, "snake health:",2);
	Print(WIDTH+1,6, "当前得分:",2);
	Print(WIDTH,HEIGHT+1,"按Esc键返回菜单",2);
	Print(WIDTH+11,0,rank[lev],2);
	Print(WIDTH+11,2,"0",2);/*游戏时间*/
	Print(WIDTH+11,4,"1",2);/*snake health*/
	Print(WIDTH+11,6,"0",2);/*当前得分*/
	for(i=0;i<WIDTH;++i)/*Print map boundaries*/
		for(j=0;j<HEIGHT;++j)
			if(i==0||j==0||i==WIDTH-1||j==HEIGHT-1)
				Print(i,j,"#",2);
	InitSnake(&S,2);/*初始化蛇*/
	randFood(&S);/*随机生成食物*/
}

/*初始化蛇*/
void InitSnake(Snake *ps,const int len){
    
	Node *p;
	int i = 0;
	ps->hp = 1;/*初始生命值*/
	ps->len = 0;/*Snake length is cleared*/
	ps->score = 0;/*当前得分*/
	ps->sym = RIGHT;/*蛇头方向*/
	ps->head = NULL;
	for(;i < len; i++){
    
		if((p = (Node*)malloc(sizeof(Node))) == NULL){
    /*Determine whether the memory allocation was successful*/
			Print(0,0,"分配内存失败,按任意键退出程序!",2);
			system("pause>nul");
			exit(0);
        }
		/*New node coordinates*/
		p->pos.x = ((WIDTH + len * 2) / 2 - (len - i) * 2) | 1; /* xCoordinates must be odd */
		p->pos.y = HEIGHT / 2;
		/*采用头插法*/
		p->next = ps->head;
		ps->head = p;
		/*蛇长加1*/
		ps->len++;
		/*Print the node to the screen*/
		Print(p->pos.x,p->pos.y,SBody,2);
	}
	Print(ps->head->pos.x,ps->head->pos.y,SHead,2);
}

/*随机生成食物*/
void randFood(const Snake *s){
    
	int x, y, k = 1;
	Node *p = s->head;/*Create a node pointing to the snake head*/
	while(p != NULL && k){
    
		/*Randomly generate coordinates within the bounds of the map*/
		x = (rand() % (WIDTH - 3) + 1) | 1;/* xCoordinates must be odd */
		y = rand() % (HEIGHT - 2) + 1;
		while(p != NULL && k)/*Determine whether the random coordinates overlap with the snake body*/
			p->pos.x == x && p->pos.y == y ? k = 0 : (int)(p = p->next);
		k = !k;
	}
	Food.x = x;		Food.y = y;
	/*Print food to the screen*/
	Print(x,y,SBody,9);
}

/*控制蛇的移动*/
int SnakeMove(Snake *s){
    
	int vec = 0,i = 0,j;
	char key,str[10];
	DWORD old;
	long time;
	while(j = 1){
    
		if(_kbhit()){
    
			key = _getch();
			/*Press the direction of the snake head to shield the specified direction key*/
			if(s->sym == UP && key == DOWN)         continue;
			else if(s->sym == DOWN && key == UP)    continue;
			else if(s->sym == LEFT && key == RIGHT) continue;
			else if(s->sym == RIGHT && key == LEFT) continue;
			switch(key){
    /*If the arrow keys are pressed,Change the direction of the snake head*/
				case UP   : s->sym = UP   ;	break;
				case DOWN : s->sym = DOWN ;	break;
				case LEFT : s->sym = LEFT ;	break;
				case RIGHT: s->sym = RIGHT;	break;
				case ESC  : return 1;
				default   : continue;
			}
			vec = 1;
			/*Life after snake collision-1*/
			if(!ChangeSnackXY(s)){
    
				s->hp -= 1;
				_itoa_s((int)s->hp,str,sizeof(str)-1,10);
				Print(WIDTH+11,4,str,2);/*snake health*/
				Print(0,HEIGHT,"撞到障碍物,生命值-1!",12);
			}
		}
		if(vec != 0){
    
			vec = (lev == 0 ? 300 : (lev == 1 ? 150 : 30));
			time = GetTickCount() - old;/*Calculate start game time*/
			_itoa_s((int)(time / 1000),str,sizeof(str)-1,10);
			Print(WIDTH+11,2,str,2);/*Print game time*/
			if((time / vec) % 2){
    /*控制移动速度*/
				/*Life after snake collision-1*/
				if(i-- == 0 && !(ChangeSnackXY(s))){
    /*用i保证ChangeSnackXY(s)Only run once during the valid time*/
					s->hp -= 1;
					_itoa_s((int)s->hp,str,sizeof(str)-1,10);
					Print(WIDTH+11,4,str,2);/*snake health*/
					Print(0,HEIGHT,"撞到障碍物,生命值-1!",12);
				}
			}else
				i = 0;
		}else{
    
			old = GetTickCount();
		}
		if((int)s->hp <= 0) return 0;/*Health is less than or equal to0时,函数返回0*/
	}
	return 1;
}

/*Update snake position*/
int ChangeSnackXY(Snake *s){
    
	int x = s->head->pos.x, y = s->head->pos.y;
	Node *p = s->head->next;
	int vx = 0, vy = 0;
	switch(s->sym){
    
		case UP   : vy = -1; break;
		case DOWN : vy = 1;  break;
		case LEFT : vx = -2; break;
		case RIGHT: vx = 2;  break;
	}
	vx += x;  vy += y;
	if(vx <  1 || vx >= WIDTH - 2 || vy == 0 || vy >= HEIGHT - 1) return 0;/*The snake head hits the border and returns0*/
	while(p != NULL){
    /*The head of the snake meets the body of the snake and returns0*/
		if(p->pos.x == vx && p->pos.y == vy)
			return 0;
		else
			p = p->next;
	}
	if(vx == Food.x && vy == Food.y){
    /*Eat food snakes grow1*/
		SAdd(s);
		return 1;
	}
	p = s->head->next;/*Repoint to the next node of the snake head*/
	s->head->pos.x = vx;/*修改蛇头坐标*/
	s->head->pos.y = vy;
	Print(x,y,SBody,2);/*The old snake head was changed to the body*/
	Print(vx,vy,SHead,2);/*Reposition the snake head*/
	while(p != NULL){
    /*Loop to update the coordinates of each node of the snake*/
		vx = p->pos.x;
		vy = p->pos.y;
		p->pos.x = x;
		p->pos.y = y;
		x = vx; y = vy;
		p = p->next;
	}
	Print(x,y," ",2);/*Erase old snake tail position characters*/
	Sleep(30);/*休眠30毫秒*/
	return 1;
}

/*Snakes grow longer after eating food1*/
void SAdd(Snake *s){
    
	char str[20] = {
    0};
	Node *p;
	if((p = (Node*)malloc(sizeof(Node))) == NULL){
    /*Determine whether the memory allocation was successful*/
		Print(0,0,"分配内存失败,按任意键退出程序!",2);
		system("pause>nul");
		exit(0);
	}
	Print(s->head->pos.x,s->head->pos.y,SBody,2);/*Change the coordinates of the old snake head to the body character*/
	p->pos.x = Food.x;/*Use food as a new snake head*/
	p->pos.y = Food.y;
	p->next = s->head;
	s->head = p;
	s->len++;
	s->score++;
	s->hp += 0.1f;
	_itoa_s((int)s->hp,str,sizeof(str)-1,10);
	Print(WIDTH+11,4,str,2);/*Update snake health*/
	_itoa_s(s->score,str,sizeof(str)-1,10);
	Print(WIDTH+11,6,str,2);/*更新当前得分*/
	Print(p->pos.x,p->pos.y,SHead,2);/*更新蛇头位置*/
	Print(0,HEIGHT,"吃到食物,蛇长+1! ",12);
	randFood(s);/*随机生成食物*/
}

int main(){
    
	SetConsoleTitleA("贪吃蛇游戏");
	/*定义随机数种子*/
	srand((unsigned)time(NULL));
	showMenu();
	return 0;
}

consfun.h——WINDOWSCommand window programming common functions(网上找的,非原创)

#include <windows.h>
#include <wincon.h>

void consinit(short x,short y);
void gotoxy(int,int);
void clrscr(void);
void textcolor(short newcolor);
void textbackground(short newcolor);
void textattr(short newattr);

/* 功能:Initialize the command window,Sets the number of rows and columns of the window 参数:y-行数,x-列数 */
void consinit(short x, short y)
{
      
    COORD scr={
    x,y};
    CONSOLE_SCREEN_BUFFER_INFO info;
	SMALL_RECT rect={
    0,0,x-1,y-1};
	HANDLE stdOut = GetStdHandle(STD_OUTPUT_HANDLE);
	GetConsoleScreenBufferInfo(stdOut,&info);	//Get command window information
	//If the original screen buffer is small, you must first set the new buffer size,Resize the window again
	if(info.dwSize.X*info.dwSize.Y<x*y)			
	{
    	SetConsoleScreenBufferSize(stdOut,scr);
		SetConsoleWindowInfo(stdOut,TRUE,&rect);//An error occurs when the buffer is smaller than needed
	}
	else
	{
    	SetConsoleWindowInfo(stdOut,TRUE,&rect);
		SetConsoleScreenBufferSize(stdOut,scr);	//Setting a value smaller than what is required for the window area will give an error
	}
 	gotoxy(0,0);

}


/* 设置光标位置:Make subsequent output from the screenx行y列输出 参数:x-行(从0开始) y-列(从0开始) */
void gotoxy(int x, int y)
{
    
    COORD Position;
	CONSOLE_CURSOR_INFO cci;
	Position.X=x; Position.Y=y;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),Position);
	GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci); /*获取光标信息*/
    cci.dwSize = 1; 	cci.bVisible =  0;	/*Set cursor size and visibility parameters*/
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);	/*设置(应用)光标信息*/
}

/* 清屏:Clear the screen with the current background color,and position the cursor in the upper left corner(0,0) 参数:无 */
void clrscr(void)
{
    
    COORD scr={
    0,0};
	DWORD num;
	HANDLE stdOut = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_SCREEN_BUFFER_INFO info;
    GetConsoleScreenBufferInfo(stdOut,&info);
	num=info.dwMaximumWindowSize.X*info.dwMaximumWindowSize.Y;
    FillConsoleOutputAttribute(stdOut,(WORD)info.wAttributes,num,scr,&num);
	FillConsoleOutputCharacter(stdOut,' ',num,scr,&num);
	gotoxy(0,0);
}

/* 设置字体颜色:Changes future output font foreground color to given value 参数:newcolor-The new color value The color value range is :0x00 ~ 0x0f */
void textcolor(short newcolor)
{
    
    HANDLE stdOut = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_SCREEN_BUFFER_INFO info;
    GetConsoleScreenBufferInfo(stdOut,&info);
	SetConsoleTextAttribute(stdOut, (WORD)(newcolor|info.wAttributes & 0xF0));
}

/* 设置背景颜色:Changes the background color of subsequent outputs to the given value 参数:newcolor-The new color value The color value range is :0x00 ~ 0x0f */
void textbackground( short newcolor)
{
    
    HANDLE stdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO info;
	GetConsoleScreenBufferInfo(stdOut,&info);
	SetConsoleTextAttribute(stdOut,(WORD)((newcolor<<4)|(info.wAttributes&0x0F)));
}

/* 设置文本属性:Set both foreground and background colors 参数:newattr-新的属性值 The color value range is :0x00 ~ 0xff,低4Bit is the foreground color,高4Bit is the background color */
void textattr(short newattr)
{
    
    HANDLE stdOut = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleTextAttribute(stdOut,newattr);
}

config.h——Contains the snake data structure、Constants and related function declarations

/*Define the entity type tag*/
enum {
    
	EMPTY ,		/*空*/
	FOOD ,		/*食物*/
	SNACK ,		/*蛇*/
};
/*定义Keyboard的键值数据 */
enum {
    
	UP = 72 ,
	DOWN = 80 ,
	LEFT = 75 ,
	RIGHT = 77 ,
	ENTER = 13 ,
	ESC = 27 ,
};

/*Defines the coordinate structure type*/
typedef struct {
    
    short x,y;
}Point;

/*Define the node structure type*/
typedef struct node{
    
    Point pos;  
    struct node *next;  
}Node;

/*Define the snake structure type*/
typedef struct snake{
    
    Node *head;
	short sym;	/*蛇头方向*/
	float hp;	/*生命值*/
    short len;	/*长度*/
	int score;/*分数*/
}Snake;	/*Point to a snake*/

/*Print characters to the specified position*/
int Print(int,int,const char[],short);

/*显示菜单*/
int showMenu();

/*创建地图*/
void showMap();

/*初始化蛇,并打印到屏幕*/
void InitSnake(Snake*,const int);

/*随机生成食物,并打印到屏幕*/
void randFood(const Snake *);

/*控制蛇的移动*/
int SnakeMove(Snake *);

/*Update snake position*/
int ChangeSnackXY(Snake *);

/*Snakes grow longer after eating food1*/
void SAdd(Snake *);
原网站

版权声明
本文为[hash crazy]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/221/202208090724110677.html