群里聊天的時候,一個學妹說她在做貪吃蛇的小作業,於是昨晚(5.20無聊只好擼代碼/(ㄒoㄒ)/~~)花了2個小時擼了一個出來,早上又花了些時間完善功能,就有了這個還算比較完善的版本,當然代碼結構比較混亂,沒有抽像成類,后來搜索了博客園以前的,發現都只是實現了基本的功能,根本不能愉快的玩耍。

整個程序只定義了一個Pos類來保存點的x,y坐標值
//位置類 class Pos { public int X; public int Y; public Pos(int x, int y) { X = x; Y = y; } }
蛇身體用一個隊列來保存Pos信息,使用隊列雖然方便了蛇尾移出和蛇頭添加,卻不能直接得到蛇頭信息,所以獨立變量保存,食物也是一個獨立的Pos變量記錄其位置
Pos food; //食物位置 Queue<Pos> snake;//蛇身體隊列 Pos head; //蛇頭位置 int x,y; //橫豎線條數 int cubeL = 22; //格子大小
整個游戲節奏由定時器驅動,當蛇長度到達預定長度,定時器將會縮短時間間隔,加快游戲進度(到100毫秒的時候,已經喪病了)
private void Speed() { if (snake.Count == 7) { timer1.Interval = 450; level = 2; } ........ else if (snake.Count == 60) { timer1.Interval = 100; level = 8; } }
繪制代碼就不詳細解釋了,有點亂,如果您有耐心可以把它們抽離出來寫到一個Snake類里面
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.TranslateTransform(20, 50);
Pen pen = new Pen(Color.Green,1);
//繪制網格
for (int i = 0; i < x+1; i++)
{
e.Graphics.DrawLine(pen, i * cubeL, 0, i * cubeL, y * cubeL);
}
for (int j = 0; j < y+1; j++)
{
e.Graphics.DrawLine(pen, 0, j * cubeL, x * cubeL, j * cubeL);
}
SolidBrush brush = new SolidBrush(Color.Orange);
//繪制蛇
if (state != GameState.Init)
{
e.Graphics.FillRectangle(brush, food.X * cubeL, food.Y * cubeL, cubeL, cubeL);
brush.Color = Color.DeepSkyBlue;
foreach (var p in snake)
{
e.Graphics.FillRectangle(brush, p.X * cubeL, p.Y * cubeL, cubeL, cubeL);
}
brush.Color = Color.Blue;
e.Graphics.FillRectangle(brush, head.X * cubeL, head.Y * cubeL, cubeL, cubeL);
brush.Color = Color.Red;
}
//繪制狀態提示
if(state == GameState.Init)
{
brush.Color = Color.Red;
e.Graphics.DrawString("S 開始游戲,空格 暫停/繼續游戲 \n\r奔向死亡吧,騷年!", new Font("微軟雅黑", 20), brush, 150, 120);
}
else if (state == GameState.Start)
{
if (!timer1.Enabled)
e.Graphics.DrawString("游戲暫停,空格繼續!", new Font("微軟雅黑", 20), brush, 150, 120);
}
else
{
brush.Color = Color.Red;
e.Graphics.DrawString("游戲結束,S 開始游戲!", new Font("微軟雅黑", 20), brush, 150, 120);
}
e.Graphics.ResetTransform();
string tip = "level:"+level.ToString()+" 長度: "+snake.Count.ToString()+ " 分數:"+(snake.Count*level*10).ToString();
brush.Color = Color.Black;
e.Graphics.DrawString(tip, new Font("微軟雅黑", 15), brush, 360, 10);
}
鍵盤輸入處理,輸入的鍵被暫時保存在一個Direction枚舉變量中,直到移動之后才確定為當前移動方向(否則會出現bug,比如先其他方向,再反方向就會出錯)
private void Form1_KeyDown(object sender, KeyEventArgs e) { switch(e.KeyCode) { case Keys.Up: if(Dir != Direction.Down) //不能向當前方向的反方向移動 tmpDir = Direction.Up; //臨時保存,移動之后才確定為當前方向 break;
.......
case Keys.Space: if(state == GameState.Start) { timer1.Enabled = !timer1.Enabled; Invalidate(); } break; case Keys.S: if (state == GameState.Start) { timer1.Enabled = false; if (MessageBox.Show("確定重新開始游戲?", "提示", MessageBoxButtons.OKCancel) == DialogResult.Cancel) { timer1.Enabled = true; break; } } StartGame(); break; } } }
蛇的移動,食物,游戲是否結束判斷
switch (Dir) //使用策略模式來替代switch { case Direction.Up: { if (head.Y <= 0) //撞牆 { GameOver(); } foreach (var po in snake) { if (po.Y + 1 == head.Y && po.X == head.X) //吃掉自己 { GameOver(); break; } } if (state == GameState.Over) break; if (food.Y + 1 == head.Y && food.X == head.X) //吃掉食物 { snake.Enqueue(food); head = food; GenerateFood(); } else //向前移動一格 { snake.Dequeue(); head = new Pos(head.X, head.Y - 1); snake.Enqueue(head); } } break; case Direction.Down:
整個程序的結構到此介紹完畢,總的來說是一個比較完整的小游戲了,當然有很多地方可以優化,但個人也就沒那個興趣和精力了(笑)
下載地址:GreedySnake
