我是秦元培,我的博客是http:///,期待交流。 今天想和大家分享的內(nèi)容是RPG游戲中游戲存檔的實(shí)現(xiàn),因?yàn)樽罱谧鲆粋€(gè)RPG游戲的項(xiàng)目,所以遇到這個(gè)問題就隨時(shí)記錄下來,在對(duì)知識(shí)進(jìn)行總結(jié)的同時(shí)可以將這種思路或者想法分享給大家,這是一件快樂而幸運(yùn)的事情。我討厭寫按部就班的技術(shù)教程,因?yàn)槲矣X得學(xué)習(xí)是一種自我的探索行為,如果一切都告訴你了,探索的過程便會(huì)變得沒有意義了。 游戲存檔是一種在單機(jī)游戲中特別常見的機(jī)制,這種機(jī)制是你在玩網(wǎng)絡(luò)游戲的時(shí)候無法體驗(yàn)到的,你知道每次玩完一款單機(jī)游戲都會(huì)把游戲存檔保存起來是一種怎樣的感覺嗎?它就像是一個(gè)征戰(zhàn)沙場(chǎng)的將軍將陪伴自己一生金戈鐵馬的寶劍靜靜地收入劍匣,然而每一次打開它的時(shí)候都會(huì)不由自主的熱淚盈眶。人的本性其實(shí)就是游戲,我們每一天發(fā)生的故事何嘗不是一個(gè)游戲?有時(shí)候讓我們懷念的可能并不是游戲本身,而只是擱淺在時(shí)光里的那時(shí)的我們。好了,游戲存檔是我們?cè)谟螒蚴澜缋镅┠帏欁?,它代表了我們?cè)?jīng)來到過這個(gè)世界。以RPG游戲?yàn)槔?,一個(gè)一般化的游戲存檔應(yīng)該囊括以下內(nèi)容: 角色信息:指一切表征虛擬角色成長(zhǎng)路線的信息,如生命值、魔法值、經(jīng)驗(yàn)值等等。 道具信息:指一切表征虛擬道具數(shù)量或者作用的信息,如藥品、道具、裝備等等。 場(chǎng)景信息:指一切和游戲場(chǎng)景相關(guān)的信息,如場(chǎng)景名稱、角色在當(dāng)前場(chǎng)景中的位置坐標(biāo)等等。 事件信息:指一切和游戲事件相關(guān)的信息,如主線任務(wù)、支線任務(wù)、觸發(fā)性事件等等。 從以上信息劃分的層次來看,我們可以發(fā)現(xiàn)在游戲存檔中要儲(chǔ)存的信息相對(duì)是比較復(fù)雜的,那么我們這里不得不說說unity3D中的數(shù)據(jù)持久化方案PlayerPrefs。該方案采用的是一種鍵值型的數(shù)據(jù)存儲(chǔ)方案,支持int、string、float三種基本數(shù)據(jù)類型,通過鍵名來獲取相對(duì)應(yīng)的數(shù)值,當(dāng)值不存在時(shí)將返回一個(gè)默認(rèn)值。這種數(shù)據(jù)存儲(chǔ)方案本質(zhì)上是將數(shù)據(jù)寫入到一個(gè)Xml文件。這種方案如果用來存儲(chǔ)簡(jiǎn)單的信息是沒有問題的,可是如果用它來存儲(chǔ)游戲存檔這樣負(fù)責(zé)的數(shù)據(jù)結(jié)構(gòu)就顯得力不從心了。一個(gè)更為重要的問題是在數(shù)據(jù)持久化的過程中我們希望得到是一個(gè)結(jié)構(gòu)化的【游戲存檔】實(shí)例,顯然此時(shí)松散的PlayerPrefs是不能滿足我們的要求的。因此我們想到了將游戲數(shù)據(jù)序列化的思路,常見的數(shù)據(jù)序列化思路主要有Xml和JSON兩種形式,在使用Xml的數(shù)據(jù)序列化方案的時(shí)候通常有兩種思路,即手動(dòng)建立數(shù)據(jù)實(shí)體和數(shù)據(jù)字符間的對(duì)應(yīng)關(guān)系和基于XmlSerializer的數(shù)據(jù)序列化。其中基于XmlSerializer的數(shù)據(jù)序列化是利用了[Serializable]這樣的語法特性來幫助.NET完成數(shù)據(jù)實(shí)體和數(shù)據(jù)字符間的對(duì)應(yīng)關(guān)系,兩種思路本質(zhì)上一樣的??墒俏覀冎繶ml的優(yōu)點(diǎn)是可讀性強(qiáng),缺點(diǎn)是冗余信息多,因此在權(quán)衡了兩種方案的利弊后,我決定采用JSON來作為數(shù)據(jù)序列化的方案,而且JSON在數(shù)據(jù)實(shí)體和數(shù)據(jù)字符間的對(duì)應(yīng)關(guān)系上有著天然的優(yōu)勢(shì),JSON所做的事情不就是將數(shù)據(jù)實(shí)體轉(zhuǎn)化為字符串和從一個(gè)字符串中解析出數(shù)據(jù)實(shí)體嗎?所以整個(gè)方案基本一氣呵成。好了,下面我們來看具體的代碼實(shí)現(xiàn)過程吧! 一、JSON的序列化和反序列化 這里我使用的是Newtonsoft.Json這個(gè)類庫(kù),相信大家都是知道的了!因此,序列化和反序列化特別簡(jiǎn)單。 [C#] 純文本查看 復(fù)制代碼
二、Rijandel加密/解密算法 因?yàn)槲覀冞@里要做的是一個(gè)游戲存檔的方案設(shè)計(jì),因?yàn)榭紤]到存檔數(shù)據(jù)的安全性,我們可以考慮采用相關(guān)的加密/解密算法來實(shí)現(xiàn)對(duì)序列化后的明文數(shù)據(jù)進(jìn)行加密,這樣可以從一定程度上保證游戲存檔數(shù)據(jù)的安全性。因?yàn)椴┲鞑]有深入地研究過加密/解密方面的內(nèi)容,所以這里僅僅提供一個(gè)從MSDN上獲取的Rijandel算法,大家感興趣的話可以自行去研究。 [C#] 純文本查看 復(fù)制代碼
三、完整代碼 好了,下面給出完整代碼,我們這里提供了兩個(gè)公開的方法GetData()和SetData()以及IO相關(guān)的輔助方法,我們?cè)趯?shí)際使用的時(shí)候只需要關(guān)注這些方法就可以了! [C#] 純文本查看 復(fù)制代碼
這里我們的密鑰是直接寫在代碼中的,這樣做其實(shí)是有風(fēng)險(xiǎn)的,因?yàn)橐坏┪覀兊捻?xiàng)目被反編譯,我們這里的密鑰就變得很不安全了。這里有兩種方法,一種是把密鑰暴露給外部方法,即在讀取數(shù)據(jù)和寫入數(shù)據(jù)的時(shí)候使用同一個(gè)密鑰即可,而密鑰可以采取由機(jī)器MAC值生成的方法,這樣每臺(tái)機(jī)器上的密鑰都是不同的可以防止數(shù)據(jù)被破解;其次可以采用DLL混淆的方法讓反編譯者無法看到代碼中的內(nèi)容,這樣就無法獲得正確的密鑰從而無法獲得存檔里的內(nèi)容了。 四、最終效果 好了,最后我們來寫一個(gè)簡(jiǎn)單的測(cè)試腳本: [C#] 純文本查看 復(fù)制代碼
腳本執(zhí)行結(jié)果: ![]() 加密后游戲存檔: ![]() 好了,這就是今天的內(nèi)容了,希望大家能夠喜歡,有什么問題可以給我留言,謝謝! 感謝風(fēng)宇沖unity3d教程寶典之兩步實(shí)現(xiàn)超實(shí)用的XML存檔一文提供相關(guān)思路! |
|