Unity下的簡單多賬號角色游戲存檔功能介紹

? ? 我們知道 在RPG里單機游戲里 游戲存檔功能必不可少 在這里 網(wǎng)上有個教程 非常的好 是基于xml下的保存 保存成dat文件(數(shù)據(jù)類型) 在這里 主要是針對網(wǎng)上那個教程做一個簡單的介紹 讓大家可以隨心所欲的用那個封裝好的存檔 可以自我增加功能


一五鲫、此套存檔腳本分為6個腳本? 先介紹哪些腳本 然后再具體腳本的作用(tag的取值是可以由用戶更改的 只是你要在相應(yīng)的腳本改成你自己設(shè)置的名字)

? ? ? ? 1.Sence腳本 2.GameDataManager腳本 3.Xmlsacer腳本 4.SenceData腳本 5.SaveCube腳本(這個腳本的名字是根據(jù)情況取的 在Demo中我是用來存檔cube位置信息) 6.UI腳本

二、這個腳本分別掛在哪些游戲?qū)ο笊?/p>

? ? 1.Sence腳本不需要掛在游戲?qū)ο笊?存在就行

? ? 2.GameDataManager腳本放在一個空物體上(取名GameDataManager)空物體Tag也設(shè)置取名GameDataManage

? ? 3.Xmlsacer腳本是xml保存數(shù)據(jù)的支撐腳本里面全是固定代碼不需要用戶編寫? 直接粘貼到工程就行 也放在名為GameDataManager空物體上

? 4.SenceData腳本 放在空物體上 空物體名字叫SenceData 空物體Tag也設(shè)置取名SenceData

? 5.SavePlayer 腳本也放在SenceData 空物體下玩家要設(shè)置tag值 隨意取名字 只是要在相應(yīng)腳本里把名字改成自己設(shè)的

6.U腳本 掛在空物體上 取名UI


三塑崖、各個腳本的作用 (在這里 我保存的是一個cube的位置信息 以及縮放比例)

? ? 1.sence腳本

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

[SerializeField]public class Sence

{

// 在這里聲明你要保存的屬性 其他的東西都不需要動

public Vector3 cubePoision ; // cube位置信息

public Vector3 cubeScale ; // cube的放大比例

}

public class sence : MonoBehaviour {

// Use this for initialization

void Start () {

}

// Update is called once per frame

void Update () {

}

}

2.GameDataManage腳本 注意保存存檔名稱和保存路徑即可 其他不需要動

using System.Collections;

using System.Collections.Generic;

using UnityEngine;?

using System.IO ; // 文件輸入與輸出 操作文件讀取和寫入時用到

using System.Collections.Generic ;

using System.Text ;

using System.Xml ;

using System.Security.Cryptography ;

using System ;

//GameData,儲存數(shù)據(jù)的類规婆,把需要儲存的數(shù)據(jù)定義在GameData之內(nèi)就行//

public class GameData

{

// 密鑰 用于防止拷貝存檔

public string key ;

// 需要存儲的內(nèi)容 現(xiàn)在只存儲一個bool值 點擊讀檔為true 加載場景后為false

public bool isDu ;

// 場景存儲內(nèi)容

public Sence s ;

public GameData()

{

s = new Sence (); // 存儲內(nèi)容初始化 只能放構(gòu)造函數(shù)

isDu = false;

}

}

