1. 程式人生 > >Easyx庫-貪吃蛇小遊戲

Easyx庫-貪吃蛇小遊戲

#include <graphics.h>
#include <string.h>
#include <stdio.h>             //sprintf將整數轉換為字串      
#include <time.h>              //srand產生隨機數
#define SQU_LONG 15            //正方形的長
#define SQU_NUMBER 30          //正方形個數
#pragma comment(lib,"Winmm.lib")               //匯入音樂標頭檔案

IMAGE img,right,stop,play,fail,change;         //定義背景,右邊,遊戲暫停,正在遊戲,遊戲失敗,分數改變圖片
int NUM=3;                                     //節點個數
char score[5];                                 //儲存分數的字串
int foodx,foody;                               //食物的座標,用於批繪製

void food();                            //產生食物
void snakeMove();                       //蛇移動
int Direction(int savec);               //控制方向
void eat();                             //吃食物
void over();                            //蛇死亡

struct snake
{
	int x;                      //蛇頭x座標
	int y;                      //蛇頭y座標
	int dire;                   //蛇頭方向
	struct snake *next;         //結構體指標
};
struct snake *head=(snake *)malloc(sizeof(snake));           //定義頭指標
struct snake *p;                                             //用於遍歷結構體
struct snake saveLast,saveBody;                              //saveLast用於儲存前一個節點,saveBody用於儲存後一個節點 

void main()//主方法
{
	initgraph(SQU_LONG*SQU_NUMBER+200,SQU_LONG*SQU_NUMBER);		    //建立畫布
	loadimage(&img,"image/bk_picture.jpg");                         //讀取背景圖片
	putimage(0,0,&img);                                             //在座標(0,0)處放置背景圖片
	loadimage(&right,"image/right.jpg");                            
	putimage(495,0,&right);                                                                                     
	settextcolor(WHITE);											//文字顏色為白色
	setbkmode(TRANSPARENT);                                         //文字背景為透明
	settextstyle(20,0,"楷體");                                      //文字字號為20,正常寬度,字型為楷體
	outtextxy(530,40,"遊戲規則:");                                 //在座標(530,70)處輸出“遊戲規則”四個字,只能輸出字串格式
	outtextxy(502,70,"方向鍵控制方向");
	outtextxy(502,90,"  Space鍵暫停");
	outtextxy(502,110,"  Shift鍵加速");	
	loadimage(&play,"image/play.jpg");
	putimage(495,290,&play);
	mciSendString("open music/bk_audio.mp3 alias bk_audio",NULL,0,NULL);            //讀取背景音樂檔案並命名為bk_audio
	mciSendString("play bk_audio repeat",NULL,0,NULL);                              //repeat為迴圈播放

	int x,y;                                        //蛇頭座標        
	srand((unsigned)time(NULL));                    //產生隨機數的語句,與rand()連用
	do
	{
		x=rand()%SQU_LONG*SQU_NUMBER;               //先算求餘,後算乘法,隨機產生蛇頭的座標
		y=rand()%SQU_LONG*SQU_NUMBER;
	}while(x>SQU_LONG*(SQU_NUMBER-3)||y>SQU_LONG*(SQU_NUMBER-3)||x<3*SQU_LONG||y<3*SQU_LONG);             //不能出現在四周靠邊的位置
	struct snake *a=(snake *)malloc(sizeof(snake));             //用於儲存蛇頭
	struct snake *b=(snake *)malloc(sizeof(snake));             //一開始出現的第一節身子
	struct snake *c=(snake *)malloc(sizeof(snake));             //一開始出現的第二節身子
	p=head;                           //p指向head
	p->next=a;
	a->x=x;
	a->y=y;
	a->dire=rand()%4+1;               //a為蛇頭,隨機產生方向
	a->next=b;
	b->next=c;
	c->next=NULL;	                  //一開始只有一個蛇頭兩個身子,最後一個身子無指向
	p=p->next;                        //p指向蛇頭
	setfillcolor(RED);                //設定填充顏色紅色,表示蛇頭
	bar(p->x,p->y,p->x+SQU_LONG-1,p->y+SQU_LONG-1);              //在(p->x,p->y)處畫一個長度為SQU_LONG的填充紅色的正方形	
	saveLast.x=p->x;                  //將移動前蛇頭資訊儲存為上一個節點的資訊
	saveLast.y=p->y;
	saveLast.dire=p->dire;
	saveLast.next=p->next;
	if(p->dire==1)
		p->x-=SQU_LONG;         //向左,p->x-1
	else if(p->dire==2)         
		p->y-=SQU_LONG;         //向上,p->y-1
	else if(p->dire==3)
		p->x+=SQU_LONG;         //向右,p->x+1
	else if(p->dire==4)
		p->y+=SQU_LONG;         //向下,p->y+1
	setfillcolor(RED);          //移動後重新畫蛇頭
	bar(p->x,p->y,p->x+SQU_LONG-1,p->y+SQU_LONG-1);              //在移動後坐標處畫一個長度為SQU_LONG的填充紅色的正方形
	p=p->next;                  //p指向第一個身子
	while(p)                           //p不為空就進入迴圈,一開始設定連結串列有三個節點,一共可進入兩次
	{
		saveBody.x=p->x;               //將移動後的資訊儲存為現在節點的資訊
		saveBody.y=p->y;
		saveBody.dire=p->dire;
		p->x=saveLast.x;               //重新將儲存的移動前的資訊讀取出,賦給當前p指向的身子
		p->y=saveLast.y;
		p->dire=saveLast.dire;
		saveLast.x=saveBody.x;         //儲存的移動前的失去作用,重新將移動後的再作為上一個節點,保證蛇每個身子記錄前一個身子的資訊
		saveLast.y=saveBody.y;
		saveLast.dire=saveBody.dire;
		setfillcolor(YELLOW);          //設定填充顏色黃色,表示蛇身子
		bar(p->x,p->y,p->x+SQU_LONG-1,p->y+SQU_LONG-1);		        //在讀取到資訊的座標處畫一個長度為SQU_LONG的填充黃色的正方形
		p=p->next;                     //p指向下一個身子
	}	
	food();                      //呼叫生成食物方法
	snakeMove();	             //呼叫蛇移動方法
}

