創作內容

10 GP

PlayerPrefs - Unity 內建簡易存檔機制

作者:KK│2020-05-21 23:23:12│巴幣:20│人氣:9653

哈囉,大家好。

試著以我理解的方式來介紹一下,

Unity 內建提供,好用的存檔機制 PlayerPrefs

相信很多已經不是初學者的人,應該都已經不陌生了,

居然連這樣的文章也想要騙一篇創作之類的XDDDD

請壓抑著想吐槽的心情看下去吧:)



我在學習一個新事物的時候,會先試著了解它,認識它,

這麼一來就不會因為太多未知,而感到恐懼。

那麼我們先來好好認識一下這個機制。



PlayerPrefs 這個 Class ,提供了一些靜態的方法,所以我們可以在任何的地方使用它。

乍看之下,它提供了我們三種型態的資料存取,整數、浮點數跟字串。

存取的原理其實是簡單的 dictionary 字典運用,使用一個 key 去查找對應的 value

實際上它可以做一個簡單的應用,達到更多方便的效果。

舉例來說,我們可以寫一個 class,叫做 MyPlayerPrefs,然後再新增以下幾個靜態方法。

public static bool CheckValue(string key)
{
// 需要先定義好,1 為 true,0 為 false;相反也可以,看個人習慣。
return PlayerPrefs.GetInt(key, 0) == 1;
}

public static Point GetStartPoint()
{
// GetInt("Key", DefaultValue), 另外兩個 Get 也可以帶預設值,如果查不到會回傳預設。
return new Point( PlayerPrefs.GetInt("PointX", 0), PlayerPrefs.GetInt("PointY", 0));
}

public static Vector3 GetStartPosition()
{
return new Vector3( PlayerPrefs.GetInt("PosX", 0), PlayerPrefs.GetInt("PosY", 0),
PlayerPrefs.GetInt("PosZ", 0));
}

剛剛說的乍看之下,就是這個意思。

其實我們是能夠擴充 bool, point, vector3......等等,你想得到的資料型態的。
(分別使用 MyPlayerPrefs.CheckValue(), MyPlayerPrefs.GetStartPoint(), MyPlayerPrefs.GetStartPosition())

既然有 GetSet 就自然而然可以用同樣方式撰寫。

再進一步說,其實有字串資料型態,基本上就可以實現各式各樣的變化了。



像是我把 "Ch-3-2-1" 存進名為 "CurrentLevel" 的 key 裡面。

取出來時做些處理,利用字串分割 Split

string[] array = PlayerPrefs.GetString("CurrentLevel").Split('-');
        //array[0] = "CH";
        //array[1] = "3";
        //array[2] = "2";
        //array[3] = "1";

這樣我們就能得知,玩家當前關卡進度在第 3 章第 2 關,然後難度是 1 (簡單)。

而剛剛展示的 bool 的延伸,把它變成 2 進制的資料來使用,

就可以實現資料庫那些超方便的紀錄方法,例如"000"~"111" 8 種變化。

000 - 玩家當前無狀態
001 - 玩家中毒了
010 - 玩家麻痺了
100 - 玩家被魅惑了
011 - 玩家中毒又麻痺了
101 - 玩家中毒又被魅惑了
110 - 玩家麻痺又被魅惑了(魅你麻痺!)
111 - 玩家全部負面狀態都中了

相信看了這些衍伸應用,你應該也能找到適合自己的擴充。

----------------------------------------------------------------------------------------------------

接下來,我們來看些比較內層的東西。

開頭說的,這是一個簡單的存檔機制,那麼檔案是存在哪裡?

我先說,Unity 是一個跨平台的開發引擎,所以每個平台對應的存檔位置是不一樣的。

Windows 作業系統中,它其實是存在登錄檔裡面的。
( 之前若有碰過要處理安裝程式 / 流程這塊的朋友,相信應該對這不陌生。 )

你可以透過 Cmd (命令提示字元),然後打上 regedit 後找到它(登錄編輯程式)。

存在兩個位置,一個是
電腦\HKEY_CURRENT_USER\Software\Unity\UnityEditor\DefaultCompany\ProjectName

=> 這個是你平常用 Editor 上測試時,會寫入的地方。

另一個是 電腦\HKEY_CURRENT_USER\Software\DefaultCompany\ProjectName

=> 這個是你玩這個遊戲,或別人玩你的遊戲,會存在他電腦的地方。
( 要修改就要改這個才有用,喂!別亂教。 )

我這邊依照整數、浮點數與字串,個別存入一些值做測試。


字串被記錄下來的樣子與位置。


整數被記錄下來的樣子跟位置。


浮點數被記錄下來的樣子與位置。......嗯?

其實只是因為登錄檔的資料類型的顯示沒有正確對應到而已,是顯示問題。
( 應該使用 64-bitQWORD,就會看到正確的顯示。 )

