19/7/24
更新
这几天想写一个32操作系统,操作系统上面跑东西啊要,就又拿着贪吃蛇鞭尸了。。。。
这次用循环队列实现,效果比数组好,因为避免了数据的反复后移。只需要直接入队,出队就行
屏幕的刷新上面,没有采取上一次的整体刷新,代替的是确定光标位置,在光标处刷新。
更详细注释见代码
/*
食物不能产生在身上未加
//
使用顺序循环队列实现
kbhit()检测键盘是否有输入,有返回非零值,否则0
撞墙会死
前进过程中不能突然折回
by shuiyihang0981 19/7/24
//
*/
#include
#include
#include
#include
#define MAX_LEN 100
#define Side_X 30
#define Side_Y 25//墙的边界
//#define DEBUG
char dir='s',last_dir='s';//设定默认方向
int test1,test2,test3,test4;//测试bug调用
int count=0,srand_x=0,srand_y=0;
int temp;
bool Game_over=false;
typedef struct
{
int x,y;
}Pos;
typedef struct
{
Pos vex;
bool exist;
}Goal;
typedef struct
{
Pos date[MAX_LEN];
int head,rear;
}Snake;
void gotoxy(int x,int y)//任意点确定光标,参考MSDN
{
COORD point={x,y};
HANDLE HOutput=GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(HOutput,point);
}
void Init(Snake *S)//墙,蛇初始化
{
S->head=S->rear=0;
S->date[S->rear].x=2;
S->date[S->rear].y=3;
S->rear=(S->rear+1)%MAX_LEN;
gotoxy(S->date[S->rear-1].x,S->date[S->rear-1].y);
printf("O");
gotoxy(Side_X+5,Side_Y/2-5);
printf("Snake Game");
gotoxy(0,Side_Y);
printf("---------------------------------\n");
gotoxy(Side_X+5,Side_Y/2);
printf("Core:%d",count);
for(int i=0;iexist==false)
{
food->vex.x=srand_x;
food->vex.y=srand_y;
food->exist=true;
gotoxy(food->vex.x,food->vex.y);
printf("*");
}
}
/*
蛇只管前行,遇到食物入队,此时不需要尾巴出队
没有吃到食物,新的队首入队,尾巴出队
*/
void GoHead(Snake *S,Goal *food)//蛇前行
{
srand_x=rand()%Side_X;
temp=((S->rear)-1+MAX_LEN)%MAX_LEN;//0的前一个应该是9,而不是-1
switch(dir)
{
case 's':
if(last_dir!='w')//Up
{
S->date[S->rear].y=(S->date[temp].y+1);
S->date[S->rear].x=(S->date[temp].x);
}else
{
Game_over=true;
gotoxy(Side_X+5,Side_Y/2+2);
printf("Bite Self!");
}
break;
case 'w':
if(last_dir!='s')//Down
{
S->date[S->rear].y=(S->date[temp].y-1);
S->date[S->rear].x=(S->date[temp].x);
}else
{
Game_over=true;
gotoxy(Side_X+5,Side_Y/2+2);
printf("Bite Self!");
}
break;
case 'a':
if(last_dir!='d')//Left
{
S->date[S->rear].x=(S->date[temp].x-1);
S->date[S->rear].y=(S->date[temp].y);
}else
{
Game_over=true;
gotoxy(Side_X+5,Side_Y/2+2);
printf("Bite Self!");
}
break;
case 'd':
if(last_dir!='a')//Right
{
S->date[S->rear].x=(S->date[temp].x+1);
S->date[S->rear].y=(S->date[temp].y);
}else
{
Game_over=true;
gotoxy(Side_X+5,Side_Y/2+2);
printf("Bite Self!");
}
break;
default:
break;
}
#ifdef DEBUG
test1=S->date[S->rear].x;
test2=S->date[S->rear].y;
#endif // DEBUG
if((S->date[S->rear].x)<0||(S->date[S->rear].x)>Side_X||(S->date[S->rear].y)<0||(S->date[S->rear].y)>Side_Y)//撞墙
{
Game_over=true;
gotoxy(Side_X+5,Side_Y/2+2);
printf("Brick Wall!");
}
else
{
gotoxy(S->date[S->rear].x,S->date[S->rear].y);
printf("O");
Sleep(0.5);
if(food->exist&&(S->date[S->rear].x==food->vex.x)&&(S->date[S->rear].y==food->vex.y))
{
count++;
food->exist=false;
gotoxy(Side_X+10,Side_Y/2);
printf("%d",count);
}else
{
gotoxy(S->date[S->head].x,S->date[S->head].y);
printf(" ");
Sleep(0.5);
S->head=(S->head+1)%MAX_LEN;
}
S->rear=(S->rear+1)%MAX_LEN;
}
}
void PlayInput()//检测输入
{
srand_y=rand()%Side_Y;
if(kbhit())//
{
last_dir=dir;//上一次的方向,规定不能突然折返蛇身
dir=getch();
if(dir!='w'&&dir!='a'&&dir!='s'&&dir!='d')
{
dir=last_dir;
}
}
}
int main()
{
srand(10);
Snake Q;
Goal food;
Init(&Q);
while(false==Game_over)
{
PlayInput();
GoHead(&Q,&food);
CreFood(&food);
Sleep(200);//windows.h//游戏速度设定
}
gotoxy(Side_X+5,Side_Y/2);
printf("Game OVER! Count:%d",count);
gotoxy(0,Side_Y+2);
return 0;
}
上一次的数组实现,有兴趣看一下,就不推荐了
贪吃蛇比较简单,要了解它的步骤:
如果你可以单独对某个点重画,就要利用只有蛇头,蛇尾会变的特点,这样会快很多。
我是在windows下跑的,通过cls命令清空,所以会有点闪,sleep函数用于调节蛇的速度
O是蛇身,*是食物
//贪吃蛇数组实现,无限生命版(撞墙不会挂)
#include
#include
#include//窗口大小设为20,25;
#include
char str;
int num=0;
int count=0;
bool eated=false;
int rand_x,rand_y;//提前准备着方便使用
struct Snake{
int x;
int y;
char dir;
}mole[50];//可以设置更长>50
struct food{
int x;
int y;
}bread;
/初始化
void init()
{
mole[0].x=10;
mole[0].y=15;
bread.x=5;
bread.y=5;
//mole[1].dir='a';//默认向左
}
/方向控制
void PlayInput()
{
rand_y=rand()%20;
if(kbhit())
{
str=getch();
switch (str){
case 'w':
mole[num].dir='w';//可以直接赋值,防止误输入
break;
case 'a':
mole[num].dir='a';
break;
case 's':
mole[num].dir='s';
break;
case 'd':
mole[num].dir='d';
break;
default:
break;
}
}
}
/屏幕重画
void show()
{
bool flag=false;
for(int i=0;i<20;i++)
{
for(int j=0;j<25;j++)
{
for(int k=0;k<=num;k++)
{
if(mole[k].x==j&&mole[k].y==i)
{
printf("O");
flag=true;
break;
}
}
if(bread.x==j&&bread.y==i)//画食物
{
printf("*");
//flag=true;
}
if(flag==false)printf(" ");
else flag=false;
}
printf("\n");
}
printf("Your Score:%d\n", count);
}
/蛇移动
void SnakeMove()//清屏重画
{
for(int i=0;i19)mole[num].x=0;
break;
case 'd':
mole[num].x=mole[num].x+1;
if(mole[num].x>24)mole[num].x=0;
break;
}
system("cls");//如果不刷屏的话,只删除蛇尾,效果会更好
show();
}
食物产生
void creatFood()
{
if(eated==true)//食物被吃掉随即再次产生
{
//范围是25,20
bread.x=rand_x;
bread.y=rand_y;
eated=false;
}
}
蛇吃食
void FoodEat()
{
SnakeMove();
switch (mole[num].dir){
case 'w':
if((mole[num].y-1)==bread.y&&mole[num].x==bread.x)
{
num++;
mole[num].x=bread.x;
mole[num].y=bread.y;
eated=true;
count++;
}
break;
case 'a':
if((mole[num].x-1)==bread.x&&mole[num].y==bread.y)
{
num++;
mole[num].x=bread.x;
mole[num].y=bread.y;
eated=true;
count++;
}
break;
case 's':
if((mole[num].y+1)==bread.y&&mole[num].x==bread.x)
{
num++;
mole[num].x=bread.x;
mole[num].y=bread.y;
eated=true;
count++;
}
break;
case 'd':
if((mole[num].x+1)==bread.x&&mole[num].y==bread.y)
{
num++;
mole[num].x=bread.x;
mole[num].y=bread.y;
eated=true;
count++;
}
break;
}
creatFood();
}
int main()
{
srand(10);
init();
while(1)
{
PlayInput();
FoodEat();
Sleep(250);
}
return 0;
}
//-----------------------------By shuiyihang------------------------------------//
//-----------------------------CodeBlocks下测试----------------------------------//
程序肯定是有Bug的,但是目前来看还行,就是有点闪,还可以优化,当然你也可以考虑使用链表