void food()//生成食物       
{
	int x,y;                             //食物座標
	do
	{
		x=rand()%SQU_LONG*SQU_NUMBER+SQU_LONG;
		y=rand()%SQU_LONG*SQU_NUMBER+SQU_LONG;
	}while(getpixel(x,y)==RED||getpixel(x,y)==YELLOW||x>SQU_LONG*(SQU_NUMBER-1)||y>SQU_LONG*(SQU_NUMBER-1));        //不能出現在蛇頭和蛇身上還有邊框右邊和下邊
	foodx=x;                             //將座標儲存為全域性變數,用於其他方法批繪製
	foody=y;
}

void snakeMove()//蛇移動
{	
	int i,savec;                //savec用於在選擇方向是臨時儲存     
	while(1)
	{			
		p=head->next;                              //p指向蛇頭
		saveLast.x=p->x;                           //依然是將移動前蛇頭資訊儲存為上一節點資訊
		saveLast.y=p->y;
		saveLast.dire=p->dire;
		if(p->dire==1)
			p->x-=SQU_LONG;                        //向左,p->x-1
		else if(p->dire==2)
			p->y-=SQU_LONG;                        //向上,p->y-1
		else if(p->dire==3)
			p->x+=SQU_LONG;                        //向右,p->x+1
		else if(p->dire==4)
			p->y+=SQU_LONG;                        //向下,p->y+1
		p=p->next;                                 //p指向第一個身子
		while(p)
		{
			saveBody.x=p->x;                       //依然是將移動後資訊儲存為現在節點的資訊
			saveBody.y=p->y;
			saveBody.dire=p->dire;
			p->x=saveLast.x;
			p->y=saveLast.y;
			p->dire=saveLast.dire;
			saveLast.x=saveBody.x;
			saveLast.y=saveBody.y;
			saveLast.dire=saveBody.dire;
			p=p->next;                             //p指向第二個身子
		}
		p=head->next;                                         //p重新指向蛇頭
		if(getpixel(p->x,p->y)==YELLOW||p->x<0||p->y<0||p->x>(SQU_LONG*(SQU_NUMBER-1)+45)||p->y>SQU_LONG*(SQU_NUMBER-1))       //如果獲取到蛇頭座標的顏色為黃色(蛇頭覆蓋在身子上)活著蛇頭碰到邊緣
			over();	                                          //呼叫失敗方法
		else if(getpixel(p->x,p->y)==GREEN)                   //如果蛇頭座標的顏色為綠色(蛇頭覆蓋在食物上,代表吃掉食物)
		{
			mciSendString("open music/eat_food.mp3 alias eat_food",NULL,0,NULL);           //呼叫吃掉食物的音樂
			mciSendString("play eat_food from 0",NULL,0,NULL);                             //from 0為播放一次
			eat();                                            //呼叫吃食物方法
			food();                                           //呼叫生成食物方法
		}
		BeginBatchDraw();                                                 //開始批繪製
		putimage(0,0,&img);                                               //每一次繪製都需要重新整理,所以每次都需要呼叫背景圖片
		p=head->next;
		setfillcolor(RED);                                    //移動後重新畫蛇頭
		bar(p->x,p->y,p->x+SQU_LONG-1,p->y+SQU_LONG-1);	  
		p=p->next;
		while(p)
		{
			setfillcolor(YELLOW);                             //移動後重新畫身子
			bar(p->x,p->y,p->x+SQU_LONG-1,p->y+SQU_LONG-1);
			p=p->next;					
		}
		setfillcolor(GREEN);                                              //設定填充顏色為綠色,表示食物
		bar(foodx,foody,foodx+SQU_LONG-1,foody+SQU_LONG-1);               //綠色代表食物		
		outtextxy(540,200,"得分:");
		sprintf(score,"%d",(NUM-3)*10);                                   //將整數(NUM-3)*10轉換為字串儲存在score中
		loadimage(&change,"image/score.jpg");
		putimage(495,220,&change);
		outtextxy(546,220,score);
		FlushBatchDraw();                                                 //每更新一次繪製一次
		p=head->next;
		for(i=0;i<5;i++)
		{
			Sleep(NUM<20?(200-4*NUM):100);	                              //蛇移動停頓的時間,隨著吃的食物個數的增多停頓時間減少,減少到0.1秒後保持不變
			savec=p->dire;                                                //將蛇頭原來的方向儲存到savec中
			p->dire=Direction(savec);                                     //呼叫按鍵方法並傳遞savec引數
			if(p->dire==5)                                                //如果選擇了加速按鍵
			{
				p->dire=savec;                                            //方向仍然是原方向
				break;                                                    //跳出迴圈,不停頓
			}
		}		
		EndBatchDraw();                                                   //關閉批量繪圖
	}
}

