接觸編程有段時間了,一直想學習怎么去寫個游戲來練練手。在看了B站上的教學終於可以自己試試怎么實現貪吃蛇這個游戲了。好了,廢話不多說,我們來看看如何用EasyX庫來實現貪吃蛇。
一、准備
- 工具vc++6.0
- 安裝庫文件
- EasyX庫安裝鏈接
- 可以安裝任意版本,本人安裝的是2018春分版
- 這是一個簡單易學的一個圖形庫,相信對於大家學習來說應該不成問題
- 准備工作做好后接下來就得弄清楚游戲工作機制了
二、基本介紹
在這里我們需要明白EasyX庫的基本知識,其次我們還有了解游戲的工作原理,不能盲目的直接寫代碼,需要一步步的思考,比如蛇是如何繪制、移動的;食物是怎么產生的;蛇吃了食物會怎樣;死亡機制等等
EasyX庫介紹
- 首先我們來講講EasyX庫的坐標概念
- 物理坐標
- 簡單來說,物理坐標就是以窗口的左上角為原點,以水平向右為x軸,豎直向下為y軸,以像素為單位
- 邏輯坐標
- 邏輯坐標和物理坐標是一一對應的,不過邏輯坐標是以點為單位
- 物理坐標
- 顏色概念
- EasyX庫的預定義顏色常量如下:
| 常量 | 值 | 顏色 |
|---|---|---|
| BLACK | 0 | 黑 |
| BULE | 0xAA0000 | 藍 |
| GREEN | 0x00AA00 | 綠 |
| CYAN | 0xAAAA00 | 青 |
| RED | 0x0000AA | 紅 |
| MAGENTA | 0xAA00AA | 紫 |
| BROWN | 0x0055AA | 棕色 |
| LIGHTGRAY | 0xAAAAAA | 淺灰 |
| DARKGRAY | 0x555555 | 深灰 |
| LIGHTBULE | 0xFF5555 | 亮藍 |
| LIGHTGREEN | 0x55FF55 | 亮綠 |
| LIGHTCYAN | 0xFFFF55 | 亮青 |
| LIGHTRED | 0x5555FF | 亮紅 |
| LIGHTMAGENTA | 0xFF55FF | 亮紫 |
| YELLOW | 0x55FFFF | 黃 |
| WHITE | 0xFFFFFF | 白 |
3.基本函數介紹
- initgraph(int width,int height,int flag=NULL):初始化繪圖環境
- width:繪圖環境的寬度
- height:繪圖環境的高度
- flag:繪圖環境的樣式,默認為NULL
- cleardevice():用於清除屏幕內容
- setbkcolor(COLORREF color):設置背景顏色
- setfillcolor(COLORREF color):設置填充顏色
- setlinecolor(COLORREF color):設置當前畫線顏色
- outtextxy(int x,int y,TCHAR c):用於在指定位置輸出字符串
- x,y表示輸出字符串的坐標值
- c表示待輸出的字符
- fillroundrect(int left,int top,int right,int bottom,int ellipsewidth,int ellipseheight):繪制圓角矩形
- left:圓角矩形左部 x 坐標
- top:圓角矩形上部 y 坐標
- right:圓角矩形右部 x 坐標
- bottom:圓角矩形下部 y 坐標
- ellipsewidth:構成圓角矩形的圓角的橢圓的寬度
- ellipseheight:構成圓角矩形的圓角的橢圓的高度
工作原理
- 必須先包含頭文件,才能運行
#include<graphics.h>
#include<time.h>
#include<stdlib.h>
#include<conio.h>
- 我們要有窗口才能繪制蛇和食物,因此可以用initgraph()函數來實現
- 其次我們要弄清楚如何來描述窗口位置,這里我們可以設置一個結構體Coor
struct Coor{
int x;
int y;
};
- 方向
enum Ch{ //枚舉類型表示上下左右鍵的鍵值
up=72,
down=80,
left=75,
right=77
};
- 蛇也是有自己屬性的結構體
struct Snake{
//蛇的屬性
int n; //蛇當前節數,一節為一個正方形,n個正方形
struct Coor szb[500]; //snake的坐標,存放蛇的坐標,這里設置500,表示蛇能達到的最大長度為500
Ch ch; //蛇的方向
}snake; //變量
- 食物的結構體
struct Food{
struct Coor fzb; //食物坐標
int flag; //是否被吃
}food;
有了以上的結構體的定義,我們就可以設置函數來完成貪吃蛇的繪制、移動、食物的繪制以及死亡機制等等
- 函數內容如下
- InitSnake():包含窗口的初始化,初始化隨機種子,初始化蛇的起始坐標
- DrawSnake():繪制蛇的每個節點
- MoveSnake():蛇的移動
- ChangeSnakeCh():通過鍵盤改變蛇的方向
- CoorFood():隨機生成食物的坐標
- DrawFood():繪制食物樣式
- EatFood():蛇吃掉食物后的變化
- KnockWall():撞牆死亡
- EatSelf():吃到自己死亡
void InitSnake(){
//初始化窗口
srand((unsigned int)time(NULL)); //產生隨機種子
initgraph(200,200); //初始化200*200像素的繪圖窗口
setbkcolor(GREEN); //設置背景顏色
//初始化蛇
//開始時蛇的節數為1,方向向右
snake.n=1;
snake.ch=right;
snake.szb[0].x=0;
snake.szb[0].y=0;
}
//繪制蛇,n節蛇
void DrawSnake(){
setlinecolor(GREEN); //設置蛇邊緣的線條顏色
setfillcolor(RED); //設置蛇身的顏色
//遍歷數組
for(int i=0;i<snake.n;i++){
fillrectangle(snake.szb[i].x,snake.szb[i].y,snake.szb[i].x+10,snake.szb[i].y+10); //根據蛇的當前長度,創建蛇身,這里設置一節蛇的大小為10*10個像素
}
}
- 關於蛇的移動其實很簡單,只要將前面的節點坐標傳遞給后面的節點坐標,就能起到移動的效果
//蛇的移動
void MoveSnake(){
for(int i=snake.n-1;i>0;i--){
snake.szb[i].x=snake.szb[i-1].x;
snake.szb[i].y=snake.szb[i-1].y;
}
switch(snake.ch){
case up:
snake.szb[0].y-=10;
break;
case down:
snake.szb[0].y+=10;
break;
case left:
snake.szb[0].x-=10;
break;
case right:
snake.szb[0].x+=10;
break;
}
}
- 這里需要注意的是:蛇移動時的方向改變規則是在蛇向左/右移動時,蛇只能向上/下移動,同理對於蛇在向上/下移動的情況
//通過鍵盤控制
void ChangeSnakeCh(){
int move;
move=getch(); //獲取鍵盤傳遞的字符
switch(move){
case right:
if(snake.ch!=left)
snake.ch=right;
break;
case left:
if(snake.ch!=right)
snake.ch=left;
break;
case up:
if(snake.ch!=down)
snake.ch=up;
break;
case down:
if(snake.ch!=up)
snake.ch=down;
break;
}
}
- 食物的產生與繪制
void CoorFood(){
food.fzb.x=rand()%20*10; //根據窗口像素來產生食物坐標
food.fzb.y=rand()%20*10;
food.flag=1; 1表示食物沒被吃的狀態,0表示已吃的狀態
}
//繪制食物
void DrawFood(){
//繪制圓角矩形
setfillcolor(YELLOW);
fillroundrect(food.fzb.x,food.fzb.y,food.fzb.x+10,food.fzb.y+10,10,10);
}
//蛇吃食物
void EatFood(){
//判斷蛇頭和食物是否重合
if(snake.szb[0].x==food.fzb.x&&snake.szb[0].y==food.fzb.y){
snake.n++; //蛇身長度加1
food.flag=0; 食物標記為0表示已吃
}
}
- 死亡機制
//撞牆
int KnockWall(){
for(int i=0;i<snake.n;i++){
if(snake.szb[i].x>200||snake.szb[i].x<0||snake.szb[i].y>200||snake.szb[i].y<0){
//如果蛇頭的坐標值超出窗口的坐標值,就返回錯誤
return 0;
}
}
}
//咬到自己
int EatSelf(){
for(int i=1;i<snake.n;i++){
if(snake.szb[0].x==snake.szb[i].x&&snake.szb[0].y==snake.szb[i].y){
//循環判斷蛇頭坐標是否與蛇身某部分重合,若重合則放回錯誤
return 0;
}
}
}
- 主函數
int main(){
InitSnake(); //初始化
while(1){
while(!kbhit()){ //未改變蛇的方向之前
if(food.flag==0){
CoorFood();
}
cleardevice(); //先清屏,才能保證之前繪制的蛇身不會顯示出來
MoveSnake(); //先移動蛇的各個坐標
DrawFood(); //繪制食物
DrawSnake(); //再繪制蛇身
if(!KnockWall()||!EatSelf()) //死亡機制
break;
EatFood(); //吃掉食物后,蛇和食物的變化
Sleep(150); //設置蛇的移動速度
}
while(!KnockWall()||!EatSelf()){
outtextxy(100,100,"YOU DIED!"); //如果蛇吃到自己或撞牆則在窗口顯示YOU DIED!
}
ChangeSnakeCh(); //通過鍵盤上下左右鍵來移動蛇
}
return 0;
}