public class GameDataManager : MonoBehaviour {

//? 存檔文件的名稱 特別注意一下這條代碼 "csData1.dat" 如果你想實現(xiàn)多賬號存儲 這里 你要穿過來賬號的名稱 每次賬號不同 保存文件名不同 文件名不同 保存的存檔就不同 這就是為什么可以多賬號存儲的原因

private string dataFileNmae = "csData1.dat" ;

public GameData gameData ;

private? XmlSaver xs = new XmlSaver();

void Awake()

{

gameData = new GameData ();

// 設(shè)置密鑰 根據(jù)具體平臺設(shè)定

gameData.key = SystemInfo.deviceUniqueIdentifier ;

Load ();

}

// 讀檔時調(diào)用的方法

public void Load()

{

string gameDataFile = GetDataPath () + "/" + dataFileNmae;

if (xs.hasFile (gameDataFile)) {

string dataString = xs.LoadXML (gameDataFile);

GameData gameDataFromXML = xs.DeserializeObject (dataString, typeof(GameData)) as GameData;

// 如果是合法存檔

if (gameDataFromXML.key == gameData.key) {

gameData = gameDataFromXML;

} else {

// 游戲啟動后數(shù)據(jù)清零 存檔后作弊用

}

} else {

if (gameData != null) {

Save ();

}

}

}

public void Save()

{

string gameDataFile = GetDataPath() + "/"+dataFileNmae;

string dataString= xs.SerializeObject(gameData,typeof(GameData));

xs.CreateXML(gameDataFile,dataString);

}

// 獲取路徑

private static string GetDataPath()

{

// 判斷當前使用設(shè)備為蘋果手機 本例子針對pc端 移動端返回路徑根據(jù)蘋果系統(tǒng)與安卓系統(tǒng)的不同自己設(shè)置

if (Application.platform == RuntimePlatform.IPhonePlayer) {

return null;

} else {

// 返回系統(tǒng)文件路徑 這里返回的是Application.dataPath 如果你想返回Application.dataPath下的文件夾 自己在后面加文件夾名字

return Application.dataPath? ;

}

}

// Use this for initialization

void Start () {

}

// Update is called once per frame

void Update () {

}

}?


3.Xmlsacer腳本位固定代碼 直接拷貝就行 不用管

using UnityEngine;

using System.Collections;

using System.Xml;

using System.Xml.Serialization;

using System.IO;

using System.Text;

using System.Security.Cryptography;

using System;

public class XmlSaver :MonoBehaviour{

//內(nèi)容加密

public string Encrypt(string toE)

{

//加密和解密采用相同的key,具體自己填嗡髓,但是必須為32位//

byte[] keyArray = UTF8Encoding.UTF8.GetBytes("12348578902223367877723456789012");

RijndaelManaged rDel = new RijndaelManaged();

rDel.Key = keyArray;

rDel.Mode = CipherMode.ECB;

rDel.Padding = PaddingMode.PKCS7;

ICryptoTransform cTransform = rDel.CreateEncryptor();

byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toE);

byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray,0,toEncryptArray.Length);

return Convert.ToBase64String(resultArray,0,resultArray.Length);

}

//內(nèi)容解密

public string Decrypt(string toD)

{

//加密和解密采用相同的key,具體值自己填饿这,但是必須為32位//

byte[] keyArray = UTF8Encoding.UTF8.GetBytes("12348578902223367877723456789012");

RijndaelManaged rDel = new RijndaelManaged();

rDel.Key = keyArray;

rDel.Mode = CipherMode.ECB;

rDel.Padding = PaddingMode.PKCS7;

ICryptoTransform cTransform = rDel.CreateDecryptor();

byte[] toEncryptArray = Convert.FromBase64String(toD);

byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray,0,toEncryptArray.Length);

return UTF8Encoding.UTF8.GetString(resultArray);

}

public string SerializeObject(object pObject,System.Type ty)

{

string XmlizedString? = null;

MemoryStream memoryStream? = new MemoryStream();

XmlSerializer xs? = new XmlSerializer(ty);

XmlTextWriter xmlTextWriter? = new XmlTextWriter(memoryStream, Encoding.UTF8);

xs.Serialize(xmlTextWriter, pObject);

memoryStream = (MemoryStream)xmlTextWriter.BaseStream;

XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray());

return XmlizedString;

}

public object DeserializeObject(string pXmlizedString , System.Type ty)

