c#游戲之路-wpf版本開發

来源:http://www.cnblogs.com/csharp-game/archive/2017/06/08/6961151.html
-Advertisement-
Play Games

中間實在忙啊,隔了幾天,終於有點時間,本來以為寫博客很簡單,不過現在感覺怎麼把意思表達清楚真是件難事啊,所以,寫的不好,園友們不要介意啊。 話說,上回我打算開發游戲,考慮了4種技術,後來我發現無論哪種技術應該是都能實現,區別大概就是性能以及占用的資源吧,所以,我後來實現用的是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或者自己部署一套代碼系統,希望能更方便一點。另外我發現自己平常得我基本上都是別人問我問題我答得頭頭是道,真要讓我自己寫文章還真是一大挑戰啊,大家有什麼好得思路都歡迎評論。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Android系統在運行每一個程式應用的時候,都會創建一個Application對象,用於存儲與整個應用相關的公共變數。一個Android應用只會生成一個Application對象,在不同的Activity中獲取的Application對象是一樣的,所以Application對象是一個單例(Sing ...
  • 轉載請註明:http://www.cnblogs.com/igoslly/p/6947225.html 下一章是關於ListFragment的內容,首先先介紹ListView的相關配置,理解ListFragment也相較容易。 在fznpcy專欄:http://blog.csdn.net/fznpc ...
  • 目錄 零、主要參考網頁 一、概述 二、分區類型以及創建方式 三、分區表的管理 三、分區表的管理 四、獲取分區表信息 四、獲取分區表信息 五、分區的局限與分表 零、主要參考網頁 http://www.2cto.com/database/201503/380348.html【mysql分表和表分區詳解】 ...
  • 目錄 零、參考網頁 一、概述 二、語法 三、外鍵 四、索引 零、參考網頁 http://zhidao.baidu.com/link?url=ik8ZtrHL2qfZMgQStSFEcP2ORechkwBzbxBQjMQ15SoCV11-rRv5buPIPLZBZu570-YWRoAFsqANBiII ...
  • 卸載MariaDB CentOS7預設安裝MariaDB而不是MySQL,而且yum伺服器上也移除了MySQL相關的軟體包。因為MariaDB和MySQL可能會衝突,故先卸載MariaDB。 1、安裝新版mysql之前,我們需要將系統自帶的mariadb-lib卸載 2、到mysql的官網下載最新版 ...
  • 恢復內容開始 [20170603]12c Top Frequency histogram.txt--//個人對直方圖瞭解很少,以前2種直方圖類型對於目前的許多應用來講已經足夠,或者講遇到的問題很少.--//抽一點點時間,簡單探究12c Top Frequency histogram.--//以前的頻 ...
  • INFORMATION_SCHEMA PROFILING "Table" PROFILING表提供了語句分析信息。 其內容對應於SHOW PROFILES和SHOW PROFILE語句生成的信息. INFORMATION_SCHEMA Name|SHOW Name| Notes |: |: QUER ...
  • 下麵簡單介紹一下如何在Red Hat Enterprise Linux上一步一步創建一個SQL Server AG(Always On Availability Group),以及配置過程中遇到的坑的填充方法。 之前發表過一篇類似的文章是Configure Always On Availabilit ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...