Easyx庫-貪吃蛇小遊戲
阿新 • • 發佈:2019-02-18
#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 }
原始碼檔案:原始碼