zoukankan      html  css  js  c++  java
  • c#游戏之路-wpf版本开发

    中间实在忙啊,隔了几天,终于有点时间,本来以为写博客很简单,不过现在感觉怎么把意思表达清楚真是件难事啊,所以,写的不好,园友们不要介意啊。

    话说,上回我打算开发游戏,考虑了4种技术,后来我发现无论哪种技术应该是都能实现,区别大概就是性能以及占用的资源吧,所以,我后来实现用的是wpf。当时在网上搜索了一下,发现曾经有人写过,也在国外的网站上找到了部分代码,所以就这么拼拼凑凑就把效果跑起来了。

    下面先上个效果图吧,算是这几天的一个成果。

    我这个是完全模仿《传奇》,屏幕所能容纳的物件数量是17*17,所以我在每一个格子上放置一格人物,并让这个人物进行运动,我的预想是,如果全屏幕人物运动的情况下还能达到10FPS,那么理论上实现《传奇》这样的游戏应该是可行的。

    下面是我的代码部分,要说实现上面这个效果,不算简单也不算难,主要应该是一些思想。我的项目名字叫做LightDarkLegend.

    典型的WPF项目,App.xaml是wpf默认的启动页,MainWindow.xaml是游戏的登录器页面,GameBox.xaml是游戏运行的页面,结构上来说还是非常简单的。

    其实最主要的核心就是这个MyDraw,也就是自定义的绘制控件。MyDraw的主要逻辑就是处理传入的人物、魔法、怪物、地图等参数,与原始数据进行比较,假如发现数据不同,则触发绘制,最终有自定义控件的OnRender方法呈现图像。

    核心代码MyMap类

    public class MyMap : INotifyPropertyChanged
        {
            private long x;
            public long X
            {
                get { return this.x; }
                set { if (this.x != value) { this.x = value; this.OnPropertyChanged("X"); } }
            }
            private long y;
            public long Y
            {
                get { return this.y; }
                set { if (this.y != value) { this.y = value; this.OnPropertyChanged("Y"); } }
            }
            private long moveX;
            private long moveY;
            public long MoveX { get => moveX; set => moveX = value; }
            public long MoveY { get => moveY; set => moveY = value; }
            private Map map;
            public Map Map
            {
                get { return this.map; }
                set { if (this.map != value) { this.map = value; this.OnPropertyChanged("Map"); } }
            }
            public event PropertyChangedEventHandler PropertyChanged;
            protected virtual void OnPropertyChanged(string propertyName)
            {
                if (this.PropertyChanged != null)
                    this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

    MyDraw类

     public class MyDraw : FrameworkElement
        {
            public WriteableBitmap mapBitMap;
            public WriteableBitmap magicBitMap;
            public WriteableBitmap monsterBitMap;
            public WriteableBitmap personBitMap;
            public WriteableBitmap itemBitMap;
            public WriteableBitmap controlBoxBitMap;
            
            public static int pixelWidth = 2040; //(int)myMap.Map.width;
            public static int pixelHeight = 1530; // (int)myMap.Map.height;
            public static int xGezi = 120;//一个砖块占用像素x
            public static int yGezi = 90;//一个砖块占用像素y
            public static int moveWidth = pixelWidth / xGezi;//人物x坐标移动格子数一屏幕
            public static int moveHeight = pixelHeight / yGezi;//人物y坐标移动格子数一屏幕
    
            public bool isLoadObject = false;//是否不进行绘制,进行元素加载。
    
            #region 我的地图
            public static readonly DependencyProperty myMapProperty =
               DependencyProperty.Register("map", typeof(MyMap), typeof(MyDraw),
               new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None, OnMyMapPropertyChanged));
    
            private static void OnMyMapPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                MyDraw draw = (MyDraw)d;
                MyMap myMap = (MyMap)e.NewValue;
                MyMap oldMap = (MyMap)e.OldValue;
                if (myMap != null && myMap.Map != null)
                {
                    if (oldMap != null && myMap.Map.id != oldMap.Map.id)
                    {
                        //LoadAllObject();//载入所有当前地图相关元素(地砖元素,建筑物,怪物图片)
                    }
                    //重新绘图
                    if (oldMap != null && oldMap.X == myMap.X && oldMap.Y == myMap.Y)//仅仅移动
                    {
                        draw.MoveMap((int)myMap.MoveX, (int)myMap.MoveY);
                        return;
                    }
                    draw.DrawMap();
                }
            }
    
            public MyMap myMap
            {
                get { return (MyMap)GetValue(myMapProperty); }
                set { SetValue(myMapProperty, value); }
            }
    
            Image GetImage(int x, int y)
            {
                int index = x * (int)myMap.Map.width + y;
                return myMap.Map.layouts[0].metros[index].img;
            }
    
            void DrawMap()
            {
                int x = (int)myMap.X;//人物x坐标
                int y = (int)myMap.Y;//人物y坐标
    
                //需要根据人物所在坐标,取得地图的点阵数据
                int moveMinX = x - moveWidth / 2-1;
                int moveMaxX = x + moveWidth / 2 + 2;
                int moveMinY = y - moveHeight / 2-1;
                int moveMaxY = y + moveHeight / 2 + 2;
    
    
                mapBitMap.Lock();
    
                //双重缓存
                using (Bitmap backBufferBitmap = new Bitmap(pixelWidth, pixelHeight,
                   mapBitMap.BackBufferStride, System.Drawing.Imaging.PixelFormat.Format32bppPArgb,
                   mapBitMap.BackBuffer))
                {
                    using (Graphics backBufferGraphics = Graphics.FromImage(backBufferBitmap))
                    {
                        backBufferGraphics.Clear(System.Drawing.Color.Black);
    
                        DateTime de = DateTime.Now;
    
                        //绘制地表
                        int drawX = -1;
                        for (int i = moveMinX; i < moveMaxX; i++)//获得数据进行绘制
                        {
                            int drawY = -1;
                            for (int j = moveMinY; j < moveMaxY; j++)
                            {
                                if (i < 0 || j < 0)
                                {
                                    //超出地图范围,以空元素代替
                                    //不进行绘制
                                }
                                else
                                {
                                    backBufferGraphics.DrawImage(GetImage(i, j), drawX * xGezi, drawY * yGezi);
                                }
                                drawY += 1;
                            }
                            drawX += 1;
                        }
    
                        backBufferGraphics.Flush();
                        DateTime de2 = DateTime.Now;
                        TimeSpan dm = de2 - de;
                    }
                }
    
                //结束绘制
                mapBitMap.AddDirtyRect(new Int32Rect(0, 0, pixelWidth, pixelHeight));
                mapBitMap.Unlock();
            }
    
            #endregion
    
            public MyDraw()
            {
                if (mapBitMap == null || (mapBitMap != null && (mapBitMap.PixelWidth != pixelWidth || mapBitMap.PixelHeight != pixelHeight)))
                {
                    mapBitMap = new WriteableBitmap(pixelWidth, pixelHeight, 96, 96, PixelFormats.Pbgra32, null);
                }
            }
    
    
            protected override void OnRender(DrawingContext drawingContext)
            {
                drawingContext.DrawImage(mapBitMap, new Rect(0, 0, RenderSize.Width, RenderSize.Height));
            }
        }

    发现,粘贴代码确实比较麻烦,尤其是代码量非常大的时候,看来下次我得考虑使用git或者自己部署一套代码系统,希望能更方便一点。另外我发现自己平常得我基本上都是别人问我问题我答得头头是道,真要让我自己写文章还真是一大挑战啊,大家有什么好得思路都欢迎评论。

  • 相关阅读:
    POJ 1328 Radar Installation
    POJ 1700 Crossing River
    POJ 1700 Crossing River
    poj 3253 Fence Repair (贪心,优先队列)
    poj 3253 Fence Repair (贪心,优先队列)
    poj 3069 Saruman's Army(贪心)
    poj 3069 Saruman's Army(贪心)
    Redis 笔记与总结2 String 类型和 Hash 类型
    数据分析方法有哪些_数据分析方法
    数据分析方法有哪些_数据分析方法
  • 原文地址:https://www.cnblogs.com/csharp-game/p/6961151.html
Copyright © 2011-2022 走看看