不要擔心,你存的數值有幾乎正確的被記錄下來的。

這個幾乎正確,才是浮點數這邊要提的重點。

浮點數是個有誤差值的資料型態,使用上需要特別注意。

相信有不少朋友應該都有踩過浮點數的坑,

當你今天真的有需求需要紀錄某個 % 數,某個需要用到小數點的資料時,

可以考慮用別的方式替代處理。

public static float GetCurrentHpRatio()
{
// 取當前血量 % 數時,改用另外兩個值去紀錄
return PlayerPrefs.GetInt("CurrentHp", 0) / PlayerPrefs.GetInt("CurrentMaxHp", 1);
}

=> 這邊注意我的除數,我的預設是填 1,因為除以 0 會有致命錯誤,
當然也要特別小心在存這個值的時後,別把 0 寫進去了!

public static float GetSSRchance()
{
// 機率 0.001 可以記錄成1; 0.123 可以記錄成 123,取值時再去除以百或千就好。
int value = int.Parse(PlayerPrefs.GetString("SSR_change", 0));
return (float)value / 1000;
}

有很多方式可以替代,如果你真的還是想要用,那就拿去用也不是什麼大問題。

基本上你的值都會被正確紀錄到的,存取也都會是正常的,

但就是某些場合要特別小心就是了。

----------------------------------------------------------------------------------------------------

那麼我們也知道了它們實際上存在哪裡了,還有什麼需要注意的嗎?

這樣一個登錄檔,作為 Unity 在這個應用程式的暫存,是有個限制的。

它的大小最多只能存到 1 M

初始什麼都沒有,只記錄一些必要的紀錄檔的情況下,是不到 1000 位元組( 連 1 KB都不到 )。

但每紀錄 100 個字元多 0.5 KB,每多一個索引紀錄多 0.1 KB

也就是說都以字串來記錄使用的話,可以記下約 20 萬個字元。

以索引來使用的話,可以使用 100 萬個紀錄空值的索引。

在這個區間內要怎麼去調整使用,就看每個人的使用方式了。

這樣的紀錄量夠不夠使用,基本上是,見仁見智的。

應用上來看,以一款完整的遊戲來說,存檔機制是不可或缺的。

但以小品遊戲、game jam 來說,不是必要,但絕對錦上添花。



說故事時間:


我舉 kuso game jam 一個有趣的作品為例,叫做「是男人就撐 60 秒」!

這個遊戲很單純,它會用很多逗趣的圖片,引人入勝的劇情,劇情的斷點讓你非常想往下看。

但是每個操作都必須等待 60 秒,你才能跟遊戲中按鈕互動,

不然就 game over,想重新遊戲亦同,也要等那個 60 秒。

撇開它就是主打想惡整玩家來說,其實它的圖片跟故事真的頗有意思的XD

而且是真的能破關喔,有結局喔!

但我想應該很少人會去看到最後。

這個時候!這個時候!

如果我們使用 PlayerPrefs 加入了對每一段劇情的達成與否做個紀錄,

如果這段玩家已經耐著性子看過了,那就無視那 60 秒等待,可以點到下一個。

如此一來,這個遊戲的細節會讓人非常玩味,也會讓撐到最後的玩家獲得成就感。

( 雖然依舊會氣得牙癢癢的。 )

例子太多,其實舉是舉不完,小型成就的應用也可以。

打一隻波莉,kill_count++;  PlayerPrefs.SetInt( "KillPoly", kill_count );

因為這個值只要不清除,它是會一直紀錄住的!

在玩家玩了好幾次之後,一但殺超過 100 隻波莉,波莉王就會出現這樣的小彩蛋。

解謎遊戲,玩家繞圈或者一直摸尚未觸發的機關,做個紀錄。

第一層機關們都檢查著這個數值,一但玩家已經陷入迷路狀態時,

亂點亂敲,數值就 +1,當這個值超過 10 次( 玩家崩潰邊緣 ),機關發光表示提示。

......等等等,這些不加依舊不影響遊戲本身好玩,但加了肯定是會讓玩家會心一笑的細節。



說在最後:


1. 存檔

PlayerPrefs 在使用上你可能會疏忽的部分。

當你只是單純在使用 Get 系列, Set 系列時,其實它在你遊戲跑的那個生命週期,

是正常紀錄並執行的。

不過一旦你關掉遊戲,離開遊戲模式回到編輯模式,值是不會有變化的。

要記得 PlayerPrefs.Save() 去做儲存才有用。

基本上可以每寫一次就存一次,但這樣其實有點小吃效能。( 因為 IO 開銷 )

假設是設定類型的,可以在開關設定介面時,做存檔。

找一個存檔時機給它。

另外也有一個應用是寫在 destroy 的時後,幫你 save

