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或者自己部署一套代碼系統,希望能更方便一點。另外我發現自己平常得我基本上都是別人問我問題我答得頭頭是道,真要讓我自己寫文章還真是一大挑戰啊,大家有什么好得思路都歡迎評論。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM