1. 程式人生 > >Unity3D遊戲開發之當遊戲開發遇上Excel

Unity3D遊戲開發之當遊戲開發遇上Excel

各位朋友,大家好,我是秦元培,歡迎大家關注我的部落格,我的部落格地址是http://blog.csdn.net/qinyuanpei
今天我們的話題是Excel,作為常用的辦公軟體的Excel相信大家都不陌生啦。可是如果我們認為Excel只是辦公軟體的話,那麼這就不只是天真而是Out了。事實上Excel和遊戲開發有著密切的聯絡,不知道大家還記不記得那款利用Excel開發出來的三國殺,這可能是Excel第一次以遊戲開發的身份出現在大家面前吧。我們知道在遊戲開發領域有一種工作叫做策劃,就像在軟體開發領域有一種工作叫做產品經理一樣。而在諸多的策劃工作中,數值策劃是一個可以直接影響遊戲程序的工作,因為數值策劃體現了一個遊戲在整體數值上的平衡,設計者需要維護好這樣一個平衡,確保遊戲外的玩家和遊戲裡的敵人面對的是同一個公平的虛擬世界。

例如《仙劍奇俠傳四》這款遊戲中,韓菱紗在遊戲後期的速度可以說是完全打破了遊戲的平衡性,因為韓菱紗本身的速度就比較快,再加上仙風雲體術的加速效果完全對玄霄產生了戲劇性壓制,導致在遊戲結尾的Boss戰中經常是韓菱紗出手N次後才捱到玄霄出手,我們知道韓菱紗的乾坤一擲每次消耗氣15,可是因為韓菱紗的速度足夠快,所以韓菱紗完全可以通過普通物理攻擊快速地積滿氣進而施展乾坤一擲,這就是遊戲的平衡性被打破了呀,更不要說這部遊戲裡最為經典的千方殘光劍Bug了,這同樣是遊戲平衡性的問題,歸根到底是紫英的這個技能在配置資料時出現了錯誤,這充分說明資料的正確合理與否是會對遊戲產生重要影響的。
乾坤一擲
千方殘光劍
儘管我們可以使用Xml、Json、ini、資料庫等儲存形式來儲存這些資料,可是毫無疑問的是,Excel是Window平臺上最好的資料處理軟體,因此數值策劃更傾向於使用Excel來設計遊戲中的資料,面對如此重要的數值策劃工作,我們自然希望在解析Excel檔案時不會出現錯誤,可是我們總不能指望著策劃把Excel資料轉換成我們能處理的資料型別吧,因此就有了博主今天的這篇文章,所以在今天的文章中我們主要的內容就是如何通過程式來解析Excel檔案。

1、專案需求

最近博主一個朋友向我抱怨,說手頭上有好幾百個Excel工作表要處理,大概幾十萬條資料吧。原因是當時公司分配任務時交待不清,等到了向公司交接資料的時候,朋友忽然發現這些Excel檔案的表格格式和公司規定的不一樣啊。這可急壞了博主的這位朋友,博主的朋友只好不斷地的複製、黏貼,因為這些資料是分佈在不同的資料表裡,朋友整天都忙得焦頭爛額,可是即使這樣效率還是得不到保證啊,朋友最後找到了博主這裡,問我能不能編寫程式幫他解決這個問題。因為平時經常與技術圈子裡的朋友聊天,所以在博主印象裡Excel的解析在遊戲開發中還是較為常見的,而且博主知道對於微軟的Office辦公軟體是可以通過VBA程式設計來實現某些功能的,可是因為博主一直在用國產的WPS,所以對於Excel的解析基本上是停留在一個概念性的認識上,可是朋友的忙不能不幫不是,所以博主決定藉著這個機會好好研究下Excel檔案的解析。

2、解決方案

因為博主在之前並沒有過解析Excel檔案的經歷,所以博主就到Github上淘了些開源專案。和很多人愛逛天貓、淘寶的經歷類似,如果你發現有一個人經常喜歡到Github上晃盪、喜歡關注技術類的部落格或者資訊、經常再看PDF版的技術文件或書籍,請千萬不要懷疑,這個人絕對是程式設計師。哈哈,好了,玩笑就此打住啊。經過博主對這些開源專案的簡單分析和整理,目前,對Excel檔案解析的解決方案主要有以下三種:

1、Microsoft.Office.Interop.Excel