int Direction(int savec)//按鍵
{
	p=head->next;                                              //p指向蛇頭                                                   
	if(p->dire!=3&&GetAsyncKeyState(VK_LEFT)&0x8000)           //如果原來方向不向右並且按下左鍵
		p->dire=1;
	else if(p->dire!=4&&GetAsyncKeyState(VK_UP)&0x8000)        //如果原來方向不向下並且按下上鍵
		p->dire=2;
	else if(p->dire!=1&&GetAsyncKeyState(VK_RIGHT)&0x8000)     //如果原來方向不向左並且按下右鍵
		p->dire=3;
	else if(p->dire!=2&&GetAsyncKeyState(VK_DOWN)&0x8000)      //如果原來方向不向上並且按下下鍵
		p->dire=4;
	else if(GetAsyncKeyState(VK_SHIFT)&0x8000)                 //按shift鍵
		p->dire=5;
	else if(GetAsyncKeyState(VK_SPACE)&0x8000)                 //按空格鍵
	{
		loadimage(&stop,"image/stop.jpg");
		putimage(495,290,&stop);                               //更新遊戲暫停圖片
		FlushBatchDraw();                                      //批繪製
		mciSendString("stop bk_audio",NULL,0,NULL);            //暫停,音樂停止
		system("pause");                                       //暫停,按任意鍵繼續
		loadimage(&play,"image/play.jpg");
		putimage(495,290,&play);                               //更新正在遊戲圖片
		FlushBatchDraw();                                      //批繪製
		mciSendString("play bk_audio",NULL,0,NULL);            //音樂重新從上一次結束的地方播放
		p->dire=savec;                   //暫停結束繼續向同一個方向走
	}		
	else
		p->dire=savec;                   // 若是沒有選擇依然是原先的方向
	return p->dire;
}

void over()//結束
{
	loadimage(&fail,"image/fail.jpg");
	putimage(495,290,&fail);                              //更新遊戲失敗圖片
	FlushBatchDraw();                                     //批繪製
	mciSendString("stop bk_audio",NULL,0,NULL);	          //結束,音樂停止
	system("pause");
	exit(0);                                              //退出到控制檯
}

void eat()//吃食物
{
	p=head;
	while(p->next!=NULL)                                  //若p不是尾節點,則繼續進入迴圈遍歷
		p=p->next;
	struct snake *a=(snake *)malloc(sizeof(snake));       //重新宣告一個節點,用於新增身子
	a->x=saveLast.x;                                      //將最後儲存的節點資訊賦給新節點
	a->y=saveLast.y;
	a->dire=saveLast.dire;
	a->next=NULL;
	p->next=a;                                            //連線到連結串列中
	p=p->next;
	NUM+=1;                                               //節點個數加1
}

原始碼檔案:原始碼