js333 > 计算机互联网 > 游戏之路

原标题:游戏之路

浏览次数:174 时间:2019-11-07

c#游戏之路-wpf版本开发,

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

 

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

 

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

金沙js333娱乐场 1

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

 

好了,如果您对我上面的实现感兴趣,那么估计就要问我代码是怎么样的了,哈哈,我会说的,要说实现上面这个效果,不算简单也不算难,主要应该是一些简单的思想。我的项目名字叫做LightDarkLegend.

金沙js333娱乐场 2

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

金沙js333娱乐场 3

金沙js333娱乐场 4

其实最主要的核心就是这个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或者自己部署一套代码系统,希望能更方便一点。另外我发现自己平常得我基本上都是别人问我问题我答得头头是道,真要让我自己写文章还真是一大挑战啊,大家有什么好得思路都欢迎评论。

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

C#游戏之路-winform,wpf,directx,opengl的了解,

终于审核通过了,开通了我的博客,虽然这么多年,已经长期在从事java相关的架构工作,但是,其实我内心,喜欢的语言一直是c#,可惜,很多时候光靠一人的力量,改变不了什么,现在的我,打算抛开自己的工作,做自己真正喜欢的事情,我开这个博客的目的主要就是为了用c#来开发大型游戏,我的第一个目标,打算使用c#实现《传奇》这样的大型网络游戏,这样的游戏会分成服务端和客户端分别开发,我的前期目标是先实现客户端,如果想了解服务端的可以订阅我,我后续会一并写完的。

从现在开始重拾8年前的c#确实有点生疏,但其实很多思想都是想通的,当然做游戏,首先要选择一种适合的技术。

今天,我主要是罗列了4项我还有点印象的实现方式。

金沙js333娱乐场 ,winform,wpf,directx,opengl,下面分别说说我对这4种实现方式的理解吧,也算是给自己理个思路。

 

winform

winform这个技术我算是最熟悉的,记得大学毕业的时候,就是用winform做了个爬虫类的应用,专门爬网络上的美女图片,以致于老师们看到那么多美女图片,就给了我一个优秀毕业设计称号,哈哈,所以,其实我第一个想到的就是winform。对于winform,实现思路我想应该是一个窗口,里面放一个绘图控件,然后重写这个绘图控件,实现自己的自定义绘制,用的类那应该就是System.Drawing下面的那些类。在这里我想了下,要实现《传奇》这样的游戏,winform的绘图性能应该是一个考验,另外,游戏动画特别多,而且很多动画都是同时存在的,这样的难题应该是个考虑,我的想法是先新建多个bitmap,预先把绘制绘制到内存中,然后统一时间刷新,比如100MS刷新一次,那就是每秒10帧,曾经分析过传奇的代码,差不多就是每秒10帧这样的程度。

 

wpf

关于wpf这个,我也是在博客园里看到了一些相关的文章,有些人说wpf是完全重写的一套绘图机制,而且可以利用GPU进行加速,所以,我打算对wpf这个也研究一番,如果按照我理解的方式,我认为wpf的实现应该跟winform有点类似,而且据我一般的了解,我发现wpf做游戏控制界面非常容易,比如拖动,拖动动画之类相对容易实现,所以wpf也不失为一种好的方案。

 

directx

说到这个,网上搜了一大圈,经过总结,基本大部分都觉得win平台下directx是开发游戏最好的解决方案,也是目前成功游戏最多的解决方案,但是我看了下相关的sdk,我发现,假如用directx开发游戏,如果没有合适的游戏引擎,想要一个人实现《传奇》这样的大型游戏,感觉就是一个人建长城的工程,但是如果使用别人的引擎,我发现好多都是c++的语言,奈何我对c++不是特别熟,所以,我原则上认为directx是属于重量级的解决方案,需要更进一步了解。

 

opengl

和directx类似,也是重量级解决方案,有个不同的地方就是opengl是开源的,相对来说,实现自己的游戏引擎难度低一点,我记得我以前最喜欢玩的《暗黑破坏神2》好像就是用的opengl,说起来,如果光从客户端的角度来讲,《暗黑破坏神2》和《传奇》还是非常相似的,不过《暗黑破坏神2》的实现应该比《传奇》要复杂,因为《传奇》只有8个方位。而《暗黑破坏神2》应该是不止8个方位判定的,需要进一步了解。

 

今天,算是个开头吧,在博客园发文章不发代码好像不是好习惯,哈哈,不过这篇文章算是个开头吧,说实话,做这种大型项目,尤其是没有一分钱的情况下,纯属自己的爱好,难度倒还可以,就怕容易放弃,所以,开通博客园,写出来,也希望能获得更多人的支持,下一篇,我将会正式开始讲这个工程,以及相关的代码。

终于审核通过了,开通了我的博客,虽然这么多年,已经长期在从事java相关的架构工作,但是,其...

本文由js333发布于计算机互联网,转载请注明出处:游戏之路

关键词:

上一篇:没有了

下一篇:没有了