Unity動態載入多個圖片到Image(UI)的方法的探討

需要載入大量圖片到Image並顯示,基本方法有2種,用WWW或者c#的FileStream。考慮到協程,異步,以及把代碼統一寫或者分開寫,衍生出5、6種方法。

job system只能處理值類型,幫不上忙。ecs也主要集中在處理update裏面的內容,似乎也不使用。還考慮過多線程,這裏不是很確定。unity多線程過程中,子線程不能使用unity的api,就只能用c#把文件讀取過程加速,對多線程不熟,就放棄了。

結論
會出現3種效果,在使用FileStream異步,在統一的地方寫代碼適應畢竟廣。

測試方法,加載102張512*512分辨率的圖片,顯示成一個圖片下拉列表,樣子如下

方法一、統一調用WWW協程

GuiController.CS

//方法一、統一調用WWW協程
GuiController.CS

    /// <summary>
    /// 統一處理WWW協程載入
    /// </summary>
    public void UniteCoroutineWWW()
    {
        //從json獲取圖片地址信息並轉爲對象數組
        MediaText[] mts = JsonConvert.DeserializeObject<MediaText[]>(ifJson.text);
        scrollView.SetActive(true);
 
        //遍歷對象數組
        foreach (MediaText mt in mts)
        {
            //實列化遊戲對象
            Transform tf = Instantiate(prefab, content);
            tf.GetChild(1).GetComponent<Text>().text = mt.Name;
            tf.GetChild(2).GetComponent<Text>().text = mt.Description;
            Image image = tf.GetChild(0).GetComponent<Image>();
 
            //調用協程
            StartCoroutine(LoadByWWW(mt.Icon, image));
        }
    }
 
    /// <summary>
    /// WWW協程載入圖片
    /// </summary>
    /// <param name="path">圖片地址</param>
    /// <param name="image">Image對象</param>
    /// <returns></returns>
    IEnumerator LoadByWWW(string path, Image image)
    {
        path = @"file://"+fileRoot + path;
 
        using (WWW www = new WWW(path))
        {
            yield return www;
            if (www.isDone && www.error == null)
            {
                image.sprite = Sprite.Create(www.texture, new Rect(0, 0, 512f, 512f), new Vector2(0.5f, 0.5f));
            }
            else
            {
                Debug.Log(www.error);
            }
        }
    }


載入情況:先把所有Image初始完成後,統一載入了圖片。

cpu佔用信息

600

方法二、統一調用WWW載入,不使用協程
GuiController.CS

   

/// <summary>
    /// 統一調用WWW,不使用協程
    /// </summary>
    public void UniteSynchronizeWWW()
    {
        string path = @"file://"+fileRoot;
        MediaText[] mts = JsonConvert.DeserializeObject<MediaText[]>(ifJson.text);
        scrollView.SetActive(true);
        foreach (MediaText mt in mts)
        {
            Transform tf = Instantiate(prefab, content);
            tf.GetChild(1).GetComponent<Text>().text = mt.Name;
            tf.GetChild(2).GetComponent<Text>().text = mt.Description;
            Image image = tf.GetChild(0).GetComponent<Image>();
 
            using (WWW www = new WWW(path+mt.Icon))
            {
                while (!www.isDone)
                {
                    if (www.error == null)
                    {
                        image.sprite = Sprite.Create(www.texture, new Rect(0, 0, 512f, 512f), new Vector2(0.5f, 0.5f));
                    }
                    else
                    {
                        Debug.Log(www.error);
                    }
                }
            }
        }
}


載入情況,會等所有內容準備好後一併顯示

cpu佔用信息

方法三、統一FileStream異步
GuiController.CS

   

