一、游戏界面
二、代码
consfun.h
/* WINDOWS命令窗口编程常用功能实现
李乾宝,2010年12月
*/
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);
void HideCursor();
snake.c
#include"consfun.h"
#include<conio.h>
#include<stdio.h>
#include<Windows.h>
#include<time.h>
#define UP 72
#define DOWN 80
#define LEFT 75
#define RIGHT 77
int i,j;
int mode=0; //游戏模式
int n=4; //n=1,2,3,4分别表示用户控制蛇的方向
int food_sum=0; //累计吃的食物
int food=0; //食物
int fx=5,fy=5; //事物的坐标
int score=0; //分数
int top_score[3]; //最高分
int speed=200; //蛇的速度
int Mode=1; //是否可以穿墙,1不可穿墙,2可以
#define high 28
#define width 45 //围墙的高和宽
int x=high/2,y=width/2; //蛇头的坐标
int snake[high][width+10]={0};//用来储存蛇,围墙,食物
void gx() //蛇数组元素全部归0
{
for(i=1;i<high-1;i++)
for(j=1;j<width-1;j++)
snake[i][j]=0;
}
void chu_shi_hua() //每次重新开始,数据数据都要初始化
{
n=4; //n=1,2,3,4分别表示用户控制蛇的方向
food_sum=0; //累计吃的食物
food=0; //食物
fx=5,fy=5; //食物的坐标
score=0; //分数
speed=300; //蛇的速度(这个越大越慢)
Mode=1; //游戏模式
x=high/2,y=width/2; //蛇头的坐标
switch(mode)
{
case 1:for(j=5;j<width-5;j++)//基本围墙已经在page_1函数初始化,所以只需初始化新增的墙壁
{
snake[high/2-1][j]=-1;
};break;
case 2:for(j=10;j<=width-10;j++)//基本围墙已经在page_1函数初始化,所以只需初始化新增的墙壁
{
if(j<20||j>25)
{
snake[high/4][j]=-1;
snake[3*high/4][j]=-1;
}
}
for(i=high/4;i<=3*high/4;i++)
{
if(i<high/4+5||i>3*high/4-5)
{
snake[i][10]=-1;
snake[i][width-10]=-1;
}
};break;
case 3:for(j=3;j<=width-3;j++)//基本围墙已经在page_1函数初始化,所以只需初始化新增的墙壁
{
if((j>=3&&j<=6)||(j>=width-7&&j<=width-4))//初始化四个角的四个横
{
snake[6][j]=-1;
snake[high-7][j]=-1;
}
if((j>=width/4&&j<=width/4+6)||(j>=3*width/4-8&&j<=3*width/4))//初始化‘F’的第一横和‘T’的横
{
snake[8][j]=-1;
}
if((j>=width/4&&j<=width/4+6))//初始化‘F’的第二横
{
snake[high/2-1][j]=-1;
}
}
for(i=3;i<=high-3;i++)
{
if((i>=3&&i<=6)||(i>=high-6&&i<high-3))//初始化四个角的四个竖
{
snake[i][6]=-1;
snake[i][width-7]=-1;
}
if(i>=8&&i<=high-8)//初始化‘F’的竖
{
snake[i][width/4]=-1;
}
if(i>=8&&i<=high-8&&i!=high/2)//初始化‘T’的竖
{
snake[i][3*width/4-4]=-1;
}
};break;
case 4:for(j=3;j<=width-3;j++)//基本围墙已经在page_1函数初始化,所以只需初始化新增的墙壁
{
if((j>=3&&j<=6)||(j>=width-7&&j<=width-4))//初始化四个角的四个横
{
snake[6][j]=-1;
snake[high-7][j]=-1;
}
}
for(i=3;i<=high-3;i++)
{
if((i>=3&&i<=6)||(i>=high-6&&i<high-3))//初始化四个角的四个竖
{
snake[i][6]=-1;
snake[i][width-7]=-1;
}
}
for(i=0;i<high;i++)
for(j=0;j<width;j++)
{
if(i==high/2+1&&(j==width/2-2||j==width/2))//鼻子
{
snake[i][j]=-1;
}
if(i==high/2-1&&j==width/2-1)//鼻子
{
snake[i][j]=-1;
}
if(i==high/2-4&&(j==width/2-3||j==width/2+1||j==width/2-6||j==width/2+4))//眉毛
{
snake[i][j]=-1;
}
if(i==high/2-5&&(j==width/2-4||j==width/2+2))
{
snake[i][j]=-1;
}
if(i==high/2-6&&(j==width/2-5||j==width/2+3))
{
snake[i][j]=-1;
}
if(i==high/2-7&&(j==width/2-6||j==width/2+4))
{
snake[i][j]=-1;
}
if(i==high/2-8&&(j==width/2-7||j==width/2+5||j==width/2-9||j==width/2+7))
{
snake[i][j]=-1;
}
if(i==high/2-9&&(j==width/2-8||j==width/2+6))
{
snake[i][j]=-1;
}
if(i==high/2+4&&j>=width/2-4&&j<=width/2+2)//嘴巴
{
snake[i][j]=-1;
}
if(i==high/2+5&&j>=width/2-2&&j<=width/2)//嘴巴
{
snake[i][j]=-1;
}
}
;break;
}
snake[high/2][width/2]=1; //以下将蛇头数值设为1
for(i=1;i<5+food_sum;i++) //以下将蛇身数值设为>1
snake[high/2][width/2-i]=1+i;
}
void page_1()首页,功能选择页
{
char input,*p[5]={" ","简单","困难","复杂","开挂"};
gx();///将数组全部元素归0,因为在选择重新开始的时候要将游戏区内容清除
for(j=0;j<width+10;j++) //以下将围墙数值设为-1
{
snake[0][j]=-1;
snake[high-1][j]=-1;
}
for(i=0;i<high;i++)
{
snake[i][0]=-1;
snake[i][width-1]=-1;
snake[i][width+9]=-1;
}
while(1)
{
for(i=0;i<high;i++)
for(j=0;j<width+10;j++)
{
if(snake[i][j]==-1) //画出围墙
{
textbackground(3);
gotoxy(i,2*j);
printf(" ");
}
if(i==high/2-6&&j==width/2-7)
{textattr(06);
gotoxy(i,2*j);
printf("@@");
textattr(32);
printf(" ");}
if(i==high/2-3&&j==width/2-5)
{textattr(03);
gotoxy(i,2*j);
printf("欢迎来到贪吃蛇游戏!");}
if(i==high/2-1&&j==width/2-2)
{textattr(03);
gotoxy(i,2*j);
printf("1.简单");}
if(i==high/2&&j==width/2-2)
{textattr(03);
gotoxy(i,2*j);
printf("2.困难");}
if(i==high/2+1&&j==width/2-2)
{textattr(03);
gotoxy(i,2*j);
printf("3.复杂");}
if(i==high/2+2&&j==width/2-2)
{textattr(03);
gotoxy(i,2*j);
printf("4.开挂");}
if(i==high/2+4&&j==width/2-5)
{textattr(06);
gotoxy(i,2*j);
printf("你选择的模式是:%s",p[mode]);}
if(i==high/2+6&&j==width/2-5)
{textattr(03);
gotoxy(i,2*j);
printf("请按回车开始游戏");}
}
if(kbhit())//当按键时执行
{
input=getch();
if(input=='1')
{mode=1;}
if(input=='2')
{mode=2;}
if(input=='3')
{mode=3;}
if(input=='4')
{mode=4;}
if(input==13)13是回车的ASCII码,按回车开始游戏
{break;}
}
}
}
void draw() //画围墙、蛇、食物
{
while(food==0&&snake[fx][fy]!=0)//当食物生成的位置不是空位置,重新生成
{
fx=rand()%(high-1)+1;
fy=rand()%(width-2)+2;
}
snake[fx][fy]=-2;
food=1;
for(i=0;i<high;i++)
for(j=0;j<width+10;j++)
{
if(snake[i][j]==-1) //画出围墙
{
textbackground(3);
gotoxy(i,2*j);
printf(" ");
}
else if(snake[i][j]==0&&j<width) //画出空白的空间
{
textattr(03);
gotoxy(i,2*j);
printf(" ");
}
else if(snake[i][j]==1) //画出蛇头
{
textattr(06);
gotoxy(i,2*j);
printf("@@");
}
else if(snake[i][j]>1) //画出蛇身
{
textattr(06);
textbackground(2);
gotoxy(i,2*j);
printf(" ");
}
else if(snake[i][j]==-2)
{
textcolor(06);
gotoxy(fx,2*fy);
printf("●");
}
if(i==2&&j==width+2)
{textattr(03);
gotoxy(i,2*j);
printf("w或↑键向上");}
if(i==4&&j==width+2)
{textattr(03);
gotoxy(i,2*j);
printf("s或↓键向下");}
if(i==6&&j==width+2)
{textattr(03);
gotoxy(i,2*j);
printf("a或←键向左");}
if(i==8&&j==width+2)
{textattr(03);
gotoxy(i,2*j);
printf("d或→键向右");}
if(i==10&&j==width+2)
{textattr(03);
gotoxy(i,2*j);
printf("空格键暂停");}
if(i==12&&j==width+2)
{textattr(03);
gotoxy(i,2*j);
printf("p键:慢");}
if(i==14&&j==width+2)
{textattr(03);
gotoxy(i,2*j);
printf("l键:中");}
if(i==16&&j==width+2)
{textattr(03);
gotoxy(i,2*j);
printf("m键:快");}
if(i==18&&j==width+2)
{textattr(03);
gotoxy(i,2*j);
printf("t键:模式1");
}
if(i==20&&j==width+1)
{textattr(03);
gotoxy(i,2*j);
printf("y键:模式2(穿墙)");
}
if(i==22&&j==width+2)
{textattr(07);
gotoxy(i,2*j);
printf("当前模式:%d",Mode);}
if(i==24&&j==width+2)
{textattr(03);
gotoxy(i,2*j);
printf("当前分数:");
textattr(06);
gotoxy(i,2*j+9);
printf("%d",score);
}
}
}
void move()
{
FILE *fp; //文件指针,用于读取最高分和保存最高分
int max=0;
int oldTail_i,oldTail_j;//旧尾巴的位置
int oldHead_i,oldHead_j;//旧蛇头的位置
int newHead_i,newHead_j;//新蛇头的位置
char input;
for(i=1;i<high-1;i++) //让蛇的每一节数字加一
for(j=1;j<width-1;j++)
{
if(snake[i][j]>0)
{
snake[i][j]++;
if(max<snake[i][j])//让数字最大的一节变0
{
max=snake[i][j];
//snake[i][j]=0;/
oldTail_i=i;
oldTail_j=j;
}
if(snake[i][j]==2)
{
oldHead_i=i;
oldHead_j=j;
}
}
}
if(kbhit())//当按键时执行
{
input=getch();
if((input=='w'||input==72)&&n!=2) //正在向上走,就不能执行向下
{n=1;}
if((input=='s'||input==80)&&n!=1)
{n=2;}
if((input=='a'||input==75)&&n!=4)
{n=3;}
if((input=='d'||input==77)&&n!=3)
{n=4;}
if(input=='p')
{speed=200;}
if(input=='l')
{speed=100;}
if(input=='m')
{speed=0;}
if(input=='t')
{Mode=1;}
if(input=='y')
{Mode=2;}
if(input==' ')
{while(1)
{
if(kbhit()!=0)
break;
}
}
if(input==27)//27为Esc键的ASCII码
{textattr(00);
system("pause");
}
}
if(n==1)
{
newHead_i=oldHead_i-1;newHead_j=oldHead_j;
}
if(n==2)
{
newHead_i=oldHead_i+1;newHead_j=oldHead_j;
}
if(n==3)
{
newHead_i=oldHead_i;newHead_j=oldHead_j-1;
}
if(n==4)
{
newHead_i=oldHead_i;newHead_j=oldHead_j+1;
}
if(snake[newHead_i][newHead_j]==-2) //如果没有吃到食物,蛇的最后一节变为0,否则不变(即蛇的长度+1)
{
food=0;
food_sum++;
score++;
}
else switch(Mode)
{
case 1:if(snake[newHead_i][newHead_j]>1||snake[newHead_i][newHead_j]==-1) //模式1,不能穿墙
{
fp=fopen("top_score.dat","wb+");
fseek(fp,4*(mode-1),1);
fread(&top_score[mode-1],sizeof(int),1,fp);
if(score>top_score[mode-1])
top_score[mode-1]=score;
fwrite(&top_score[mode-1],sizeof(int),1,fp);
while(1)
{
textattr(03);
gotoxy(high/2,width-7);
printf("GAME OVER!");
gotoxy(high/2+1,width-8);
printf("按r键重新开始");
gotoxy(high/2+2,width-8);
printf("按b键退出游戏");
textattr(06);
gotoxy(high/2+4,width-10);
printf("历史最高分:%d 你的分数:%d",top_score[mode-1],score);
if(kbhit())//当按键时执行
{
input=getch();
if(input=='r')
main();
if(input=='b')
{
gotoxy(high/2+4,width-8);
exit(0);
}
}
}
}
else snake[oldTail_i][oldTail_j]=0;/如果没有吃到食物,蛇的最后一节变为0,否则不变(即蛇的长度+1)
break;
case 2:if(snake[newHead_i][newHead_j]==-1&&n==1) //模式2,可以穿墙
{newHead_i=high-2;}
else if(snake[newHead_i][newHead_j]==-1&&n==2)
{newHead_i=1;}
else if(snake[newHead_i][newHead_j]==-1&&n==3)
{newHead_j=width-2;}
else if(snake[newHead_i][newHead_j]==-1&&n==4)
{newHead_j=1;}
else if(snake[newHead_i][newHead_j]>1)
{
fp=fopen("top_score.dat","wb+");
fseek(fp,4*(mode-1),1);
fread(&top_score[mode-1],sizeof(int),1,fp);
if(score>top_score[mode-1])
top_score[mode-1]=score;
fwrite(&top_score[mode-1],sizeof(int),1,fp);
while(1)
{
textattr(03);
gotoxy(high/2,width-7);
printf("GAME OVER!");
gotoxy(high/2+1,width-8);
printf("按r键重新开始");
gotoxy(high/2+2,width-8);
printf("按b键退出游戏");
textattr(06);
gotoxy(high/2+4,width-10);
printf("最高分:%d 你的分数:%d",top_score[mode-1],score);
if(kbhit())//当按键时执行
{
input=getch();
if(input=='r')
main();
if(input=='b')
{
gotoxy(high/2+4,width-8);
exit(0);
}
}
}
}
else snake[oldTail_i][oldTail_j]=0;/如果没有吃到食物,蛇的最后一节变为0,否则不变(即蛇的长度+1)
break;
}
snake[newHead_i][newHead_j]=1;
}
int main()
{
system("cls");
HideCursor();
srand((unsigned int)time(0));
system("title 贪吃蛇");
system("mode con cols=110 lines=28");//设定窗口大小
SetWindowLong(GetConsoleWindow(),GWL_STYLE,GetWindowLong(GetConsoleWindow(),GWL_STYLE) & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX);
page_1(); //将page_1函数放在chu_shi_hua()函数前,待用户选择游戏模式再对数组进行初始化
chu_shi_hua(); //数据初始化
while(1)///游戏循环
{
Sleep(speed);
draw();
move();
textattr(03);
}
return 0;
}
consfun.c
/* WINDOWS命令窗口编程常用功能
程序设计:李乾宝
修改时间:2010年12月--2017年1月
*/
#include <windows.h>
#include <wincon.h>
/* 设置光标位置:使后续的输出从屏幕的x行y列输出
参数:x-行(从0开始)
y-列(从0开始)
*/
void gotoxy(int x, int y)
{
COORD Position;
Position.X=y; Position.Y=x;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),Position);
}
/* 功能:初始化命令窗口,设置窗口的行列数
参数: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); //获取命令窗口信息
//如果原屏缓冲区小必须先设置新的缓冲区大小,再调整窗口大小
if(info.dwSize.X*info.dwSize.Y<x*y)
{ SetConsoleScreenBufferSize(stdOut,scr);
SetConsoleWindowInfo(stdOut,TRUE,&rect);//缓冲区比需要的小时会出错
}
else
{ SetConsoleWindowInfo(stdOut,TRUE,&rect);
SetConsoleScreenBufferSize(stdOut,scr); //设置值比窗口区域需要的小时会出错
}
gotoxy(0,0);
}
/* 清屏:用当前的背景颜色清除屏幕,并将光标定位在左上角(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);
}
/* 设置字体颜色:使以后的输出字体前景颜色改为给定值
参数:newcolor-新的颜色值
颜色取值范围为: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));
}
/* 设置背景颜色:使以后的输出的背景颜色改为给定值
参数:newcolor-新的颜色值
颜色取值范围为: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)));
}
/* 设置文本属性:同时设定前景和背景颜色
参数:newattr-新的属性值
颜色取值范围为:0x00 ~ 0xff,低4位为前景颜色,高4位为背景颜色
*/
void textattr(short newattr)
{
HANDLE stdOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(stdOut,newattr);
}
void HideCursor() //隐藏光标的函数,网上搜的,需加头文件<windows.h>
{CONSOLE_CURSOR_INFO cursor_info={1,0};
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}
上面的头函数和窗口编程代码系汕大李乾宝老师所编写,我写的是snake.c 。snake.c 是大一期末熬一个通宵码的代码,比较冗长,不过勉强可以玩一下,我懒得改啦~,哈哈哈感兴趣的小伙伴可以对代码进行模块化以及相应的删改优化。