群里聊天的时候,一个学妹说她在做贪吃蛇的小作业,于是昨晚(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 = ; //格子大小
整个游戏节奏由定时器驱动,当蛇长度到达预定长度,定时器将会缩短时间间隔,加快游戏进度(到100毫秒的时候,已经丧病了)
private void Speed()
{
if (snake.Count == )
{
timer1.Interval = ;
level = ;
} ........ else if (snake.Count == )
{
timer1.Interval = ;
level = ;
}
}
绘制代码就不详细解释了,有点乱,如果您有耐心可以把它们抽离出来写到一个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 <= ) //撞墙
{
GameOver();
}
foreach (var po in snake)
{
if (po.Y + == head.Y && po.X == head.X) //吃掉自己
{
GameOver();
break;
}
}
if (state == GameState.Over)
break; if (food.Y + == head.Y && food.X == head.X) //吃掉食物
{
snake.Enqueue(food);
head = food;
GenerateFood();
}
else //向前移动一格
{
snake.Dequeue();
head = new Pos(head.X, head.Y - );
snake.Enqueue(head);
}
}
break;
case Direction.Down:
整个程序的结构到此介绍完毕,总的来说是一个比较完整的小游戏了,当然有很多地方可以优化,但个人也就没那个兴趣和精力了(笑)
下载地址:GreedySnake