zoukankan      html  css  js  c++  java
  • 人生就像一条加速奔向死亡的贪吃蛇【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 开始游戏,空格 暂停/继续游戏 
    
    奔向死亡吧,骚年!", 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

  • 相关阅读:
    python:JSON的两种常用编解码方式实例解析
    Python中的map与reduce函数简介
    Python初学者的几个迷惑点
    Python Numpy中数据的常用的保存与读取方法
    python全栈 day03 操作系统 -- 摘要
    python全栈 day02 计算机原理 -- 硬件
    Python作业之购物商城
    Lesson one of python
    总体设计
    ASP.Net页面上用户控件相互调用的方法
  • 原文地址:https://www.cnblogs.com/HelliX/p/5514595.html
Copyright © 2011-2022 走看看