{

XmlSerializer xs? = new XmlSerializer(ty);

MemoryStream memoryStream? = new MemoryStream(StringToUTF8ByteArray(pXmlizedString));

XmlTextWriter xmlTextWriter? = new XmlTextWriter(memoryStream, Encoding.UTF8);

return xs.Deserialize(memoryStream);

}

//創(chuàng)建XML文件

public void CreateXML(string fileName,string thisData)

{

string xxx = Encrypt(thisData);

StreamWriter writer;

writer = File.CreateText(fileName);

writer.Write(xxx);

writer.Close();

}

//讀取XML文件

public string LoadXML(string fileName)

{

StreamReader sReader = File.OpenText(fileName);

string dataString = sReader.ReadToEnd();

sReader.Close();

string xxx = Decrypt(dataString);

return xxx;

}

//判斷是否存在文件

public bool hasFile(String fileName)

{

return File.Exists(fileName);

}

public string UTF8ByteArrayToString(byte[] characters? )

{

UTF8Encoding encoding? = new UTF8Encoding();

string constructedString? = encoding.GetString(characters);

return (constructedString);

}

public byte[] StringToUTF8ByteArray(String pXmlString )

{

UTF8Encoding encoding? = new UTF8Encoding();

byte[] byteArray? = encoding.GetBytes(pXmlString);

return byteArray;

}

}


4.SenceData腳本. 這里你要把你所保存的東西的腳本名字tag值修改成你自己的

using System.Collections;

using System.Collections.Generic;

using UnityEngine;public class SenceData : MonoBehaviour

{// Use this for initializationvoid Start () {SaveCube sc = gameObject.GetComponent();

sc.Load ();

//末尾設(shè)置默認不讀擋

GameObject gameDataManager = GameObject.Find ("GameDataManager");

GameDataManager g = gameDataManager.GetComponent();

g.gameData.isDu = false;

g.Save ();

}

public void Save (){

/存檔數(shù)據(jù)//Cube信息的保存SaveCube sc = gameObject.GetComponent();

sc.Save();

}

// Update is called once per frame

void Update () {

}

}


5.SaveCube腳本 這里就是存檔的本質(zhì)了 在游戲結(jié)束后 把最后cube的屬性值賦予給sence腳本里你要保存的信息 同時 在讀檔時 把保存下來的給控制cube信息實際的屬性(切記:要理解兩個點 1.你把cube最后的位置給保存的屬性 最后的位置一定是可以決定cube位置的 比如說。cube.position系統(tǒng)方法 修改 cube.position cube的位置一定會被改變 2.讀檔時 你把保留下來的值給能決定當前對象的屬性 這樣一運行 就是你結(jié)束游戲時那個樣子 )

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class SaveCube : MonoBehaviour {

// Use this for initialization

void Start () {

}

// Update is called once per frame

void Update () {

}

// 保存cube的部分數(shù)據(jù) 這里只保存cube的位置信息

public void Save(){GameObject cube = GameObject.Find ("Cube");

GameObject gameDataManager = GameObject.Find ("GameDataManager");?

這里是保存cube在游戲結(jié)束時最后的位置 把它賦予給你在sence腳本創(chuàng)的屬性

// 拿到游戲?qū)ο蠊芾淼哪_本GameDataManager g = gameDataManager.GetComponent() ;

g.gameData.s.cubePoision = cube.transform.position;

g.gameData.s.cubeScale = cube.transform.localScale;

}

////// 場景開始時加載游戲?qū)ο?br>

///public void Load(){GameObject cube = GameObject.Find("Cube");

這里是賦值 cube在游戲結(jié)束時保存的位置 把它賦予給能決定cube位置的屬性

//獲得Cube對象GameObject gameDataManager =GameObject.Find("GameDataManager");

//獲得GameDataManager(游戲控制器)對象

GameDataManager g = gameDataManager.GetComponent();

//獲得GameDataManager(游戲控制器)腳本

if(g.gameData.isDu == true){//如果是讀檔狀態(tài)

cube.transform.position = g.gameData.s.cubePoision;//讀取Cube的位置,并賦值給Cube

cube.transform.localScale = g.gameData.s.cubeScale ;

}

}

}


