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
    }
}
相关推荐
小春熙子13 小时前
Unity图形学之Shader结构
unity·游戏引擎·技术美术
Sitarrrr15 小时前
【Unity】ScriptableObject的应用和3D物体跟随鼠标移动:鼠标放置物体在场景中
3d·unity
极梦网络无忧15 小时前
Unity中IK动画与布偶死亡动画切换的实现
unity·游戏引擎·lucene
逐·風1 天前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
_oP_i1 天前
Unity Addressables 系统处理 WebGL 打包本地资源的一种高效方式
unity·游戏引擎·webgl
Leoysq1 天前
【UGUI】实现点击注册按钮跳转游戏场景
游戏·unity·游戏引擎·ugui
_oP_i2 天前
unity中 骨骼、纹理和材质关系
unity·游戏引擎·材质
Padid2 天前
Unity SRP学习笔记(二)
笔记·学习·unity·游戏引擎·图形渲染·着色器
Tp_jh2 天前
推荐一款非常好用的C/C++在线编译器
linux·c语言·c++·ide·单片机·unity·云原生
dangoxiba2 天前
[Unity Demo]从零开始制作空洞骑士Hollow Knight第十八集补充:制作空洞骑士独有的EventSystem和InputModule
游戏·unity·c#·游戏引擎·playmaker