Unity照片墙简易圆形交互效果总结

还要很多可以优化的点地方,有兴趣的可以做

比如对象的销毁和生成可以做成对象池,走到最左边后再移动到最右边循环利用

分析过程文件,采用Blender,资源已上传,可以播放动画看效果,下面截个图:

视频效果如下:

anim

Untiy结构如下:

上面的ImageItem是我手动添加展示关系用的,默认就一个Target,PictureWall挂PictureWall脚本,ImageItem(预制体)挂ImageItemController 脚本即可

csharp 复制代码
using UnityEngine;

public class ImageItemController : MonoBehaviour
{
    public RectTransform target;
    public float speed = 10;
    [SerializeField]
    private float radiusScale = 1;
    public float horizontalOffset = 0;
    private RectTransform rect;
    private float radius = 0;
    private Vector2 originalPos = Vector2.zero;
    private bool isCheck = false;
    private bool isStartRotate = false;
    private Vector2 circleCenter;
    private float xDelta = 0;
    private float offset = 0;

    void Start()
    {
        rect = transform as RectTransform;
        rect.anchoredPosition = new Vector2(rect.anchoredPosition.x - horizontalOffset, rect.anchoredPosition.y);
        radius = target.rect.width * radiusScale;// * Random.Range(0.8f, 1); 半径可以在范围内随机
    }

    /* 1.现根据接触点计算出圆的路径:目标移动的位移,计算在圆的的位置,只需修改x即可,y保持不变
     * 2.计算出的位置x加上移动的距离,得出最总x的位置
     * 3.设置位置即可
     * 4.走远时的接触点:开始接触时的关于x对称位置  
     * 5.添加移动:平移原点和圆点即可
     */

    //移动
    void Update()
    {
        if (!isCheck)
        {
            var dis = Vector2.Distance(target.anchoredPosition, rect.anchoredPosition);

            if (dis <= radius)
            {
                isCheck = true;
                originalPos = rect.anchoredPosition;

                float y = Mathf.Abs(originalPos.y - target.anchoredPosition.y);
                float xToCircleCenter = Mathf.Sqrt(radius * radius - y * y);
                float x = originalPos.x - xToCircleCenter;
                circleCenter = new Vector2(x, target.anchoredPosition.y);

                isStartRotate = true;
                rect.SetSiblingIndex(transform.parent.childCount - 2);
            }
        }

        xDelta = Time.deltaTime * speed;
        rect.anchoredPosition = new Vector2(rect.anchoredPosition.x - xDelta, rect.anchoredPosition.y);

        if (isStartRotate)
        {
            circleCenter.x -= xDelta;
            originalPos.x -= xDelta;
            float moveXDistance = target.anchoredPosition.x - circleCenter.x;
            float x = originalPos.x - circleCenter.x - moveXDistance;
            float y = Mathf.Sqrt(radius * radius - x * x);

            float maxY = radius;
            if (originalPos.y < circleCenter.y)
            {
                y = -y;
                maxY = -radius;
            }
            Vector2 circlePoint = new Vector2(x, y);
            if (rect.anchoredPosition.x >= target.anchoredPosition.x)
            {
                var v1 = circlePoint - (originalPos - circleCenter);
                var v2 = (originalPos - circleCenter) + new Vector2(0, maxY);
                v2.Normalize();
                offset = Vector2.Dot(v1, v2);
            }
            else
            {
                float tempX = originalPos.x - circleCenter.x;
                Vector2 originalPos2 = originalPos + 2 * new Vector2(-tempX, 0);
                var v1 = circlePoint - new Vector2(0, maxY);
                var v2 = originalPos2 - circleCenter + new Vector2(0, maxY);
                v2.Normalize();
                offset = -Vector2.Dot(v1, v2);
            }

            if (float.IsNaN(offset))
            {
                offset = 0;
            }
            x += moveXDistance + offset;

            Vector2 pos = circleCenter + new Vector2(x, y);
            rect.anchoredPosition = pos;

            if (target.anchoredPosition.x >= originalPos.x + originalPos.x - circleCenter.x)
            {
                rect.anchoredPosition = originalPos;
                rect.SetAsFirstSibling();
            }
            else if (target.anchoredPosition.x <= circleCenter.x)
            {
                rect.anchoredPosition = originalPos;
                rect.SetAsFirstSibling();
            }
        }

        if (rect.anchoredPosition.x < -rect.rect.width)
        {
            Destroy(gameObject);
        }
    }
}
csharp 复制代码
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;
using Utility;

public class PictureWall : MonoBehaviour
{
    [SerializeField]
    private GameObject prefab;
    private const float WIDTH = 3072;
    private const float HEIGHT = 1664;

    private int row = 6;
    private int column;
    private float intervalDistance = 20;
    [SerializeField]
    private float offset = 200;

    private float itemWidth;
    private float itemHeight;

    public float speed = 10;
    private float time = 0;
    [SerializeField]
    private RectTransform target;

    private string path = "/PictureWall/";
    private List<string> texturePaths;
    private int currentIndex = 0;
    private List<Texture2D> textureList;

   
    void Start()
    {
        textureList = new List<Texture2D>();
        path = Application.streamingAssetsPath + path;
        ReadImage();
        CalculateRowColumn();
        enabled = false;
    }

    private void ReadImage()
    {
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
            return;
        }
        texturePaths = new List<string>();

        var jpgs = Directory.GetFiles(path, "*.jpg");
        texturePaths.AddRange(jpgs);
        texturePaths.Reverse();
        if (texturePaths.Count > 100)
        {
            for (int i = texturePaths.Count - 1; i == 100; i--)
            {
                File.Delete(texturePaths[i]);
                texturePaths.RemoveAt(i);
            }
        }

        foreach (var filePath in texturePaths)
        {
            UtilityLoadImage.I.LoadImage(filePath, tex =>
            {
                textureList.Add(tex);
                addNum++;
                if (addNum == texturePaths.Count)
                {
                    Spawn();
                }
            });
        }
    }

    float addNum = 0;

    private void Spawn()
    {
        float x = 0;
        float y = 0;

        for (int i = 0; i < row; i++)
        {
            y = i * (itemHeight + intervalDistance);
            for (int j = 0; j < column; j++)
            {
                x = j * (itemWidth + intervalDistance);
                if (i % 2 != 0)
                {
                    //x -= offset;
                }
                RectTransform rect = Instantiate(prefab, transform).transform as RectTransform;
                rect.pivot = new Vector2(0.5f, 0.5f);
                rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, itemWidth);
                rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, itemHeight);
                rect.anchoredPosition = new Vector2(x, -y) + new Vector2(rect.rect.width / 2, -rect.rect.height / 2);
                var controller = rect.GetComponent<ImageItemController>();
                controller.speed = speed;
                controller.target = target;
                if (i % 2 != 0)
                {
                    controller.horizontalOffset = offset;
                }

                SetTexture(rect);
            }
        }
        target.SetAsLastSibling();  
        enabled = true;
    }

    private void CalculateRowColumn()
    {
        itemHeight = (HEIGHT - (row - 1) * intervalDistance) / row;
        itemWidth = itemHeight * 16 / 9;
        //offset = itemWidth / 2;
        column = (int)(WIDTH / (itemWidth + intervalDistance)) + 3;
        time = itemWidth / speed;
    }

    bool isSpawned = false;

    private void Update()
    {
        if (!isSpawned && transform.childCount <= (column - 1) * row + 1)
        {
            isSpawned = true;

            SpawnColumn();
        }
    }
    

    private void SpawnColumn()
    {
        float x = 0;
        float y = 0;

        for (int i = 0; i < row; i++)
        {
            y = i * (itemHeight + intervalDistance);
            for (int j = 0; j < 1; j++)
            {
                x = (column - 1) * (itemWidth + intervalDistance);
                RectTransform rect = Instantiate(prefab, transform).transform as RectTransform;
                rect.pivot = new Vector2(0.5f, 0.5f);
                rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, itemWidth);
                rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, itemHeight);
                rect.anchoredPosition = new Vector2(x, -y) + new Vector2(intervalDistance - Time.deltaTime * speed, -rect.rect.height / 2);
                var controller = rect.GetComponent<ImageItemController>();
                controller.speed = speed;
                controller.target = target;
                if (i % 2 != 0)
                {
                    controller.horizontalOffset = offset;
                }

                SetTexture(rect);
            }
        }
        target.SetAsLastSibling();
        StartCoroutine(Delay());
    }

    private void SetTexture(RectTransform rect)
    {        
        rect.GetComponent<RawImage>().texture = textureList[currentIndex];
        currentIndex = (currentIndex + 1) % texturePaths.Count;
    }

    private IEnumerator Delay()
    {
        //yield return new WaitForSeconds(0.1f);
        yield return null;
        isSpawned = false;
    }
}
csharp 复制代码
工具类
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

namespace Utility
{
    public class UtilityLoadImage
    {
        public class MonoHelper : MonoBehaviour { }

        public static UtilityLoadImage I;

        private static MonoHelper helper;

        static UtilityLoadImage()
        {
            var go = new GameObject("UtilityLoadImage");
            helper = go.AddComponent<MonoHelper>();
            UnityEngine.Object.DontDestroyOnLoad(go);
            I = new UtilityLoadImage();
        }

        private UtilityLoadImage() { }

        #region  inner method
        private IEnumerator LoadTexture2D(string path, Action<Texture2D> callback)
        {           
            //Debug.Log("path:" + path);           
            UnityWebRequest uwr = UnityWebRequestTexture.GetTexture(path);

            yield return uwr.SendWebRequest();

            if (uwr.downloadHandler.isDone)
            {
                var tex = DownloadHandlerTexture.GetContent(uwr);
                callback?.Invoke(tex);
            }
        }
        private void LoadTexture2DByFile(string path, Action<Texture2D> callback)
        {
            if (path.StartsWith("file://"))
            {
                var bytes = File.ReadAllBytes(path);
                Texture2D tex = new Texture2D(1, 1);
                if (tex.LoadImage(bytes))
                    callback?.Invoke(tex);
            }
        }

        private IEnumerator LoadByte(string path, Action<byte[]> callback)
        {
            UnityWebRequest uwr = UnityWebRequest.Get(path);
            yield return uwr.SendWebRequest();

            if (uwr.downloadHandler.isDone)
            {
                var data = uwr.downloadHandler.data;

                callback?.Invoke(data);
            }
        }

        private void DeleteFolder(string savedFolder, bool clearSavedPath, bool isRecursive = false)
        {
            if (!Directory.Exists(savedFolder))
            {
                Debug.LogError("要删除的文件夹不存在!");
                return;
            }

            if (clearSavedPath)
            {
                Directory.Delete(savedFolder, isRecursive);
                Directory.CreateDirectory(savedFolder);
            }
        }

        private byte[] Texture2DToByte(string path, Texture2D tex)
        {
            byte[] data = null;

            int index = path.LastIndexOf('.');
            if (index != -1)
            {
                string expandedName = path.Substring(index + 1);

                switch (expandedName)
                {
                    case "jpeg":
                    case "jpg":
                        data = tex.EncodeToJPG();
                        break;
                    case "png":
                        data = tex.EncodeToPNG();
                        break;
                    default:
                        Debug.Log("");
                        break;
                }
            }
            else
            {
                Debug.Log("path is not correct!!!");
            }

            return data;
        }

        private IEnumerator LoadAudio(string path, string savedFolder, string fileName, Action<AudioClip> callback)
        {
            UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(path, AudioType.MPEG);
            yield return request.SendWebRequest();
            if (request.downloadHandler.isDone)
            {
                File.WriteAllBytes(savedFolder + "/" + fileName, request.downloadHandler.data);

                AudioClip clip = DownloadHandlerAudioClip.GetContent(request);

                callback?.Invoke(clip);
            }
        }

        private IEnumerator LoadAudio(string path, string savePath, Action<AudioClip> callback)
        {
            UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(path, AudioType.MPEG);
            yield return request.SendWebRequest();
            if (request.downloadHandler.isDone)
            {
                File.WriteAllBytes(savePath, request.downloadHandler.data);

                AudioClip clip = DownloadHandlerAudioClip.GetContent(request);

                callback?.Invoke(clip);
            }
        }

        private IEnumerator LoadAudio(string path, Action<AudioClip> callback)
        {
            UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(path, AudioType.MPEG);
            yield return request.SendWebRequest();
            if (request.downloadHandler.isDone)
            {
                AudioClip clip = DownloadHandlerAudioClip.GetContent(request);

                if (callback != null)
                    callback(clip);
                else
                    Debug.Log("加载音频回调为null");
            }
        }

        #endregion

        #region load and download image
        public void LoadImage(string path, Action<Texture2D> callback)
        {
            helper.StartCoroutine(LoadTexture2D(path, callback));
        }

        public void LoadImageByFile(string path, Action<Texture2D> callback)
        {
            LoadTexture2DByFile(path, callback);
        }

        public void LoadImages(string[] paths, Action<List<Texture2D>> callback)
        {
            Debug.Log("start!!!!!");
            List<Texture2D> list = new List<Texture2D>();
            for (int i = 0; i < paths.Length; i++)
            {
                LoadImage(paths[i], tex => list.Add(tex));
            }
            callback?.Invoke(list);
            Debug.Log("end!!!!!" + list.Count);
        }

        public void LoadImagesByFile(string[] paths, Action<List<Texture2D>> callback)
        {
            List<Texture2D> list = new List<Texture2D>();
            for (int i = 0; i < paths.Length; i++)
            {
                var data = File.ReadAllBytes(paths[i]);
                Texture2D tex = new Texture2D(1, 1);
                if (tex.LoadImage(data))
                    list.Add(tex);
            }
            callback?.Invoke(list);
        }

        public void DownloadImageAndSave(string url, string savedFolder, string fileName, Action callback = null)
        {
            helper.StartCoroutine(LoadTexture2D(url, tex =>
            {
                File.WriteAllBytes(savedFolder + "/" + fileName, Texture2DToByte(url, tex));

                callback?.Invoke();
            }));
        }
        public void DownloadImageAndSave(string url, string savePath, Action callback = null)
        {
            helper.StartCoroutine(LoadTexture2D(url, tex =>
            {
                File.WriteAllBytes(savePath, Texture2DToByte(url, tex));

                callback?.Invoke();
            }));
        }

        public void DownloadImageAndSave_Texture2D(string url, string savedFolder, string fileName, Action<Texture2D> callback = null)
        {
            helper.StartCoroutine(LoadTexture2D(url, tex =>
            {
                File.WriteAllBytes(savedFolder + "/" + fileName, Texture2DToByte(url, tex));

                callback?.Invoke(tex);
            }));
        }
        public void DownloadImageAndSave_Texture2D(string url, string savePath, Action<Texture2D> callback = null)
        {
            helper.StartCoroutine(LoadTexture2D(url, tex =>
            {
                File.WriteAllBytes(savePath, Texture2DToByte(url, tex));

                callback?.Invoke(tex);
            }));
        }

        public void DownloadImageAndSave_FilePath(string url, string savedFolder, string fileName, Action<string> callback = null)
        {
            helper.StartCoroutine(LoadTexture2D(url, tex =>
            {
                string path = savedFolder + "/" + fileName;
                File.WriteAllBytes(path, Texture2DToByte(url, tex));
                callback?.Invoke(path);
            }));
        }
        public void DownloadImageAndSave_FilePath(string url, string savePath, Action<string> callback = null)
        {
            helper.StartCoroutine(LoadTexture2D(url, tex =>
            {
                File.WriteAllBytes(savePath, Texture2DToByte(url, tex));
                callback?.Invoke(savePath);
            }));
        }

        public void DownloadImagesAndSave(string[] urls, string savedFolder, string[] fileNames, Action completedCallback = null, bool deleteFolder = false, bool recursive = false)
        {
            if (urls.Length != fileNames.Length)
            {
                Debug.Log("下载数量和保存的文件数量不一致!");
                return;
            }

            DeleteFolder(savedFolder, deleteFolder, recursive);

            int completedNum = 0;

            for (int i = 0; i < urls.Length; i++)
            {
                DownloadImageAndSave(urls[i], savedFolder, fileNames[i], () =>
                {
                    ++completedNum;
                    if (completedNum == urls.Length)
                    {
                        completedCallback?.Invoke();
                        Debug.Log("所以文件下载完成!");
                    }
                });
            }
        }

        public void DownloadImagesAndSave_Texture2DPaths(string[] urls, string savedFolder, string[] fileNames, Action<string[]> callback = null, bool deleteFolder = false, bool recursive = false)
        {
            if (urls.Length != fileNames.Length)
            {
                Debug.Log("下载数量和保存的文件数量不一致!");
                return;
            }

            DeleteFolder(savedFolder, deleteFolder, recursive);

            int completedNum = 0;
            string[] filePaths = new string[fileNames.Length];

            for (int i = 0; i < urls.Length; i++)
            {
                DownloadImageAndSave_FilePath(urls[i], savedFolder, fileNames[i], path =>
                {
                    filePaths[completedNum] = path;
                    ++completedNum;
                    if (completedNum == urls.Length)
                    {
                        callback?.Invoke(filePaths);
                        Debug.Log("所以图片下载完成!");
                    }
                });
            }
        }

        public void DownloadImagesAndSave_Texture2DPaths(string[] urls, string[] savePaths, Action<string[]> callback = null)
        {
            if (urls.Length != savePaths.Length)
            {
                Debug.Log("下载数量和保存的文件数量不一致!");
                return;
            }

            int completedNum = 0;
            string[] filePaths = new string[savePaths.Length];

            for (int i = 0; i < urls.Length; i++)
            {
                DownloadImageAndSave_FilePath(urls[i], savePaths[i], path =>
                {
                    filePaths[completedNum] = path;
                    ++completedNum;
                    if (completedNum == urls.Length)
                    {
                        callback?.Invoke(filePaths);
                        Debug.Log("所以图片下载完成!");
                    }
                });
            }
        }

        public void DownloadImagesAndSave_Texture2Ds(string[] urls, string savedFolder, string[] fileNames, Action<Texture2D[]> callback = null, bool deleteFolder = false, bool recursive = false)
        {
            if (urls.Length != fileNames.Length)
            {
                Debug.Log("下载数量和保存的文件数量不一致!");
                return;
            }

            DeleteFolder(savedFolder, deleteFolder, recursive);

            int completedNum = 0;
            Texture2D[] textures = new Texture2D[fileNames.Length];

            for (int i = 0; i < urls.Length; i++)
            {
                DownloadImageAndSave_Texture2D(urls[i], savedFolder, fileNames[i], tex =>
                {
                    textures[completedNum] = tex;
                    ++completedNum;
                    if (completedNum == urls.Length)
                    {
                        callback?.Invoke(textures);
                        Debug.Log("所以图片下载完成!");
                    }
                });
            }
        }

        public void DownloadImagesAndSave_Texture2Ds(string[] urls, string[] savePaths, Action<Texture2D[]> callback = null)
        {
            if (urls.Length != savePaths.Length)
            {
                Debug.Log("下载数量和保存的文件数量不一致!");
                return;
            }

            int completedNum = 0;
            Texture2D[] textures = new Texture2D[savePaths.Length];

            for (int i = 0; i < urls.Length; i++)
            {
                DownloadImageAndSave_Texture2D(urls[i], savePaths[i], tex =>
                {
                    textures[completedNum] = tex;
                    ++completedNum;
                    if (completedNum == urls.Length)
                    {
                        callback?.Invoke(textures);
                        Debug.Log("所以图片下载完成!");
                    }
                });
            }
        }
        #endregion

        #region download file

        public void DownloadFileAndSave(string url, string savedFolder, string fileName, Action callback = null)
        {
            helper.StartCoroutine(LoadByte(url, data =>
            {
                File.WriteAllBytes(savedFolder + "/" + fileName, data);

                callback?.Invoke();
            }));
        }
        public void DownloadFileAndSave(string url, string savePath, Action callback = null)
        {
            helper.StartCoroutine(LoadByte(url, data =>
            {
                File.WriteAllBytes(savePath, data);

                callback?.Invoke();
            }));
        }

        public void DownloadFileAndSave_FilePath(string url, string savedFolder, string fileName, Action<string> callback = null)
        {
            helper.StartCoroutine(LoadByte(url, data =>
            {
                string path = savedFolder + "/" + fileName;

                File.WriteAllBytes(path, data);

                callback?.Invoke(path);
            }));
        }
        public void DownloadFileAndSave_FilePath(string url, string savePath, Action<string> callback = null)
        {
            helper.StartCoroutine(LoadByte(url, data =>
            {
                File.WriteAllBytes(savePath, data);

                callback?.Invoke(savePath);
            }));
        }

        public void DownloadFileAndSave_FileData(string url, string savedFolder, string fileName, Action<byte[]> callback = null)
        {
            helper.StartCoroutine(LoadByte(url, data =>
            {
                string path = savedFolder + "/" + fileName;

                File.WriteAllBytes(path, data);

                callback?.Invoke(data);
            }));
        }
        public void DownloadFileAndSave_FileData(string url, string savePath, Action<byte[]> callback = null)
        {
            helper.StartCoroutine(LoadByte(url, data =>
            {
                File.WriteAllBytes(savePath, data);

                callback?.Invoke(data);
            }));
        }

        public void DownloadFilesAndSave(string[] urls, string savedFolder, string[] fileNames, Action completedCallback = null, bool deleteFolder = false, bool recursive = false)
        {
            if (urls.Length != fileNames.Length)
            {
                Debug.Log("下载数量和保存的文件数量不一致!");
                return;
            }

            DeleteFolder(savedFolder, deleteFolder, recursive);

            int completedNum = 0;
            for (int i = 0; i < urls.Length; i++)
            {
                DownloadFileAndSave(urls[i], savedFolder, fileNames[i], () =>
                {
                    ++completedNum;
                    if (completedNum == fileNames.Length)
                    {
                        completedCallback?.Invoke();
                    }
                });
            }
        }
        public void DownloadFilesAndSave(string[] urls, string[] savePath, Action callback = null)
        {
            if (urls.Length != savePath.Length)
            {
                Debug.Log("下载数量和保存的文件数量不一致!");
                return;
            }

            int completedNum = 0;
            for (int i = 0; i < urls.Length; i++)
            {
                DownloadFileAndSave(urls[i], savePath[i], () =>
                {
                    ++completedNum;
                    if (completedNum == savePath.Length)
                    {
                        callback?.Invoke();
                    }
                });
            }
        }

        public void DownloadFilesAndSave_FilePaths(string[] urls, string savedFolder, string[] fileNames, Action<string[]> completedCallback = null, bool deleteFolder = false, bool recursive = false)
        {
            if (urls.Length != fileNames.Length)
            {
                Debug.Log("下载数量和保存的文件数量不一致!");
                return;
            }

            DeleteFolder(savedFolder, deleteFolder, recursive);

            int completedNum = 0;
            string[] filePaths = new string[fileNames.Length];
            for (int i = 0; i < urls.Length; i++)
            {
                DownloadFileAndSave_FilePath(urls[i], savedFolder, fileNames[i], path =>
                {
                    filePaths[completedNum] = path;
                    ++completedNum;
                    if (completedNum == fileNames.Length)
                    {
                        completedCallback?.Invoke(filePaths);
                    }
                });
            }
        }
        public void DownloadFilesAndSave_FilePaths(string[] urls, string[] savePath, Action<string[]> completedCallback = null)
        {
            if (urls.Length != savePath.Length)
            {
                Debug.Log("下载数量和保存的文件数量不一致!");
                return;
            }

            int completedNum = 0;
            string[] filePaths = new string[savePath.Length];
            for (int i = 0; i < urls.Length; i++)
            {
                DownloadFileAndSave_FilePath(urls[i], savePath[i], path =>
                {
                    filePaths[completedNum] = path;
                    ++completedNum;
                    if (completedNum == savePath.Length)
                    {
                        completedCallback?.Invoke(filePaths);
                    }
                });
            }
        }

