#define N 200
#include <graphics.h>
#include <stdlib.h>
#include <dos.h>
#define LEFT 0x4b00
#define RIGHT 0x4d00
#define DOWN 0x5000
#define UP 0x4800
#define ESC 0x011b
int i,key
int score=0/*得分*/
int gamespeed=50000/*游戏速度自己调整*/
struct Food
{
int x/*食物的横坐标*/
int y/*食物的纵坐标*/
int yes/*判断是否要出现食物的变量*/
}food/*食物的 结构 体*/
struct Snake
{
int x[N]
int y[N]
int node/*蛇的节数*/
int direction/*蛇移动方向*/
int life/* 蛇的生命,0活着,1死亡*/
}snake
void Init(void)/*图形驱动*/
void Close(void)/*图形结束*/
void DrawK(void)/*开始画面*/
void GameOver(void)/*结束游戏*/
void GamePlay(void)/*玩游戏具体过程*/
void PrScore(void)/*输出成绩*/
/*主函数*/
void main(void)
{
Init()/*图形驱动*/
DrawK()/*开始画面*/
GamePlay()/*玩游戏具体过程*/
Close()/*图形结束*/
}
/*图形驱动*/
void Init(void)
{
int gd=DETECT,gm
initgraph(&gd,&gm,"c: c")
cleardevice()
}
/*开始画面,左上角坐标为(50,40),右下角坐标为(610,460)的围墙*/
void DrawK(void)
{
/*setbkcolor(LIGHTGREEN)*/
setcolor(11)
setlinestyle(SOLID_LINE,0,THICK_WIDTH)/*设置线型*/
for(i=50i<=600i+=10)/*画围墙*/
{
rectangle(i,40,i+10,49)/*上边*/
rectangle(i,451,i+10,460)/*下边*/
}
for(i=40i<=450i+=10)
{
rectangle(50,i,59,i+10)/*左边*/
rectangle(601,i,610,i+10)/*右边*/
}
}
/*玩游戏具体过程*/
void GamePlay(void)
{
randomize()/*随机数发生器*/
food.yes=1/*1表示需要出现新食物,0表示已经存在食物*/
snake.life=0/*活着*/
snake.direction=1/*方向往右*/
snake.x[0]=100snake.y[0]=100/*蛇头*/
snake.x[1]=110snake.y[1]=100
snake.node=2/*节数*/
PrScore()/*输出得分*/
while(1)/*可以重复玩游戏,压ESC键结束*/
{
while(!kbhit())/*在没有按键的情况下,蛇自己移动身体*/
{
if(food.yes==1)/*需要出现新食物*/
{
food.x=rand()%400+60
food.y=rand()%350+60
while(food.x%10!=0)/*食物随机出现后必须让食物能够在整格内,这样才可以让蛇吃到*/
food.x++
while(food.y%10!=0)
food.y++
food.yes=0/*画面上有食物了*/
}
if(food.yes==0)/*画面上有食物了就要显示*/
{
setcolor(GREEN)
rectangle(food.x,food.y,food.x+10,food.y-10)
}
for(i=snake.node-1i>0i--)/*蛇的每个环节往前移动,也就是贪吃蛇的关键算法*/
{
snake.x[i]=snake.x[i-1]
snake.y[i]=snake.y[i-1]
}
/*1,2,3,4表示右,左,上,下四个方向,通过这个判断来移动蛇头*/
switch(snake.direction)
{
case 1:snake.x[0]+=10break
case 2: snake.x[0]-=10break
case 3: snake.y[0]-=10break
case 4: snake.y[0]+=10break
}
for(i=3i<snake.nodei++)/*从蛇的第四节开始判断是否撞到自己了,因为蛇头为两节,第三节不可能拐过来*/
{
if(snake.x[i]==snake.x[0]&&snake.y[i]==snake.y[0])
{
GameOver()/*显示失败*/
snake.life=1
break } }
if(snake.x[0]<55||snake.x[0]>595||snake.y[0]<55||
snake.y[0]>455)/*蛇是否撞到墙壁*/
{
GameOver()/*本次游戏结束*/
snake.life=1/*蛇死*/
}
if(snake.life==1)/*以上两种判断以后,如果蛇死就跳出内 循环 ,重新开始*/
break
if(snake.x[0]==food.x&&snake.y[0]==food.y)/*吃到食物以后*/
{
setcolor(0)/*把画面上的食物东西去掉*/
rectangle(food.x,food.y,food.x+10,food.y-10)
snake.x[snake.node]=-20snake.y[snake.node]=-20
/*新的一节先放在看不见的位置,下次循环就取前一节的位置*/
snake.node++/*蛇的身体长一节*/
food.yes=1/*画面上需要出现新的食物*/
score+=10
PrScore()/*输出新得分*/
}
setcolor(4)/*画出蛇*/
for(i=0i<snake.nodei++)
rectangle(snake.x[i],snake.y[i],snake.x[i]+10,
snake.y[i]-10)
delay(gamespeed)
setcolor(0)/*用黑色去除蛇的的最后一节*/
rectangle(snake.x[snake.node-1],snake.y[snake.node-1],
snake.x[snake.node-1]+10,snake.y[snake.node-1]-10)
} /*endwhile(!kbhit)*/
if(snake.life==1)/*如果蛇死就跳出循环*/
break
key=bioskey(0)/*接收按键*/
if(key==ESC)/*按ESC键退出*/
break
else
if(key==UP&&snake.direction!=4)
/*判断是否往相反的方向移动*/
snake.direction=3
else
if(key==RIGHT&&snake.direction!=2)
snake.direction=1
else
if(key==LEFT&&snake.direction!=1)
snake.direction=2
else
if(key==DOWN&&snake.direction!=3)
snake.direction=4
}/*endwhile(1)*/
}
/*游戏结束*/
void GameOver(void)
{
cleardevice()
PrScore()
setcolor(RED)
settextstyle(0,0,4)
outtextxy(200,200,"GAME OVER")
getch()
}
/*输出成绩*/
void PrScore(void)
{
char str[10]
setfillstyle(SOLID_FILL,YELLOW)
bar(50,15,220,35)
setcolor(6)
settextstyle(0,0,2)
sprintf(str,"score:%d",score)
outtextxy(55,20,str)
}
/*图形结束*/
void Close(void)
{
getch()
closegraph()
}
基本思路:
蛇每吃一个食物蛇身子就增加一格,用UP, DOWN, LEFT, RIGHT控制蛇头的运动,而蛇身子跟着蛇头走,每后一格蛇身子下一步走到上一格蛇身子的位置,以此类推。
#include <stdio.h>
#include <conio.h>
#include <windows.h>
#define BEG_X 2
#define BEG_Y 1
#define WID 20
#define HEI 20
HANDLE hout
typedef enum {UP, DOWN, LEFT, RIGHT} DIR
typedef struct Snake_body
{
COORD pos//蛇身的位置
struct Snake_body *next//下一个蛇身
struct Snake_body *prev//前一个蛇身
}SNAKE, *PSNAKE
PSNAKE head = NULL//蛇头
PSNAKE tail = NULL//蛇尾
//画游戏边框的函数
void DrawBorder()
{
int i, j
COORD pos = {BEG_X, BEG_Y}
for(i = 0i <HEI++i)
{
SetConsoleCursorPosition(hout, pos)
for(j = 0j <WID++j)
{
if(i == 0)//第一行
{
if(j == 0)
printf("┏")
else if(j == WID - 1)
printf("┓")
else
printf("━")
}
else if(i == HEI - 1)//最后一行
{
if(j == 0)
printf("┗")
else if(j == WID - 1)
printf("┛")
else
printf("━")
}
else if(j == 0 || j == WID - 1)//第一列或最后一列
printf("┃")
else
printf(" ")
}
++pos.Y
}
}
//添加蛇身的函数
void AddBody(COORD pos)
{
PSNAKE pnew = (PSNAKE)calloc(1, sizeof(SNAKE))
pnew->pos = pos
if(!head)
{
head = tail = pnew
}
else
{
pnew->next = head//新创建蛇身的next指向原先的蛇头
head->prev = pnew//原先的蛇头的prev指向新创建的蛇身
head = pnew//把新创建的蛇身作为新的蛇头
}
SetConsoleCursorPosition(hout, head->pos)
printf("◎")
}
//蛇身移动的函数
void MoveBody(DIR dir)
{
PSNAKE ptmp
COORD pos = head->pos
switch(dir)
{
case UP:
if(head->pos.Y >BEG_Y + 1)
--pos.Y
else
return
break
case DOWN:
if(head->pos.Y <BEG_Y + HEI - 2)
++pos.Y
else
return
break
case LEFT:
if(head->pos.X >BEG_X + 2)
pos.X -= 2
else
return
break
case RIGHT:
if(head->pos.X <BEG_X + (WID - 2) * 2)
pos.X += 2
else
return
break
}
AddBody(pos)//添加了一个新的蛇头
ptmp = tail//保存当前的蛇尾
tail = tail->prev
if(tail)
tail->next = NULL
SetConsoleCursorPosition(hout, ptmp->pos)
printf(" ")
free(ptmp)
}
int main()
{
int ctrl
DIR dir = RIGHT//初始蛇的方向是向右的
COORD pos = {BEG_X + 2, BEG_Y + HEI / 2}
system("color 0E")
system("mode con cols=90 lines=30")
hout = GetStdHandle(STD_OUTPUT_HANDLE)
printf(" ------------贪吃蛇的移动------------")
DrawBorder()
//自定义几个蛇的身体
AddBody(pos)
pos.X += 2
AddBody(pos)
pos.X += 2
AddBody(pos)
pos.X += 2
AddBody(pos)
pos.X += 2
AddBody(pos)
pos.X += 2
AddBody(pos)
pos.X += 2
AddBody(pos)
//控制蛇的移动
while(ctrl = getch())
{
switch(ctrl)
{
case 'w':
if(dir == DOWN)
continue
dir = UP
break
case 's':
if(dir == UP)
continue
dir = DOWN
break
case 'a':
if(dir == RIGHT)
continue
dir = LEFT
break
case 'd':
if(dir == LEFT)
continue
dir = RIGHT
break
case 'q':
return 0
}
MoveBody(dir)
}
return 0
}
扩展资料:
实现逻辑
1,可以设置光标,就能实现制定位置打印制定符号。
2,涉及一个结构体,包含两个元素坐标元素和一个结构体指针。
3,结构体串联形成链表,遍历获取成员坐标,打印符号得到蛇身。
4,不断的加头,去尾,重新遍历坐标,再打印形成蛇的移动。
5,食物产生的位置判定,不能越界,也不能与蛇身体重合。
6,蛇的转向判定,一条规则,不允许倒退。
7,转向的实现,跟行进方向决定新的关节坐标(当前头的上下左右)
8,死亡检测,是否头节点坐标是否与墙壁重合,是否与身体其他关节重合。
9,加速减速,设置刷新休眠时间实现。
参考资料来源:百度百科-C语言
C语言贪吃蛇源代码必须经过相应的C/C++编译器编译成EXE文件后才能运行。
由于我们通常使用的操作系统是Windows系统,而在该系统下最长用的C/C++编译器是VC++编译器,目前在大专院校常用的版本还是VC++6.0
下面就以VC++6.0来说明编译过程:
1.在VC++6.0中通过“File”菜单下的 “Open”子菜单打开贪吃蛇代码
2.在VC++6.0中通过“Build”菜单下的 “Compile xxxx.xx”子菜单编译贪吃蛇代码
3.在VC++6.0中通过“Build”菜单下的 “Execute xxxx.exe”子菜单运行贪吃蛇程序
附:在VC++6环境下可运行的C/C++贪吃蛇源代码(无版权,自己编写,欢迎任意修改拷贝)
/*C/C++贪吃蛇游戏,zjlj,2015.3.16
*/
#define DEBUG 0 //当程序在调试阶段时 DEBUG为 1
#include<iostream>
#include<windows.h>
#include<time.h>
#include<conio.h>
using namespace std
void readini(FILE **fphead, int *score, char *argv[]) //创建或打开一个和运行文件对应的ini文件,读取最高纪录
{
char filename[200],*pfilename
int flag=-1,i
strcpy(filename,argv[0])
for(i=0filename[i]!='\0'i++)
{
if ('.'==filename[i])flag=1
}
if(1==flag)
{
filename[i-1]='i'
filename[i-2]='n'
filename[i-3]='i'
}
else
{
filename[i]='.'
filename[i+1]='i'
filename[i+2]='n'
filename[i+3]='i'
filename[i+4]='\0'
}
for(filename[i]!='\\'&&i>=0i--)pfilename=&filename[i]
if ( (*fphead=fopen(pfilename, "rb+"))==NULL)
{
if ( (*fphead=fopen(pfilename, "wb+"))==NULL)
{
printf("无法创建或打开\"%s\"文件\n",pfilename)
system("pause")
exit(0)
}
}
else
{
fread(score,sizeof(int),1,*fphead)
}
}
void writeini(FILE **fphead, int *score, char *argv[]) //打开一个和运行文件对应的ini文件,写入最高纪录
{
char filename[200],*pfilename
int flag=-1,i
strcpy(filename,argv[0])
for(i=0filename[i]!='\0'i++)
{
if ('.'==filename[i])flag=1
}
if(1==flag)
{
filename[i-1]='i'
filename[i-2]='n'
filename[i-3]='i'
}
else
{
filename[i]='.'
filename[i+1]='i'
filename[i+2]='n'
filename[i+3]='i'
filename[i+4]='\0'
}
for(filename[i]!='\\'&&i>=0i--)pfilename=&filename[i]
if ( (*fphead=fopen(pfilename, "wb+"))==NULL)
{
printf("无法写入\"%s\"文件,磁盘写保护!\n",pfilename)
system("pause")
exit(0)
}
else
{
rewind(*fphead)
fwrite(score,sizeof(int),1,*fphead)
fclose(*fphead)
}
}
void gotoxy(int x,int y)//光标定位,光标定位函数SetConsoleCursorPosition是左上角位置是0,0然后向左向下延伸
{
COORD pos
pos.X=2*y
pos.Y=x
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos)
}
void color(int a)//颜色函数
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),a)
}
void Refresh(int q[][22], int grade, int gamespeed, int length,int score) // 输出贪吃蛇棋盘
{
int i,j
for(i=0i<22i++)
{
for(j=0j<22j++)
{
if(q[i][j]==0)//输出棋盘空白
{
gotoxy(i,j)
color(11)
cout<<"■"
}
if(q[i][j]==1||q[i][j]==2)//输出棋盘墙壁
{
gotoxy(i,j)
color(11)
cout<<"□"
}
if(q[i][j]==3)//输出蛇头
{
gotoxy(i,j)
color(14)
cout<<"★"
}
if(q[i][j]==4)//输出蛇身
{
gotoxy(i,j)
color(12)
cout<<"◆"
}
if(q[i][j]==5)//输出果子
{
gotoxy(i,j)
color(12)
cout<<"●"
}
}
if(i==0) cout << "\t***********************"
if(i==1) cout << "\t等级为:" << grade//显示等级
if(i==3) cout << "\t自动前进时间"
if(i==4) cout << "\t间隔为:" << gamespeed << "ms"//显示时间
if(i==6) cout << "\t历史最高分为:" << score << "分"
if(i==7) cout << "\t你现在得分为:" << (length+(grade-1)*8)*10 << "分"
if(i==8) cout << "\t**********************"
if(i==9) cout << "\t游戏说明:"
if(i==10) cout << "\t(1)用小键盘方向键控制"
if(i==11) cout << "\t蛇头运动方向"
if(i==12) cout << "\t(2)蛇每吃一个果子蛇身"
if(i==13) cout << "\t增加一节"
if(i==14) cout << "\t(3)蛇咬到自己或碰到墙"
if(i==15) cout << "\t壁游戏结束。"
if(i==18) cout << "\t**********************"
if(i==19) cout << "\tC/C++语言作业:"
if(i==20) cout << "\tzjlj,2015.03.16 "
}
}
int main(int argc, char *argv[]){
int tcsQipan[22][22] // 贪吃蛇棋盘是一个二维数组(如22*22,包括墙壁)
int i,j,score,directiontemp
FILE *fpini//*fpini 信息文件
readini(&fpini, &score, argv)//读取ini文件的最高纪录
if (score<0)//最高成绩小于零设置为零,初建文件会是负数
score=0
while(1)
{
for(i=1i<=20i++)
for(j=1j<=20j++)
tcsQipan[i][j]=0 //贪吃蛇棋盘相应坐标标上中间空白部分的标志0
for(i=0i<=21i++)
tcsQipan[0][i] = tcsQipan[21][i] = 1 //贪吃蛇棋盘相应坐标标上上下墙壁的标志1
for(i=1i<=20i++)
tcsQipan[i][0] = tcsQipan[i][21] = 2 //贪吃蛇棋盘相应坐标标上左右墙壁的标志2
int tcsZuobiao[2][500] //蛇的坐标数组
for(i=0 i<4 i++)
{
tcsZuobiao[0][i] = 1//蛇身和蛇头的x坐标
tcsZuobiao[1][i] = i + 1//蛇身和蛇头的y坐标
}
int head = 3,tail = 0//标示蛇头和蛇尾的数组偏移量
for(i=1i<=3i++)
tcsQipan[1][i]=4 //蛇身
tcsQipan[1][4]=3 //蛇头
int x1, y1 // 随机出果子
srand(time(0))//设置随机种子
do
{
x1=rand()%20+1
y1=rand()%20+1
}
while(tcsQipan[x1][y1]!=0)//如果不是在空白处重新出果子
tcsQipan[x1][y1]=5//贪吃蛇棋盘相应坐标标上果子的标志5
color(12)
cout<<"\n\n\t\t\t\t贪吃蛇游戏即将开始 !"<<endl//准备开始
long start,starttemp
int grade = 1, length = 4 //设置初始等级和蛇的初始长度
int gamespeed = 500 //设置初始前进时间间隔
for(i=3i>=0i--)
{
start=clock()
while(clock()-start<=1000)
system("cls")
if(i>0)
cout << "\n\n\t\t\t\t进入倒计时:" << i << endl //倒计时显示
else
Refresh(tcsQipan,grade,gamespeed,length,score) //初始棋盘显示
}
int timeover=1,otherkey=1//初始化超时时间和按键判断参数
char direction = 77 // 设置初始情况下,向右运动
int x=tcsZuobiao[0][head],y=tcsZuobiao[1][head]//保存蛇头坐标到x,y变量
while(1)//运行一局游戏
{
start = clock()
while((timeover=((starttemp=clock())-start<=gamespeed))&&!kbhit())//如果有键按下或时间超过自动前进时间间隔则终止循环
if(direction==72||direction==80||direction==75 ||direction==77)
directiontemp=direction//保留上一次方向按键
//starttemp=gamespeed+start-starttemp//保留停留时间
if(timeover)
{
#if (DEBUG==1)
direction = getch()//调试代码
#else
if((direction =getch())==-32)
direction = getch()
#endif
}
#if (DEBUG==1)//调试代码
start=clock()
while(clock()-start<=2000)
gotoxy(24,4)
cout << "\t按键ASCII代码"<<(int)direction<<" "<<endl
#endif
if(!(direction==72||direction==80||direction==75 ||direction==77))
{
otherkey=0// 按键非方向键,otherkey设置为0
}
else
{
otherkey=1// 按键为方向键,otherkey设置为1
}
if(direction==72 && directiontemp==80)//忽略反方向按键
{
direction=32
otherkey=0
//start = clock()
//while(clock()-start<=starttemp)
}
else if(direction==80 && directiontemp==72)
{
direction=32//设置按键为非方向键
otherkey=0// 按键为非方向键,otherkey设置为0
// start = clock()
//while(clock()-start<=starttemp)//补偿等待时间
}
else if(direction==75 && directiontemp==77)
{
direction=32
otherkey=0
//start = clock()
//while(clock()-start<=starttemp)
}
else if(direction==77 && directiontemp==75)
{
direction=32
otherkey=0
//start = clock()
//while(clock()-start<=starttemp)
}
switch(direction)//判断方向键
{
case 72: x= tcsZuobiao[0][head]-1 y= tcsZuobiao[1][head]break // 向上
case 80: x= tcsZuobiao[0][head]+1 y= tcsZuobiao[1][head]break // 向下
case 75: x= tcsZuobiao[0][head] y= tcsZuobiao[1][head]-1break // 向左
case 77: x= tcsZuobiao[0][head] y= tcsZuobiao[1][head]+1break // 向右
default: break
}
if(x==0 || x==21 ||y==0 || y==21) // 蛇头碰到墙壁,结束本局游戏
{
gotoxy(22,12)
cout << "\t游戏已结束!" << endl
if(score>=(length+(grade-1)*8)*10)//判断是否破记录
{
gotoxy(10,7)
color(12)
cout << "闯关失败 加油耶!" << endl
fclose(fpini)//关闭ini文件
}
else
{
gotoxy(10,7)
color(12)
cout << "恭喜您打破记录" << endl
score=(length+(grade-1)*8)*10
writeini(&fpini, &score, argv)//写入ini文件的最高纪录
}
gotoxy(23,12)
cout << "按回车键重新开始,按ESC退出游戏" << endl//显示的提示
break//退出该局游戏
}
if(tcsQipan[x][y]!=0&&!(x==x1&&y==y1)&&tcsQipan[x][y]!=3) // 蛇头碰到蛇身,结束本局游戏
{
gotoxy(22,12)
cout << "\t游戏已结束!" << endl
if(score>=(length+(grade-1)*8)*10)//判断是否破记录
{
gotoxy(10,7)
color(12)
cout << "闯关失败 加油耶!" << endl
fclose(fpini)//关闭ini文件
}
else
{
gotoxy(10,7)
color(12)
cout << "恭喜您打破记录" << endl
score=(length+(grade-1)*8)*10
writeini(&fpini, &score, argv)//写入ini文件的最高纪录
}
gotoxy(23,12)
cout << "按回车键重新开始,按ESC退出游戏" << endl//显示的提示
break//退出该局游戏
}
/*
游戏运行时的核心算法开始
*/
if(x==x1 && y==y1) // 吃果子,长度加1
{
length ++
if(length>=8)//长度大于等于8重新计算长度,等级加1
{
length -= 8//重新计算长度
grade ++//等级加1
if(gamespeed>50)//控制最快速度为50
gamespeed = 550 - grade * 50 // 改变自动前进时间间隔
}
tcsQipan[x][y]= 3//贪吃蛇棋盘相应坐标现在蛇头标志改为蛇头标志3
tcsQipan[tcsZuobiao[0][head]][tcsZuobiao[1][head]] = 4//贪吃蛇棋盘相应坐标原来蛇头标志改为蛇身标志4
head = (head+1)%400//防止数组越界
tcsZuobiao[0][head] = x//蛇头的x坐标
tcsZuobiao[1][head] = y//蛇头的y坐标
do//随机出果子
{
x1=rand()%20+1
y1=rand()%20+1
}
while(tcsQipan[x1][y1]!=0)//如果不是在空白处重新出果子
tcsQipan[x1][y1]=5//贪吃蛇棋盘相应坐标标上果子的标志5
gotoxy(22,12)
cout << "\t游戏进行中!" << endl
Refresh(tcsQipan,grade,gamespeed,length,score)
}
else // 不吃果子
{
if(otherkey)
{
tcsQipan [tcsZuobiao[0][tail]][tcsZuobiao[1][tail]]=0
tail=(tail+1)%400//防止数组越界
tcsQipan [tcsZuobiao[0][head]][tcsZuobiao[1][head]]=4
head=(head+1)%400//防止数组越界
tcsZuobiao[0][head]=x//蛇头的x坐标
tcsZuobiao[1][head]=y//蛇头的y坐标
tcsQipan[tcsZuobiao[0][head]][tcsZuobiao[1][head]]=3
gotoxy(22,12)
cout << "\t游戏进行中!" << endl
Refresh(tcsQipan,grade,gamespeed,length,score)
}
else
{
gotoxy(22,12)
cout << "\t游戏暂停中!" << endl
}
}
/*
游戏运行时的核心算法结束
*/
}
while(1)
{
while(!kbhit())
if((direction =getch())==13)//按回车键开始下一局
break
if(direction ==27)//按ESC退出游戏
exit(0)
}
system("cls")//清除屏幕重新开始
}
return 0
}