namespace?SnakeGame
{
public?partial?class?frmSnake?:?Form
{
public?Point?FoodLct?=?new?Point();//緩存食物的坐標?
public?int?snakeLen?=?6;
public?const?int?SnakeMaxLength?=?500;
public?Point[]?snakeArr?=?new?Point[SnakeMaxLength];
public?int?snakeDrt?=?2;
public?bool?panDuan?=?true;
public?frmSnake()
{
InitializeComponent();
int?temp?=?0;
for?(int?i?=?snakeLen?-?1;?i?>=?0;?i--)
{
snakeArr[i].X?=?temp;?snakeArr[i].Y?=?0;?
temp?+=?15;
}
}
/*
前言?
說到貪吃蛇,大家可能小時候都玩過,小菜最近在整理Winfrom的學習系列,那我覺得有興趣才會有學習,就從這個小遊戲講起吧。?
其實我剛開始學習編程的時候,感覺寫個貪吃蛇的程序會很難,因為涉及到畫圖什麽的,其實現在來看,實現很簡單。?
實現貪吃蛇首先有幾個元素:?
蛇?
食物?
然後有幾個行為:?
吃食物和吃不到食物?
撞墻和撞自己?
說到這有點oo的意思啊,這篇就不啰嗦,只是簡單實現,下篇會優化下。?
其實整個貪吃蛇的難點就在於畫圖,可能用其他語言實現有點復雜,但是強大的.net提供了GDI+繪圖機制,實現起來就很方便了,其次就是細節的處理,比如坐標的定位,蛇的行走路線等。?
我們簡單壹點來看,食物可以看成壹個小方格,蛇是有N個小方格組成,那我們就可以用GDI+這樣實現:
///?<summary>?
///?畫壹個小方塊?
///?</summary>?
public?void?DrawShape(int?x,?int?y)
{
Graphics?g?=?this.CreateGraphics();
Pen?pen?=?new?Pen(Color.Blue,?2);
g.DrawRectangle(pen,?x,?y,?15,?15);
g.FillRectangle(Brushes.Green,?x,?y,?15,?15);
}
///?<summary>?
///?畫壹個食物?
///?</summary>?
public?void?DrawFood(int?x,?int?y)
{
Graphics?g?=?this.CreateGraphics();
Pen?pen?=?new?Pen(Color.Red,?2);
SolidBrush?brush?=?new?SolidBrush(Color.Green);
g.DrawRectangle(pen,?x,?y,?15,?15);
g.FillRectangle(brush,?x,?y,?15,?15);
}
Graphics這個類我就不多說,大家可以看看MSDN上介紹的用法,上面是畫蛇的最小單元-方格,和壹個食物方格,蛇的方格大小是15*15,邊框顏色是Blue,填充色是Green;食物方格的大小是15*15,邊框顏色是Red,填充色是Green。?
畫好了基本元素,那下面就是用基本元素來表現蛇了,可以用Point數組來存儲蛇的坐標,也就是每個方格的坐標,我們先看下代碼:?
///?<summary>?
///?設置Point數組坐標?
///?</summary>?
public?void?Forward(int?drt)
{
Point?temp?=?snakeArr[0];
for?(int?i?=?snakeLen?-?1;?i?>?0;?i--)
{
snakeArr[i].X?=?snakeArr[i?-?1].X;
snakeArr[i].Y?=?snakeArr[i?-?1].Y;
}
switch?(drt)
{
case?1:
snakeArr[0].X?=?temp.X;
snakeArr[0].Y?=?temp.Y?-?15;
break;?//上
case?2:
snakeArr[0].X?=?temp.X?+?15;
snakeArr[0].Y?=?temp.Y;
break;?//右
case?3:
snakeArr[0].X?=?temp.X;
snakeArr[0].Y?=?temp.Y?+?15;
break;?//下
case?4:
snakeArr[0].X?=?temp.X?-?15;
snakeArr[0].Y?=?temp.Y;
break;?//左
}
}
drt參數是鍵盤上上下左右鍵對應的數字,snakeLen是數組的長度也就是方格的個數,上面那個for循環主要的作用是把前壹個數組的坐標賦值給下壹個,就像是毛毛蟲爬行壹樣,後壹節會按照前壹節的路線來爬,下面那個switch的作用是,設置蛇頭的行進路線。?
再下面就是判斷蛇是否吃到食物、是否撞到墻和撞到自己,因為蛇和食物都是用坐標存儲的,所以只要判斷蛇頭坐標是否等於食物坐標就可以了:?
///?<summary>?
///?判斷是否吃到食物
///?</summary>?
public?bool?EatedFoot(Point?FoodLct)
{
if?(snakeArr[0].X?==?FoodLct.X?&&?snakeArr[0].Y?==?FoodLct.Y)
{
if?(snakeLen?<?SnakeMaxLength)
{
snakeLen++;
snakeArr[snakeLen].X?=?snakeArr[snakeLen?-?1].X;
snakeArr[snakeLen].Y?=?snakeArr[snakeLen?-?1].Y;
}
return?true;
}
else
return?false;
}
///?<summary>?
///?判斷是否撞到自己?
///?</summary>?
public?bool?CheckSnakeHeadInSnakeBody()
{
return?this.CheckInSnakeBody(this.snakeArr[0].X,?this.snakeArr[0].Y,?1);
}
///?<summary>?
///?檢查輸入的坐標是否在蛇的身上
///?</summary>?
public?bool?CheckInSnakeBody(int?x,?int?y,?int?snkHead)
{
for?(int?i?=?snkHead;?i?<?snakeLen;?i++)
{
if?(x?==?this.snakeArr[i].X?&&?y?==?this.snakeArr[i].Y)
{
return?true;
}
}?return?false;
}
///?<summary>?
///?判斷是否撞墻
///?</summary>?
///?<returns></returns>?
public?bool?CheckSnakeBodyInFrm()
{
if?(this.snakeArr[0].X?>=?594?||?this.snakeArr[0].Y?>=?399?-?32?||?this.snakeArr[0].X?<?0?||?this.snakeArr[0].Y?<?0)
return?true;
else
return?false;
}*/
/*實現上面的幾個步驟,簡單版的貪吃蛇基本上就完成了,再加上壹個timer控件,這樣蛇就會“動”起來了,就這麽簡單。?
完整代碼:*/
///?<summary>?
///?畫壹個小方塊
///?</summary>?
public?void?DrawShape(int?x,?int?y)
{
Graphics?g?=?this.CreateGraphics();
Pen?pen?=?new?Pen(Color.Blue,?2);
g.DrawRectangle(pen,?x,?y,?15,?15);
g.FillRectangle(Brushes.Green,?x,?y,?15,?15);
}
///?<summary>?
///?畫壹個食物
///?</summary>?
public?void?DrawFood(int?x,?int?y)
{
Graphics?g?=?this.CreateGraphics();
Pen?pen?=?new?Pen(Color.Red,?2);
SolidBrush?brush?=?new?SolidBrush(Color.Green);
g.DrawRectangle(pen,?x,?y,?15,?15);
g.FillRectangle(brush,?x,?y,?15,?15);
}
///?<summary>?
///?設置Point數組坐標
///?</summary>?
public?void?Forward(int?drt)
{
Point?temp?=?snakeArr[0];
for?(int?i?=?snakeLen?-?1;?i?>?0;?i--)
{
snakeArr[i].X?=?snakeArr[i?-?1].X;
snakeArr[i].Y?=?snakeArr[i?-?1].Y;
}
switch?(drt)
{
case?1:?snakeArr[0].X?=?temp.X;?snakeArr[0].Y?=?temp.Y?-?15;?break;?//上
case?2:?snakeArr[0].X?=?temp.X?+?15;?snakeArr[0].Y?=?temp.Y;?break;?//右
case?3:?snakeArr[0].X?=?temp.X;?snakeArr[0].Y?=?temp.Y?+?15;?break;?//下
case?4:?snakeArr[0].X?=?temp.X?-?15;?snakeArr[0].Y?=?temp.Y;?break;?//左
}
}
///?<summary>?
///?時間事件///?</summary>?
private?void?timer1_Tick(object?sender,?EventArgs?e)
{
Graphics?g?=?this.CreateGraphics();
g.Clear(Color.DarkKhaki);//清除整個畫面?
Forward(snakeDrt);
for?(int?i?=?0;?i?<?snakeLen;?i++)
{
DrawShape(snakeArr[i].X,?snakeArr[i].Y);
}
if?(panDuan)
{
ShowFood();//DrawFood(FoodLct.X,?FoodLct.Y);?
panDuan?=?false;
}
if?(EatedFoot(FoodLct))
{
ShowFood();
DrawFood(FoodLct.X,?FoodLct.Y);
}
else
{
DrawFood(FoodLct.X,?FoodLct.Y);
}
if?(CheckSnakeHeadInSnakeBody()?||?CheckSnakeBodyInFrm())
{
this.timer1.Enabled?=?false;
MessageBox.Show("遊戲結束!");
}
}
///?<summary>?
///?按下方向鍵
///?</summary>?
private?void?frmSnake_KeyDown(object?sender,?KeyEventArgs?e)
{
if?(e.KeyCode?==?Keys.Up)?snakeDrt?=?1;
else?if?(e.KeyCode?==?Keys.Down)
snakeDrt?=?3;
else?if?(e.KeyCode?==?Keys.Right)
snakeDrt?=?2;
else?if?(e.KeyCode?==?Keys.Left)
snakeDrt?=?4;
}
///?<summary>?
///?判斷是否撞到自己
///?</summary>?
public?bool?CheckSnakeHeadInSnakeBody()
{
return?this.CheckInSnakeBody(this.snakeArr[0].X,?this.snakeArr[0].Y,?1);
}
///?<summary>?
///?檢查輸入的坐標是否在蛇的身上
///?</summary>?
public?bool?CheckInSnakeBody(int?x,?int?y,?int?snkHead)
{
for?(int?i?=?snkHead;?i?<?snakeLen;?i++)
{
if?(x?==?this.snakeArr[i].X?&&?y?==?this.snakeArr[i].Y)
{
return?true;
}
}
return?false;
}
///?<summary>?
///?判斷是否撞墻
///?</summary>?
///?<returns></returns>?
public?bool?CheckSnakeBodyInFrm()
{
if?(this.snakeArr[0].X?>=?594?||?this.snakeArr[0].Y?>=?399?-?32?||?this.snakeArr[0].X?<?0?||?this.snakeArr[0].Y?<?0)
return?true;
else
return?false;
}
///?<summary>?
///?隨機顯示食物
///?</summary>?
public?void?ShowFood()
{
Random?rmd?=?new?Random();
int?x,?y;?x?=?rmd.Next(0,?this.Width?/?15)?*?15;
y?=?rmd.Next(0,?this.Height?/?15)?*?15;
//while?(this.CheckInSnakeBody(x,?y,?1))
//{
//x?=?rmd.Next(0,?32)?*?15;
//y?=?32?+?rmd.Next(0,?30)?*?15;
//}?
FoodLct.X?=?x;
FoodLct.Y?=?y;
}
///?<summary>?
///?判斷是否吃到食物
///?</summary>?
public?bool?EatedFoot(Point?FoodLct)
{
if?(snakeArr[0].X?==?FoodLct.X?&&?snakeArr[0].Y?==?FoodLct.Y)
{
if?(snakeLen?<?SnakeMaxLength)
{
snakeLen++;
snakeArr[snakeLen].X?=?snakeArr[snakeLen?-?1].X;?
snakeArr[snakeLen].Y?=?snakeArr[snakeLen?-?1].Y;
}?return?true;
}
else
return?false;
}
}
}