人生就像一条加速奔向死亡的贪吃蛇【winform版】

群里聊天的时候,一个学妹说她在做贪吃蛇的小作业,于是昨晚(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

 

posted @ 2016-05-21 13:30  大萝卜卜  阅读(1831)  评论(10编辑  收藏  举报