6. UI腳本 就是按鈕的點擊存檔 以及讀檔 注意:游戲第一次運行 從來沒有存檔過 此時點擊讀檔會報錯? 解決方案已經(jīng)在代碼體現(xiàn) 讀者自己理解下

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

private GameDataManager g;//定義GameDataManager(游戲控制器)腳本

private SenceData s;//定義SenceData(場景加載器)腳本

public int senceNum;

void Awake()

{

Instant = this;

// 程序一運行 就獲取isEnable的布爾值 如果此時還是假 也沒有關(guān)系 當游戲第二次運行 就會變成真 那么 就讀檔 存檔正常了

if (PlayerPrefs.GetString(LoginManager.instance.userName)=="true")

{

isEnable = true;

}

}

void Start ()

{GameObject gameDataManager = GameObject.Find ("GameDataManager");

//獲得GameDataManager(游戲控制器)對象

g = gameDataManager.GetComponent();

//獲得GameDataManager(游戲控制器)腳本

GameObject senceData = GameObject.Find ("SenceData");

//獲得SenceData(場景加載器)對象

s = senceData.GetComponent();//獲得SenceData(場景加載器)腳本

}

// 你的存檔按鈕方法回調(diào)

public void SaveBtn()

{

s.Save ();//場景提交數(shù)據(jù)

g.Save ();//日志保存

isEnable = true;

PlayerPrefs.SetString(LoginManager.instance.userName,"true");

}

// 讀檔按鈕

public void ReadBtn()

{

// isEnable布爾值 為真才會去讀取 這就是能解決游戲一運行去點擊讀檔報錯的方案 一出來isEnable為false 不會執(zhí)行 方法 必須點擊過保存 才會變成true 然后用系統(tǒng)單例PlayerPrefs把isEnable為真保存起來 下次運行 就是 讀檔就可以被點擊了

if (isEnable)

{

g.gameData.isDu = true;//設(shè)置為可讀檔狀態(tài)

g.Save();//日志保存為可讀檔狀態(tài)

UnityEngine.SceneManagement.SceneManager.LoadScene(senceNum);//加載場景

senceNum++;

}

else

{

Debug.Log("還不能保存");

}

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末声功,一起剝皮案震驚了整個濱河市先巴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌摩渺,老刑警劉巖摇幻,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绰姻,死亡現(xiàn)場離奇詭異狂芋,居然都是意外死亡银酗,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門锯蛀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來旁涤,“玉大人,你說我怎么就攤上這事瞳遍【穑” “怎么了注祖?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵是晨,是天一觀的道長。 經(jīng)常有香客問我蚊逢,道長箫章,這世上最難降的妖魔是什么炉抒? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任拿诸,我火速辦了婚禮塞茅,結(jié)果婚禮上野瘦,老公的妹妹穿的比我還像新娘鞭光。我一直安慰自己,他們只是感情好席覆,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布聊倔。 她就那樣靜靜地躺著耙蔑,像睡著了一般甸陌。 火紅的嫁衣襯著肌膚如雪邀层。 梳的紋絲不亂的頭發(fā)上遂庄,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天秸谢,我揣著相機與錄音霹肝,去河邊找鬼沫换。 笑死,一個胖子當著我的面吹牛垮兑,可吹牛的內(nèi)容都是我干的系枪。 我是一名探鬼主播私爷,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼衬浑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤奠支,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后叉抡,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體尔崔,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年褥民,在試婚紗的時候發(fā)現(xiàn)自己被綠了季春。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡消返,死狀恐怖载弄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情撵颊,我是刑警寧澤宇攻,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站倡勇,受9級特大地震影響逞刷,放射性物質(zhì)發(fā)生泄漏固耘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧呈昔,春花似錦迁客、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嗡害,卻和暖如春叹螟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工袖外, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓臭猜,卻偏偏與公主長得像次屠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容