zoukankan      html  css  js  c++  java
  • x01.Game.Dragon.1: 恐龙飞行

     与其白手起家,不如学习高手。恐龙飞行是个不错的入门例子,实现如下。

    1.运行 VS2010,新建 WinForm 项目 x01.Game.Dragon,将 Form1.cs 改名为 MainForm.cs,在 MainForm 类中,添加字段

      bool  isOver = false;

      添加引擎函数 Run(),代码如下:

    Run()
    void Run()
    {
        while (!isOver)
        {
            Application.DoEvents();
        }
        Application.Exit();
    }

      添加 override 函数 OnKeyDown(),代码如下:

    OnKeyDown()
            protected override void OnKeyDown(KeyEventArgs e)
            {
                switch (e.KeyCode)
                {
                    case Keys.Enter:
                        Run();
                        break;
                    case Keys.Escape:
                        GameOver();
                        break;
                    case Keys.Up:
                        break;
                    case Keys.Right:
                        break;
                    case Keys.Down:
                        break;
                    case Keys.Left:
                        break;
                }
            }

      添加退出函数 GameOver(),代码如下:

    GameOver()
            private void GameOver()
            {
                isOver = true;
            }

      如此,游戏框架完成。虽然现在什么都不干,但看 OnKeyDown() 函数,不难发现,Enter 键开始,Esc 键结束,箭头键控制飞行方向。

    2.游戏说白了,就是操作图形,GDI+ 是个不错的选择。Graphics 提供操作方法,Bitmap 提供被操作对象,将 Bitmap 提供给 PictureBox 的 Image 属性,即可实现游戏的基本场景。添加类 GameBox,继承自 PictureBox。其代码文件 GameBox.cs 的内容如下:

    GameBox
        class GameBox : PictureBox
        {
            Graphics device;
            Bitmap surface;
            Font font;
    
            public GameBox(int width, int height)
            {
                BackColor = Color.Black;
    
                surface = new Bitmap(width, height);
                Image = surface;
                device = Graphics.FromImage(surface);
    
                font = new Font("Arial", 18, FontStyle.Regular, GraphicsUnit.Pixel);
            }
    
            protected override void Dispose(bool disposing)
            {
                device.Dispose();
                surface.Dispose();
                font.Dispose();
    
                base.Dispose(disposing);
            }
    
            public Graphics Device
            {
                get { return device; }
            }
    
            public void Refresh()
            {
                Image = surface;
            }
    
            public void Print(int x, int y, string text, Brush brush = null)
            {
                if (brush == null)
                {
                    brush = Brushes.White;
                }
    
                Device.DrawString(text, font, brush, x, y);
            }
        }

      Print() 是为了输出文本,Device 是为了提供操作,如此而已。
    3.终于到了核心的部分:Sprite 类。其代码文件 Sprite.cs 内容如下:

    Sprite
        class Sprite
        {
            public enum FrameDirectionE
            {
                Forward = 1, Backward = -1, None = 0
            }
            public enum FrameWrapE
            {
                Wrap, Bounce
            }
    
            GameBox gameBox;
    
            public Sprite(ref GameBox box)
            {
                gameBox = box;
                Rate = 30;
                FrameDirection = FrameDirectionE.Forward;
            }
    
            public PointF Position { get; set; }
            public PointF Offset { get; set; }
            public Size Size { get; set; }
            public Bitmap Image { get; set; }
            public int Columes { get; set; }
            public int Frames { get; set; }
            public int CurrentFrame { get; set; }
            public FrameDirectionE FrameDirection { get; set; }
            public FrameWrapE FrameWrap { get; set; }
            public int Rate { get; set; }
            public Rectangle Bound
            {
                get { return new Rectangle((int)Position.X, (int)Position.Y, Size.Width, Size.Height); }
            }
    
            public void Animation(int startFram, int endFrame)
            {
                int lastTime = 0;
                int time = Environment.TickCount;
                if (time > lastTime + Rate)
                {
                    lastTime = time;
                    CurrentFrame += (int)FrameDirection;
                    switch (FrameWrap)
                    {
                        case FrameWrapE.Wrap:
                            if (CurrentFrame < startFram)
                            {
                                CurrentFrame = endFrame;
                            }
                            else if (CurrentFrame > endFrame)
                            {
                                CurrentFrame = startFram;
                            }
                            break;
                        case FrameWrapE.Bounce:
                            if (CurrentFrame < startFram)
                            {
                                CurrentFrame = startFram;
                                FrameDirection = FrameDirectionE.Forward;
                            }
                            else if (CurrentFrame > endFrame)
                            {
                                CurrentFrame = endFrame;
                                FrameDirection = FrameDirectionE.Backward;
                            }
                            break;
                        default:
                            break;
                    }
                }
            }
    
            public void Draw()
            {
                Rectangle frame = new Rectangle();
                frame.X = (CurrentFrame % Columes) * Size.Width;
                frame.Y = (CurrentFrame / Columes) * Size.Height;
                frame.Width = Size.Width;
                frame.Height = Size.Height;
                gameBox.Device.DrawImage(Image, Bound, frame, GraphicsUnit.Pixel);
            }
        }

      仔细一看,只有两个方法:Animation() 和 Draw()。Draw() 比较简单,就是把需要的 Frame 绘制到指定的位置。Animation() 则是通过设置控制 Frame 的移动,以形成动画效果。
    4.有了 GameBox 和 Sprite,再回到 MainForm 就简单了。最后的代码文件 MainForm.cs 内容如下:

    MainForm
        public partial class MainForm : Form
        {
            const string ImgDir = @"F:\Resource\Image\game\";
    
            GameBox gameBox;
            Sprite sprite;
            Bitmap dragon;
            Bitmap grass;
            PointF offset;
    
            bool isOver = false;
            int direction = 2;
    
            public MainForm()
            {
                InitializeComponent();
                Init();
            }
    
            protected override void OnClosed(EventArgs e)
            {
                GameOver();
            }
            protected override void OnKeyDown(KeyEventArgs e)
            {
                switch (e.KeyCode)
                {
                    case Keys.Enter:
                        Run();
                        break;
                    case Keys.Escape:
                        GameOver();
                        break;
                    case Keys.Up:
                        direction = 0;
                        break;
                    case Keys.Right:
                        direction = 2;
                        break;
                    case Keys.Down:
                        direction = 4;
                        break;
                    case Keys.Left:
                        direction = 6;
                        break;
                }
            }
    
            void Run()
            {
                int currentTime = 0, startTime = 0;
                while (!isOver)
                {
                    currentTime = Environment.TickCount;
                    if (currentTime > startTime + 16)
                    {
                        startTime = currentTime;
                        Draw();
                        Application.DoEvents();
                        gameBox.Refresh();
                    }
                }
                Application.Exit();
            }
            private void GameOver()
            {
                isOver = true;
            }
            private void Init()
            {
                Text = "Dragon Game";
                Size = new Size(800, 600);
    
                gameBox = new GameBox(800, 600);
                gameBox.Parent = this;
                gameBox.Dock = DockStyle.Fill;
                gameBox.Print(10, 10, "Enter: 开始");
                
                dragon = new Bitmap(ImgDir + "dragon.png");
                grass = new Bitmap(ImgDir + "grass.bmp");
    
                sprite = new Sprite(ref gameBox);
                sprite.Image = dragon;
                sprite.Size = new Size(256, 256);
                sprite.Columes = 8;
                sprite.Frames = 64;
                sprite.Position = new PointF(250, 150);
                
            }
    
            void Draw()
            {
                gameBox.Device.DrawImageUnscaled(grass, 0, 0, 800, 600);
    
                switch (direction)
                {
                    case 0: // up
                        offset = new PointF(0, -1);
                        break;
                    case 2: // right
                        offset = new PointF(1, 0);
                        break;
                    case 4: // down
                        offset = new PointF(0, 1);
                        break;
                    case 6: // left
                        offset = new PointF(-1, 0);
                        break;
                    default:
                        break;
                }
    
                sprite.Position = new PointF(sprite.Position.X + offset.X, sprite.Position.Y + offset.Y);
                sprite.Animation(direction * 8 + 1, direction * 8 + 8);
                sprite.Draw();
    
                gameBox.Print(0, 0, "Esc: 结束\t->: 方向");
            }
        }

      其中 ImgDir 应作适当调整。dragon.png 文件是 8*8 的 Frame 集合,0,2,4,6 行分别表示上、右、下、左方向。相关资源,可到我的 x01.download 中下载。

    5.本例学自《Virtual C# Game Programming for Teens》,但作了点精简,以突出主干。一本好书胜过一个好老师,的确如此。运行效果图如下:

  • 相关阅读:
    LeetCode:Container With Most Water
    c#编写的基于Socket的异步通信系统
    关于Thread类中三个interrupt方法的研究与学习(转)
    使用svnkit 的相关实例及相关问题汇总
    创业早期,联合创始人如何避免窝里反?(转)
    程序员解决问题的60个策略(转)
    码农和程序员之间的5个关键差异(转)
    LayoutInflater的使用
    2014年中国95家企业入围世界500强,超日本
    How to get the source code of the chromium of the specified revision
  • 原文地址:https://www.cnblogs.com/china_x01/p/2491674.html
Copyright © 2011-2022 走看看