版權(quán)聲明:本文由秦元培創(chuàng)作和發(fā)表,采用署名(BY)-非商業(yè)性使用(NC)-相同方式共享(SA)國(guó)際許可協(xié)議進(jìn)行許可,轉(zhuǎn)載請(qǐng)注明作者及出處,本文作者為秦元培,本文標(biāo)題為在Unity3D中加載外部圖片的兩種方法,本文鏈接為http:///2015/10/08/2-methods-to-load-image-in-unity3d/.
各位朋友大家好,我是秦元培,歡迎大家關(guān)注我的博客。最近在做項(xiàng)目的過(guò)程中遇到這樣的一個(gè)需求:玩家可以在游戲過(guò)程中進(jìn)行實(shí)時(shí)存檔,在存檔過(guò)程中會(huì)保存當(dāng)前游戲進(jìn)度,同時(shí)會(huì)截取當(dāng)前游戲畫(huà)面并加載到游戲存檔界面中。當(dāng)下一次進(jìn)入游戲的時(shí)候,將讀取本地存檔圖片并加載到游戲界面中。這在單機(jī)游戲中是特別常見(jiàn)的一種功能,這里主要有兩個(gè)關(guān)鍵點(diǎn)。首先是截取游戲畫(huà)面,這個(gè)問(wèn)題大家可以在《Unity3D游戲開(kāi)發(fā)之截屏保存精彩瞬間》這篇文章中找到答案。其次是從本地加載圖片,因?yàn)檫@里要保證可讀可寫(xiě),因此傳統(tǒng)的Resources.Load()方式和AssetBundle方式均無(wú)法實(shí)現(xiàn)這樣的功能。那么怎樣從外部加載圖片到游戲中,這就是我們今天要討論的內(nèi)容啦。好了,這里介紹兩種方法來(lái)實(shí)現(xiàn)這一目的。
喜聞樂(lè)見(jiàn)的WWW方式喜聞樂(lè)見(jiàn)的WWW方式之所以喜聞樂(lè)見(jiàn),這是因?yàn)檫@是我們最為熟悉的一種,我們都知道通過(guò)WWW可以從網(wǎng)絡(luò)上加載文本、圖片、音頻等形式的內(nèi)容,那么通過(guò)WWW能否加載本地外部(相對(duì)于應(yīng)用程序)資源呢?答案是肯定的,這是因?yàn)閃WW可以支持http和file兩種協(xié)議。我們通常接觸到的WWW默認(rèn)都是指http協(xié)議,現(xiàn)在我們來(lái)說(shuō)說(shuō)file協(xié)議,該協(xié)議可以用來(lái)訪問(wèn)本地資源(絕對(duì)路徑)。例如我們希望加載文件D:\TestFile\pic001.png這個(gè)文件,則此時(shí)對(duì)應(yīng)的C#腳本為:
1 2 3 4 5 6 7 8 9
| //請(qǐng)求WWW WWW www = new WWW("file://D:\\TestFile\\pic001.png); yield return www; if(www != null && string.IsNullOrEmpty(www.error)) { //獲取Texture Texture texture=www.texture; //更多操作... }
|
注意到這里出現(xiàn)了yield return結(jié)構(gòu),這表示這里使用到了協(xié)程,因此我們需要付出的代價(jià)就是需要在項(xiàng)目中使用StartCoroutine等協(xié)程相關(guān)的方法來(lái)調(diào)用這些協(xié)程。雖然在Unity3D中使用協(xié)程是件簡(jiǎn)單的事情,可是如果我們隨隨便便地使用協(xié)程而不注意去維護(hù)這些協(xié)程,那么這些讓我們引以為傲的簡(jiǎn)單代碼可能就會(huì)變成我們痛苦不堪的無(wú)盡深淵。
亙古不變的傳統(tǒng)IO方式好了,下面我們隆重推出亙古不變的傳統(tǒng)IO方式,這種方式相信大家都沒(méi)有接觸過(guò),所以這里將這種方法和大家分享。既然是傳統(tǒng)的IO方式,那么無(wú)非就是各種IO流的處理啦。好,我們一起來(lái)看下面這段代碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| //創(chuàng)建文件讀取流 FileStream fileStream = new FileStream(screen, FileMode.Open, FileAccess.Read); fileStream.Seek(0, SeekOrigin.Begin); //創(chuàng)建文件長(zhǎng)度緩沖區(qū) byte[] bytes = new byte[fileStream.Length]; //讀取文件 fileStream.Read(bytes, 0, (int)fileStream.Length); //釋放文件讀取流 fileStream.Close(); fileStream.Dispose(); fileStream = null;
//創(chuàng)建Texture int width=800; int height=640; Texture2D texture = new Texture2D(width, height); texture.LoadImage(bytes);
|
可以看到在使用這種方式讀取圖片文件的時(shí)候主要是將圖片文件轉(zhuǎn)化為byte[]數(shù)組,再利用Texture2D的LoadImage方法轉(zhuǎn)化為Unity3D中的Texture2D。這種方法需要在創(chuàng)建過(guò)程中傳入圖片的大小,在這里我們創(chuàng)建了一張800X640的圖片。經(jīng)過(guò)博主的研究發(fā)現(xiàn),這種方式加載外部圖片相對(duì)于使用WWW加載外部圖片效率更高,所以如果大家遇到類(lèi)似的需求,博主個(gè)人推薦大家使用這種方式進(jìn)行加載。
到目前為止我們解決了如何從外部加載圖片到Unity3D中,現(xiàn)在我們回到最開(kāi)始的問(wèn)題,我們從外部讀取到這些圖片以后需要將它們加載到游戲界面中。比如當(dāng)我們使用UGUI的時(shí)候,UGUI中的Image控件需要一個(gè)Sprite來(lái)作為它的填充內(nèi)容,那么此時(shí)我們就需要將Texture轉(zhuǎn)化為Sprite.號(hào)了,下面我們給出一個(gè)簡(jiǎn)單的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| using UnityEngine; using System.Collections; using UnityEngine.UI; using System.IO;
public class TestLoading : MonoBehaviour { /// <summary> /// Image控件 /// </summary> private Image image;
void Start () { image = this.transform.Find("Image").GetComponent<Image>();
//為不同的按鈕綁定不同的事件 this.transform.Find("LoadByWWW").GetComponent<Button>().onClick.AddListener ( delegate(){LoadByWWW();} );
this.transform.Find("LoadByIO").GetComponent<Button>().onClick.AddListener ( delegate(){LoadByIO();} ); }
/// <summary> /// 以IO方式進(jìn)行加載 /// </summary> private void LoadByIO() { double startTime = (double)Time.time; //創(chuàng)建文件讀取流 FileStream fileStream = new FileStream("D:\\test.jpg", FileMode.Open, FileAccess.Read); fileStream.Seek(0, SeekOrigin.Begin); //創(chuàng)建文件長(zhǎng)度緩沖區(qū) byte[] bytes = new byte[fileStream.Length]; //讀取文件 fileStream.Read(bytes, 0, (int)fileStream.Length); //釋放文件讀取流 fileStream.Close(); fileStream.Dispose(); fileStream = null;
//創(chuàng)建Texture int width = 300; int height = 372; Texture2D texture = new Texture2D(width, height); texture.LoadImage(bytes);
//創(chuàng)建Sprite Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f)); image.sprite = sprite;
startTime=(double)Time.time-startTime; Debug.Log("IO加載用時(shí):" + startTime); }
/// <summary> /// 以WWW方式進(jìn)行加載 /// </summary> private void LoadByWWW() { StartCoroutine(Load()); }
IEnumerator Load() { double startTime = (double)Time.time; //請(qǐng)求WWW WWW www = new WWW("file://D:\\test.jpg"); yield return www; if(www != null && string.IsNullOrEmpty(www.error)) { //獲取Texture Texture2D texture=www.texture;
//創(chuàng)建Sprite Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f)); image.sprite = sprite;
startTime = (double)Time.time - startTime; Debug.Log("WWW加載用時(shí):" + startTime); } } }
|
現(xiàn)在我們運(yùn)行程序可以發(fā)現(xiàn)兩種方式均可以讓圖片加載進(jìn)來(lái),為了對(duì)比兩種方式在執(zhí)行效率上的高低,我們?cè)谀_本中加入了相關(guān)代碼,通過(guò)對(duì)比可以發(fā)現(xiàn)使用IO方式加載一張227k的圖片需要的時(shí)間為0s,而使用WWW方式加載需要0.0185s,因此傳統(tǒng)的IO方式具有更高的效率,建議大家在遇到這類(lèi)問(wèn)題時(shí)盡可能地使用這種方式。好了,今天的內(nèi)容就是這樣啦,歡迎大家在我的博客中留言、歡迎大家關(guān)注和支持我的博客,謝謝大家!
版權(quán)聲明:本文由秦元培創(chuàng)作和發(fā)表,采用署名(BY)-非商業(yè)性使用(NC)-相同方式共享(SA)國(guó)際許可協(xié)議進(jìn)行許可,轉(zhuǎn)載請(qǐng)注明作者及出處,本文作者為秦元培,本文標(biāo)題為在Unity3D中加載外部圖片的兩種方法,本文鏈接為http:///2015/10/08/2-methods-to-load-image-in-unity3d/.
|