        public void DownloadFilesAndSave_FileDatas(string[] urls, string savedFolder, string[] fileNames, Action<List<byte[]>> completedCallback = null, bool deleteFolder = false, bool recursive = false)
        {
            if (urls.Length != fileNames.Length)
            {
                Debug.Log("下载数量和保存的文件数量不一致!");
                return;
            }

            DeleteFolder(savedFolder, deleteFolder, recursive);

            int completedNum = 0;
            List<byte[]> allDatas = new List<byte[]>(fileNames.Length);
            for (int i = 0; i < urls.Length; i++)
            {
                DownloadFileAndSave_FileData(urls[i], savedFolder, fileNames[i], data =>
                {
                    allDatas.Add(data);
                    ++completedNum;
                    if (completedNum == fileNames.Length)
                    {
                        completedCallback?.Invoke(allDatas);
                    }
                });
            }
        }
        public void DownloadFilesAndSave_FileDatas(string[] urls, string[] savePath, Action<List<byte[]>> completedCallback = null)
        {
            if (urls.Length != savePath.Length)
            {
                Debug.Log("下载数量和保存的文件数量不一致!");
                return;
            }

            int completedNum = 0;
            List<byte[]> allDatas = new List<byte[]>(savePath.Length);
            for (int i = 0; i < urls.Length; i++)
            {
                DownloadFileAndSave_FileData(urls[i], savePath[i], data =>
                {
                    allDatas.Add(data);
                    ++completedNum;
                    if (completedNum == savePath.Length)
                    {
                        completedCallback?.Invoke(allDatas);
                    }
                });
            }
        }
        #endregion

        #region download audio

        public void DownloadAudioAndSave_FileData(string url, string savedFolder, string fileName, Action<AudioClip> callback = null)
        {
            helper.StartCoroutine(LoadAudio(url, savedFolder, fileName, callback));
        }
        public void DownloadAudioAndSave_FileData(string url, string savePath, Action<AudioClip> callback = null)
        {
            helper.StartCoroutine(LoadAudio(url, savePath, callback));
        }
        public void LoadAudioClip(string url, Action<AudioClip> callback = null)
        {
            helper.StartCoroutine(LoadAudio(url, callback));
        }

        #endregion
    }
}
相关推荐
小贺儿开发1 小时前
Unity3D 智慧城市管理平台
数据库·人工智能·unity·智慧城市·数据可视化
June bug16 小时前
【领域知识】休闲游戏一次发版全流程:Google Play + Apple App Store
unity
星夜泊客18 小时前
C# 基础:为什么类可以在静态方法中创建自己的实例?
开发语言·经验分享·笔记·unity·c#·游戏引擎
dzj202119 小时前
PointerEnter、PointerExit、PointerDown、PointerUp——鼠标点击物体,则开始旋转,鼠标离开或者松开物体,则停止旋转
unity·pointerdown·pointerup
心前阳光20 小时前
Unity 模拟父子关系
android·unity·游戏引擎
在路上看风景1 天前
26. Mipmap
unity
咸鱼永不翻身1 天前
Unity视频资源压缩详解
unity·游戏引擎·音视频
在路上看风景1 天前
4.2 OverDraw
unity
在路上看风景1 天前
1.10 CDN缓存
unity
ellis19701 天前
Unity插件SafeArea Helper适配异形屏详解
unity