C/C++贪吃蛇游戏
首先我讲一下我写该游戏的思路
1.界面设计
可以利用数字0,1,2,3,
用0表示边界,接触边界便会死亡
用1表示可移动的区域范围
用2表示蛇的身体(有需要的可以单独给蛇头设置其他数字)
用3表示食物
那么,我们就能用二位数组将界面给表示出来,这里创建一个全局变量
int show[N][N]={
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
void menu(int a[][N])
{
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
if(a[i][j]==0)
{
set_color(10);
cout <<"□";
}
if(a[i][j]==1)
{
set_color(9);
cout <<"■";
}
if(a[i][j]==2)
{
set_color(4);
cout <<"●";
}
if(a[i][j]==3)
{
set_color(14);
cout <<"★";
}
}
cout <<"\n";
}
}
2.颜色函数与坐标函数
// color(0); printf("黑色\n");
// color(1); printf("蓝色\n");
// color(2); printf("绿色\n");
// color(3); printf("湖蓝色\n");
// color(4); printf("红色\n");
// color(5); printf("紫色\n");
// color(6); printf("黄色\n");
// color(7); printf("白色\n");
// color(8); printf("灰色\n");
// color(9); printf("淡蓝色\n");
// color(10); printf("淡绿色\n");
// color(11); printf("淡浅绿色\n");
// color(12); printf("淡红色\n");
// color(13); printf("淡紫色\n");
// color(14); printf("淡黄色\n");
// color(15); printf("亮白色\n");
// color(16); //因为这里大于15,恢复默认的颜色
void set_color(int x)
{
HANDLE winHandle;
winHandle = GetStdHandle((STD_OUTPUT_HANDLE)) ;//用来修改命令行窗口的颜色
SetConsoleTextAttribute(winHandle,x) ;
}
//坐标函数
void set_position(int x,int y)
{
HANDLE winHandle; //句柄
COORD pos={x,y}; //定义一个位置
winHandle=GetStdHandle(STD_OUTPUT_HANDLE); //将控制台窗口赋值给定义的句柄
SetConsoleCursorPosition(winHandle,pos); //设置光标位置
}
3.存储蛇的信息
我采用的是链表的方式
typedef struct _snake
{
int x;
int y;
struct _snake *next;
}Snake;
4.蛇的移动与显示
在给代码之前我讲下思路
利用键值
使用while()函数使得蛇能一直移动,除非给出另一个键值
key=getch(); //按下按键//119 上 115下 97左 100右 ASCII码值
当时我碰到了两个问题
(1)每次我按下键值后蛇只移动一下,如果我让它一直移动的话就会无法接收我输入的下一个命令
解决:查阅一些资料后,我学到了一个非常适合这种情况的函数kbhit(),只要不操作就为假,只要按了按键就为真
头文件为:#include <conio.h>
if(kbhit())
{
key=getch();
}
(2)要实现蛇往下之后就不能在往上走,往左走之后就不能往右走,于是我设置了char key2来代表上一个输入的键值,但是还是无法实现想要的效果,它会中途暂停,然后在走就不按照我的想法
解决:首先将先前key赋值给key2,然后重新给key赋值
if(kbhit())
{
key2=key;
key=getch();
}
如果重新输入的值与上次相反,既先上后下,先左后右,先下后上,先右后左,这些都是要不操作的,可以运行以下代码
key=key2;
continue;
5.其他函数
比如,
触碰边界
触碰本身
吃下食物
显示分数以及其他数据
全部代码:
没有写很多注释,又不懂的可以参考链表的增删改查操作,万变不离其中,只要能实现功能就行
#include <iostream>
#include <windows.h>
#include <mmsystem.h>
#pragma comment(lib,"Winmm.lib")
#define N 25 //定义游戏边界
#include <time.h>
#include <strings.h>
#include <conio.h>
using namespace std;
int score; //得分
int longs=3; //蛇的长度
int c,d; //食物坐标
char key,key2; //移动方向
//颜色函数
// color(0); printf("黑色\n");
// color(1); printf("蓝色\n");
// color(2); printf("绿色\n");
// color(3); printf("湖蓝色\n");
// color(4); printf("红色\n");
// color(5); printf("紫色\n");
// color(6); printf("黄色\n");
// color(7); printf("白色\n");
// color(8); printf("灰色\n");
// color(9); printf("淡蓝色\n");
// color(10); printf("淡绿色\n");
// color(11); printf("淡浅绿色\n");
// color(12); printf("淡红色\n");
// color(13); printf("淡紫色\n");
// color(14); printf("淡黄色\n");
// color(15); printf("亮白色\n");
// color(16); //因为这里大于15,恢复默认的颜色
void set_color(int x)
{
HANDLE winHandle;
winHandle = GetStdHandle((STD_OUTPUT_HANDLE)) ;//用来修改命令行窗口的颜色
SetConsoleTextAttribute(winHandle,x) ;
}
//坐标函数
void set_position(int x,int y)
{
HANDLE winHandle; //句柄
COORD pos={x,y}; //定义一个位置
winHandle=GetStdHandle(STD_OUTPUT_HANDLE); //将控制台窗口赋值给定义的句柄
SetConsoleCursorPosition(winHandle,pos); //设置光标位置
}
typedef struct _snake
{
int x;
int y;
struct _snake *next;
}Snake;
//界面函数
//定义数组,用0表示边界,1表示背景,2表示蛇本体,3表示食物
void menu(int a[][N])
{
set_position(0,0);
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
if(a[i][j]==0)
{
set_color(10);
cout <<"□";
}
if(a[i][j]==1)
{
set_color(9);
cout <<"■";
}
if(a[i][j]==2)
{
set_color(4);
cout <<"●";
}
if(a[i][j]==3)
{
set_color(14);
cout <<"★";
}
}
cout <<"\n";
}
set_position(62,10);
set_color(5);
cout <<score;
set_position(0,0);
}
//界面数组
int show[N][N]={
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
//游戏内容界面数组
void imformation()
{
set_position(55,1);
set_color(4);
cout <<"游戏名称:吞星蟒之路";
set_position(55,5);
set_color(6);
cout <<"W、S、A、D控制上下左右移动";
set_position(55,10);
set_color(5);
cout <<"分数:";
}
//蛇碰壁结束函数
void death(Snake *head)
{
if(head->x==0||head->x==24||head->y==0||head->y==24)
{
set_position(55,15);
set_color(4);
cout <<"游戏结束!得分"<<score<<"分";
set_position(55,26);
exit(0);
}
}
//蛇吃到自己
void eat_self(Snake *head)
{
Snake *p;
p=head->next;
for(int i=0;i<longs-1;i++)
{
if(p->x==head->x&&p->y==head->y)
{
set_position(55,15);
set_color(4);
cout <<"游戏结束!得分"<<score<<"分";
set_position(55,26);
exit(0);
}
p=p->next;
}
}
//吃下食物
void eats(Snake *head)
{
srand((unsigned)time(NULL));
Snake *p,*q;
if(head->x==c&&head->y==d)
{
score+=10;
p=head;
for(int i=0;i<longs-1;i++)
{
p=p->next;
if(p->next==NULL)
{
if(key==119)
{
q=new Snake;
q->x=p->x+1;
q->y=p->y;
q->next=NULL;
p->next=q;
p=q;
show[p->x][p->y]=2;
}
else if(key==115)
{
q=new Snake;
q->x=p->x-1;
q->y=p->y;
q->next=NULL;
p->next=q;
p=q;
show[p->x][p->y]=2;
}
else if(key==97)
{
q=new Snake;
q->x=p->x;
q->y=p->y+1;
q->next=NULL;
p->next=q;
p=q;
show[p->x][p->y]=2;
}
else if(key==100)
{
q=new Snake;
q->x=p->x;
q->y=p->y-1;
q->next=NULL;
p->next=q;
p=q;
show[p->x][p->y]=2;
}
}
}
longs++;
c=rand()%22+1;
d=rand()%22+1;
while(c==head->x&&d==head->y)
{
c=rand()%22+1;
d=rand()%22+1;
}
show[c][d]=3;
}
}
//蛇的移动
void moves(Snake *head)
{
PlaySound("four.wav",NULL, SND_FILENAME | SND_ASYNC|SND_LOOP); //背景音乐循环播放
while(key!= 0x11b)
{
eats(head);
death(head);
Snake *p,*q,*t;
if(kbhit())
{
key2=key;
key=getch();
}
else if(key==119&&key2!=115)
{
t=head;
p=head->next;
q=new Snake;
q->x=head->x-1;
q->y=head->y;
show[q->x][q->y]=2;
q->next=head;
head=q;
for(int i=0;i<longs+1;i++)
{
if(!p->next)
{
show[p->x][p->y]=1;
t->next=NULL;
}
else
{
p=p->next;
t=t->next;
}
}
menu(show);
Sleep(100); //控制速度
eat_self(head);
}
else if(key==115&&key2!=119)
{
q=new Snake;
q->x=head->x+1;
q->y=head->y;
show[q->x][q->y]=2;
q->next=head;
head=q;
p=head->next;
t=head;
for(int i=0;i<longs+1;i++)
{
if(!p->next)
{
show[p->x][p->y]=1;
t->next=NULL;
}
else
{
p=p->next;
t=t->next;
}
}
menu(show);
Sleep(100);
}
else if(key==97&&key2!=100)
{
q=new Snake;
q->x=head->x;
q->y=head->y-1;
show[q->x][q->y]=2;
q->next=head;
head=q;
p=head->next;
t=head;
for(int i=0;i<longs+1;i++)
{
if(!p->next)
{
show[p->x][p->y]=1;
t->next=NULL;
}
else
{
p=p->next;
t=t->next;
}
}
menu(show);
Sleep(100);
}
else if(key==100&&key2!=97)
{
q=new Snake;
q->x=head->x;
q->y=head->y+1;
show[q->x][q->y]=2;
q->next=head;
head=q;
p=head->next;
t=head;
for(int i=0;i<longs+1;i++)
{
if(!p->next)
{
show[p->x][p->y]=1;
t->next=NULL;
}
else
{
p=p->next;
t=t->next;
}
}
menu(show);
Sleep(100);
}
else
{
key=key2;
continue;
}
}
}
int main()
{
int a,b; //定义产生的随机数,确定食物以及蛇坐标
SetConsoleTitle("吞星蟒之路");
srand((unsigned)time(NULL)); //产生2个随机数
a=rand()%22+1;
b=rand()%18+3;
c=rand()%22+1;
d=rand()%22+1;
while((a==c&&b==d)||(a==c&&b==d-1)||(a==c&&b==d-2))
{
c=rand()%22+1;
d=rand()%22+1;
}
show[c][d]=3; //食物初始位置
Snake *head,*p,*last; //定义蛇链表的头指针,普通指针,尾指针
head =new Snake;
head=NULL;
last=head;
for(int i=0;i<longs;i++)
{
p=new Snake;
p->x=a;
p->y=b-i;
p->next=NULL;
if(!head)
head=p;
else
last->next=p;
last=p;
show[last->x][last->y]=2;
}
menu(show);
imformation();
key=getch(); //按下按键//119 115 97 100 ASCII码值
key2 ='g';
moves(head);
}
部分截图
背景音乐如果有问题可以看我的这篇博客
C++语言写养成类游戏