看最適合你的情況使用,記得存檔就是了。

2. 安全性

上面其實已經小小提到一下,基本上任何的紀錄方式,都是危險的。

透過網路把資料存在遊戲主機的資料庫裡,可能是相對安全一點。

但以單機遊戲來說,任何存檔的格式被破解什麼,只是難易度的差別而已。

當然也是有一些手段,混淆,加密,壓縮後加密再簽章......等,

我自己是覺得道高一尺,魔高一丈啦ˊˋ

實在是防不勝防,都可以額外開另一篇文來講這個議題了。

主要是先說明,這個儲存的方式,要是紀錄什麼重要的資訊,

必須要有這是會被輕易修改的心理準備,

當然,也會有其它更方便較安全的存檔方法,我們留在下一篇討論。

3. 存檔的需求確立


遊戲是否用到了大量的數值,例如 50 個屬性與能力,

這樣的記錄方式就挺辛苦的,不必要勉強使用 50 幾個 SetIntGetInt 去維護。

換一個存讀檔的方式會更好。

資料是否有區分,帳號型資料,跟設定資料。

不用想成連網的遊戲,舉例來說,一個遊戲提供 3 個紀錄格。

那就表示那是 Save1Save2Save3,三個帳號;

背景音樂、音效開關、鏡頭遠近,這些算是設定資料。

設定資料使用 PlayerPrefs 紀錄是沒什麼問題的,

帳號資料當然有字串去分隔不是不能處理,只是不方便到令人痛苦......

先了解需求,再去使用;就像開頭說的,我們先認識、學習這個東西後,

我們就比較清楚再那些場合可以使用了。

以上,謝謝收看。







開個玩笑,

最近公會的收錄區出現了小異狀,

可能是我最近都在畫畫,感覺不務正業,

我已經從程式被除名了,嚇得我趕快發一篇程式相關技術文壓壓驚XDDDD

放著放著就轉職,感覺真有趣?!

看到很多認識的人突然轉職,真是令人莞爾。XDDDDDD
引用網址:https://home.gamer.com.tw/TrackBack.php?sn=4790322
All rights reserved. 版權所有,保留一切權利

相關創作

同標籤作品搜尋:Unity|存檔讀檔|PlayerPrefs

留言共 7 篇留言

樂小呈
第一次看人解釋Unity的存檔XD

酷[e19]

05-21 23:30

KK
你應該都自己寫一套序列化存檔吧~~~
這個對新手還滿好用的,還是要介紹一下。05-21 23:34
樂小呈
沒那麼厲害啦XDD

其實我都沒做過什麼存檔(つд⊂)

05-21 23:41

KK
好耶!這樣我下一篇序列化存檔就有動力了。
你繼續做你的系統,存檔這個也不是很急,之後再碰都來得及~[e19]05-21 23:43
樂小呈
期待[e12]

05-21 23:49

我是龘天
頗有收穫 謝謝(*´ω`*)

11-14 07:25

KK
有幫上忙就好,加油:)11-14 22:23
遍尋天下
我想問的是 我發布在window 我在電腦上玩 但我我用usb把檔案到別人的電腦 紀錄就沒了 所以playerprefsplayerprefs這個功能是存在電腦裡的嬤 檔案移動 紀錄並沒有跟著存 還是有其他做法?

01-01 02:27

KK
存在電腦的這個位置,C:\Users\使用者名稱\AppData\LocalLow\公司名稱\遊戲名稱(例如貪食蛇巧達),把這個一起搬過去紀錄就會在了,除非想特別換一個位置存,先找找這個地方有沒有相關文件檔吧~01-01 16:16
Suxoxlaaty
目前大學生的我,只有寒暑假有空碰unity[e3],
這篇文章實在是很實用,
之後我想要挑戰用xml的方式搭配PlayerPrefsX存檔
[e12][e12]

01-19 17:32

KK
有幫上忙就好~~~xml,Json也都可以搭配使用,
小屋的背景有改過,有些字顏色可讀性沒那麼好,找機會再調整,敬請見諒。01-19 18:27
自我感覺良好
看不懂,但好像很厲害

11-15 01:42

我要留言提醒:您尚未登入,請先登入再留言

10喜歡★nigel0813 可決定是否刪除您的留言,請勿發表違反站規文字。

前一篇:跟風練習... 後一篇:Defold 學習紀錄 ...

追蹤私訊切換新版閱覽

作品資料夾

REIayanami00莫名
現在的笑只不過是一個表情看更多我要大聲說2小時前


face基於日前微軟官方表示 Internet Explorer 不再支援新的網路標準,可能無法使用新的應用程式來呈現網站內容,在瀏覽器支援度及網站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業系統版本才可使用)

face我們了解您不想看到廣告的心情⋯ 若您願意支持巴哈姆特永續經營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】