第一種解決方案是基於微軟提供的Office API,這組API以COM元件的形式給出,我們可以通過呼叫該API實現對Excel檔案的解析。使用這組API非常簡單,博主稍後會為大家給出一個示例程式碼。微軟的Office API特點是使用起來方便,可以使用C#、Visual Basic等語言進行相關開發。可是這種解決方案的的缺點同樣很明顯,因為COM元件主要依賴於系統,因此使用COM元件需要在系統中註冊,這將對程式碼的可移植性產生影響,而且受制於COM技術,這種解決方案只能執行在Windows平臺上,無法實現跨平臺,加之解析速度較慢,因此這種方案通常只適合在解析速度要求不高,執行環境為Windows平臺的應用場景。

第二種解決方案得益於OpenOffice標準,OpenOffice標準可以讓我們使用一種標準來解析和處理Excel檔案而無需關注Excel檔案是來自微軟的Misrosoft Office、金山的WPS還是其它的辦公軟體。如果說第一種解決方案是Windows平臺上解析Excel檔案的選擇之一,那麼ExcelRead就是跨平臺目標下解析Excel檔案的首選方案。尤其像Unity3D這樣的跨平臺解決方案下,選擇一個跨平臺的類庫或者元件能夠保證我們的遊戲在各種平臺下穩定地執行,所以ExcelRead是博主向大家推薦的一個跨平臺的Excel解析方案。

第三種解決方案FastExcel是博主在解決博主的這位朋友的問題時所採取的方案。FastExcel是一個在開源世界裡比較著名的Excel讀寫的類庫,因此使用這個類庫可以得到較為廣泛的社群支援,而且在FastExcel這個專案的原始碼中,作者為我們提供了使用FastExel進行Excel解析的相關示例,具有較高的參考價值,基本上可以在這個示例的基礎上寫出可以執行的程式碼。根據示例程式碼的執行結果使用FastExcel單獨讀寫100000行資料基本上維持在3~4秒,讀寫速度還是蠻快的。不過FastExcel使用的是迭代器和Linq to Xml來讀取Excel檔案的,所以當資料表中存在空白單元格時,讀寫的時候會比較詭異,這一點希望大家注意。

3、工程案例

既然今天的主題是Unity3D遊戲開發,所以無論我們在前面提出了什麼樣的解決方案,最後我們都要落實到遊戲開發上,所以最後和大家分享的是一個Unity3D配合ExcelReader實現Excel解析的簡單案例。為什麼要選擇ExcelReader呢?因為ExcelReader是一個跨平臺的解決方案。好了,下面我們一起來學習這個案例:

using UnityEngine;
using System.Collections;
using System.IO;
using Excel;
using System.Data;


public class ExcelScripts : MonoBehaviour 
{

    void Start () 
    {
        FileStream m_Stream=File.Open(Application.dataPath + 
            "\\Excel\\UserLevel.xlsx",FileMode.Open,FileAccess.Read);
        //使用OpenXml讀取Excel檔案
        IExcelDataReader mExcelReader=ExcelReaderFactory.CreateOpenXmlReader(m_Stream);
        //將Excel資料轉化為DataSet
        DataSet mResultSets=mExcelReader.AsDataSet();
        //讀取行數
        int rowCount=mResultSets.Tables[0].Rows.Count;
        //逐行讀取,從第一行讀以跳過表頭
        for(int i=1;i<rowCount;i++)
        {
            //將讀取的Excel資料轉化成資料實體
            UserLevel mUser=new UserLevel();
            mUser.Name=mResultSets.Tables[0].Rows[i][0].ToString();
            mUser.Level=mResultSets.Tables[0].Rows[i][1].ToString();
            mUser.Description=mResultSets.Tables[0].Rows[i][2].ToString();
            mUser.Skill=mResultSets.Tables[0].Rows[i][3].ToString();
            //輸出Debug資訊
            Debug.Log(mUser.ToString());
            //ADD:更多邏輯
        }
    }

    //定義一個數據實體類UserLevel
    private class UserLevel
    {
        private string m_Name;
        public string Name 
        {
          get { return m_Name;}
          set { m_Name = value;}
        }

        private string m_Level;
        public string Level 
        {
          get { return m_Level;}
          set { m_Level = value;}
        }

        private string m_Description;
        public string Description 
        {
          get { return m_Description;}
          set { m_Description = value;}
        }

        private string m_Skill;
        public string Skill 
        {
          get { return m_Skill;}        
          set { m_Skill = value;}
        }

        public override string ToString()
        {
            return string.Format("Name={0}&Level={1}&Description={2}&Skill={3}",
                           m_Name,m_Level,m_Description,m_Skill);
        }
    }
}

好了,這就是今天這篇文章的全部內容了,希望大家喜歡!