/// <summary>
    /// 異步載入圖片
    /// </summary>
    /// <param name="path">路徑</param>
    /// <param name="image">Image對象</param>
    /// <returns></returns>
    async Task LoadByFSAsync(string path, Image image)
    {
        path = fileRoot + path;
        byte[] result;
 
        using (FileStream SourceStream = File.Open(path, FileMode.Open))
        {
            result = new byte[SourceStream.Length];
            await SourceStream.ReadAsync(result, 0, (int)SourceStream.Length);
        }
 
        Texture2D tx = new Texture2D(512, 512);
        tx.LoadImage(result);
        image.sprite = Sprite.Create(tx, new Rect(0, 0, 512f, 512f), new Vector2(0.5f, 0.5f));
    }
 
    /// <summary>
    /// 統一異步載入
    /// </summary>
    public async void UniteFSAsync()
    {
        MediaText[] mts = JsonConvert.DeserializeObject<MediaText[]>(ifJson.text);
        scrollView.SetActive(true);
        foreach (MediaText mt in mts)
        {
            Transform tf = Instantiate(prefab, content);
            tf.GetChild(1).GetComponent<Text>().text = mt.Name;
            tf.GetChild(2).GetComponent<Text>().text = mt.Description;
            Image image = tf.GetChild(0).GetComponent<Image>();
 
            await LoadByFSAsync(mt.Icon, image);
        }
}


載入情況:會順序將對象實例化並載入圖片

 

cpu佔用

方法四、由遊戲對象自己用WWW協程載入
GuiController.CS   

 /// <summary>
    /// 由遊戲對象自己載入圖片
    /// </summary>
    public void SelfLoad()
    {
        MediaText[] mts = JsonConvert.DeserializeObject<MediaText[]>(ifJson.text);
        scrollView.SetActive(true);
        foreach (MediaText mt in mts)
        {
            Transform tf = Instantiate(prefab, content);
            tf.GetChild(1).GetComponent<Text>().text = mt.Name;
            tf.GetChild(2).GetComponent<Text>().text = mt.Description;
            LoadImage loadImage = tf.GetComponent<LoadImage>();
            loadImage.path = fileRoot + mt.Icon;
            //LoadImageDestory lid = tf.GetComponent<LoadImageDestory>();
            //lid.path = fileRoot + mt.Icon;
        }
}
LoadImage.CS

    void Start () {
        image = transform.GetChild(0).GetComponent<Image>();
        StartCoroutine(LoadByWWW(path, image)); 
        //LoadByFSAsync(path, image); 
    }
 
    /// <summary>
    /// 用WWW協程載入圖片
    /// </summary>
    /// <param name="path"></param>
    /// <param name="image"></param>
    /// <returns></returns>
    IEnumerator LoadByWWW(string path, Image image)
    {
        path = @"file://" + path;
        using (WWW www = new WWW(path))
        {
            yield return www;
            if (www.isDone && www.error == null)
            {
                image.sprite = Sprite.Create(www.texture, new Rect(0, 0, 512f, 512f), new Vector2(0.5f, 0.5f));
            }
            else
            {
                Debug.Log(www.error);
            }
        }
    }


載入情況:先把所有Image初始完成後,統一載入了圖片。

cpu佔用

方法五,由遊戲對象自己用FileStream異步載入
GuiController.CS   

 /// <summary>
    /// 由遊戲對象自己載入圖片
    /// </summary>
    public void SelfLoad()
    {
        MediaText[] mts = JsonConvert.DeserializeObject<MediaText[]>(ifJson.text);
        scrollView.SetActive(true);
        foreach (MediaText mt in mts)
        {
            Transform tf = Instantiate(prefab, content);
            tf.GetChild(1).GetComponent<Text>().text = mt.Name;
            tf.GetChild(2).GetComponent<Text>().text = mt.Description;
            LoadImage loadImage = tf.GetComponent<LoadImage>();
            loadImage.path = fileRoot + mt.Icon;
            //LoadImageDestory lid = tf.GetComponent<LoadImageDestory>();
            //lid.path = fileRoot + mt.Icon;
        }
}
LoadImage.CS

    void Start () {
        image = transform.GetChild(0).GetComponent<Image>();
        //StartCoroutine(LoadByWWW(path, image)); 
        LoadByFSAsync(path, image); 
    }
 
    async Task LoadByFSAsync(string path, Image image)
    {
        byte[] result;
 
        using (FileStream SourceStream = File.Open(path, FileMode.Open))
        {
            result = new byte[SourceStream.Length];
            await SourceStream.ReadAsync(result, 0, (int)SourceStream.Length);
        }
 
        Texture2D tx = new Texture2D(512, 512);
        tx.LoadImage(result);
        image.sprite = Sprite.Create(tx, new Rect(0, 0, 512f, 512f), new Vector2(0.5f, 0.5f));
    }


載入情況,會等所有內容準備好後一併顯示

cpu佔用信息

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章