19/7/24
更新
這幾天想寫一個32操作系統,操作系統上面跑東西啊要,就又拿着貪吃蛇鞭屍了。。。。
這次用循環隊列實現,效果比數組好,因爲避免了數據的反覆後移。只需要直接入隊,出隊就行
屏幕的刷新上面,沒有采取上一次的整體刷新,代替的是確定光標位置,在光標處刷新。
更詳細註釋見代碼
/*
食物不能產生在身上未加
//////////////////////////////////////////////
使用順序循環隊列實現
kbhit()檢測鍵盤是否有輸入,有返回非零值,否則0
撞牆會死
前進過程中不能突然折回
by shuiyihang0981 19/7/24
//////////////////////////////////////////////
*/
#include<stdio.h>
#include<windows.h>
#include<conio.h>
#include<stdlib.h>
#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;i<Side_Y;i++)
{
gotoxy(0,i);
gotoxy(Side_X,i);
printf("|");
}
}
void CreFood(Goal *food)//食物產生
{
if(food->exist==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())//<conio.h>
{
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<stdio.h>
#include<conio.h>
#include<windows.h>//窗口大小設爲20,25;
#include<stdlib.h>
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;i<num;i++)
{
mole[i]=mole[i+1];
}
rand_x=rand()%25;
switch (mole[num].dir){
case 'w':
mole[num].y=mole[num].y-1;
if(mole[num].y<0)mole[num].y=19;
break;
case 'a':
mole[num].x=mole[num].x-1;
if(mole[num].x<0)mole[num].x=24;
break;
case 's':
mole[num].y=mole[num].y+1;
if(mole[num].y>19)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的,但是目前來看還行,就是有點閃,還可以優化,當然你也可以考慮使用鏈表