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

news2024/11/25 10:33:20

还要很多可以优化的点地方,有兴趣的可以做
比如对象的销毁和生成可以做成对象池,走到最左边后再移动到最右边循环利用

分析过程文件,采用Blender,资源已上传,可以播放动画看效果,下面截个图:
在这里插入图片描述

视频效果如下:

anim

Untiy结构如下:
在这里插入图片描述
上面的ImageItem是我手动添加展示关系用的,默认就一个Target,PictureWall挂PictureWall脚本,ImageItem(预制体)挂ImageItemController 脚本即可

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);
        }
    }
}
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;
    }
}

工具类
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
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1552885.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenPLC_Editor 在Ubuntu 虚拟机安装记录

1. OpenPLC_Editor在虚拟机上费劲的装了一遍&#xff0c;有些东西已经忘了&#xff0c;主要还是python3 的缺失库版本对应问题&#xff0c;OpenPLC_Editor使用python3编译的&#xff0c;虚拟机的Ubuntu 18.4 有2.7和3.6两个版本&#xff0c;所以需要注意。 2. OpenPLC_Editor …

专题:一个自制代码生成器(嵌入式脚本语言)之应用实例

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 专题&#xff1a;一个自制代码…

【嵌入式机器学习开发实战】(十二)—— 政安晨:通过ARM-Linux掌握基本技能【C语言程序的安装运行】

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 嵌入式机器学习开发实战 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 在ARM-Linux系统中&#xff0c;C语言程序的安装和运行可…

局域网找不到共享电脑怎么办?

局域网找不到共享电脑是一种常见的问题&#xff0c;给我们的共享与合作带来一定的困扰。天联组网技术可以解决这个问题。本文将介绍天联组网的原理和优势&#xff0c;并探讨其在解决局域网找不到共享电脑问题中的应用。 天联组网的原理和优势 天联组网是一种基于加速服务器的远…

Linux 系统 CentOS7 上搭建 Hadoop HDFS集群详细步骤

集群搭建 整体思路:先在一个节点上安装、配置,然后再克隆出多个节点,修改 IP ,免密,主机名等 提前规划: 需要三个节点,主机名分别命名:node1、node2、node3 在下面对 node1 配置时,先假设 node2 和 node3 是存在的 **注意:**整个搭建过程,除了1和2 步,其他操作都使…

浅谈C语言编译与链接

个人主页&#xff08;找往期文章包括但不限于本期文章中不懂的知识点&#xff09;&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 翻译环境和运行环境 在ANSI C&#xff08;标准 C&#xff09;的任何一种实现中&#xff0c;存在两个不同的环境。 第1种是翻译环境&#xff0c;在这个…

XUbuntu22.04之激活Linux最新Typora版本(二百二十五)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

109、Recent Advances in 3D Gaussian Splatting

简介 论文 对3D Gaussian Splatting的综述 质量提升 Mip-Splatting观察到&#xff0c;改变采样率&#xff0c;例如焦距&#xff0c;可以通过引入高频高斯类形伪影或强膨胀效应&#xff0c;极大地影响渲染图像的质量&#xff0c;因此Mip-Splatting将3D表示的频率限制在训练图…

IP种子是什么?理解和应用

在网络世界中&#xff0c;IP种子是一个广泛应用于文件共享和网络下载领域的概念。它是一种特殊的标识符&#xff0c;用于识别和连接到基于对等网络&#xff08;P2P&#xff09;协议的文件共享网络中的用户或节点。本文将深入探讨IP种子的含义、作用以及其在网络中的应用。 IP地…

计算机网络:物理层 - 信道极限容量

计算机网络&#xff1a;物理层 - 信道极限容量 实际信道中的数字信号奈式准则香农公式练习 实际信道中的数字信号 信号在传输过程中会受到各种因素的影响&#xff0c;如图所示&#xff1a; 这是一个数字信号&#xff0c;当它通过实际的信道后&#xff0c;波形会产生失真&#…

C语言例4-36:求Fibonacci数列的前40个数

教材优化代码如下&#xff1a; //求Fibonacci数列的前40个数 #include<stdio.h> int main(void) {long int f11,f21;int i1;for(;i<20;i){printf("%15ld%15ld",f1,f2);if(i%20)printf("\n");f1f2;f2f1;}return 0; } 结果如下&#xff1a; 我的基…

php 快速入门(七)

一、操作数据库 1.1 操作MySQL的步骤 第一步&#xff1a;登录MySQL服务器 第二步&#xff1a;选择当前数据库 第三步&#xff1a;设置请求数据的字符集 第四步&#xff1a;执行SQL语句 1.2 连接MySQL 函数1&#xff1a;mysql_connect() 功能&#xff1a;连接&#xff08;登录…

Netty对Channel事件的处理以及空轮询Bug的解决

继续上一篇Netty文章&#xff0c;这篇文章主要分析Netty对Channel事件的处理以及空轮询Bug的解决 当Netty中采用循环处理事件和提交的任务时 由于此时我在客户端建立连接&#xff0c;此时服务端没有提交任何任务 此时select方法让Selector进入无休止的阻塞等待 此时selectCnt进…

【计算机网络】第 11、12 问:流量控制和可靠传输机制有哪些?

目录 正文流量控制的基本方法停止-等待流量控制基本原理滑动窗口流量控制基本原理 可靠传输机制1. 停止-等待协议2. 后退 N 帧协议&#xff08;GBN&#xff09;3. 选择重传协议&#xff08;SR&#xff09; 正文 流量控制涉及对链路上的帧的发送速率的控制&#xff0c;以使接收…

zabbix自定义监控进程、日志文件

zabbix自定义监控进程、日志文件 zabbix自定义监控进程 在客户端安装httpd服务 [rootnode1 ~]# yum -y install httpd [rootnode1 ~]# systemctl start httpd [rootnode1 ~]# ss -antl State Recv-Q Send-Q Local Address:Port Peer Address:Port Pr…

【Redis】Redis 内存管理,Redis事务,bigkey和hotkey

目录 Redis 内存管理 缓存数据设置过期时间&#xff1f; Redis 是如何判断数据是否过期的呢&#xff1f; 过期删除策略 内存淘汰机制 主从模式下对过期键的处理&#xff1f; LRU和LFU的区别 Redis事务 定义和原理 Redis 事务的注意点&#xff1f; 为什么不支持回滚&a…

shell脚本发布docker-nginx vue2 项目示例

docker、git、node.js安装略过。 使git pull或者git push不需要输入密码操作方法 nginx安装在docker容器里面&#xff0c;参见&#xff1a;https://blog.csdn.net/HSJ0170/article/details/128631155 姊妹篇&#xff08;宿主机nginx&#xff0c;非docker-nginx&#xff09;&am…

React 应用实现监控可观测性最佳实践

前言 React 是一个用于构建用户界面的 JavaScript 框架。它采用了虚拟 DOM 和 JSX&#xff0c;提供了一种声明式的、组件化的编程模型&#xff0c;以便更高效地构建用户界面。无论是简单还是复杂的界面&#xff0c;React 都可以胜任。 YApi 是使用 React 编写的高效、易用、功…

StarRocks实战——多点大数据数仓构建

目录 前言 一、背景介绍 二、原有架构的痛点 2.1 技术成本 2.2 开发成本 2.2.1 离线 T1 更新的分析场景 2.2.2 实时更新分析场景 2.2.3 固定维度分析场景 2.2.4 运维成本 三、选择StarRocks的原因 3.1 引擎收敛 3.2 “大宽表”模型替换 3.3 简化Lambda架构 3.4 模…

“预防儿童烧烫伤”科普安全课堂走进嘉鱼县第一小学

为提高嘉鱼县儿童烧烫伤安全意识、隐患识别能力以及突发应急处置能力&#xff0c;3月26日下午&#xff0c;在中国社会福利基金会烧烫伤关爱公益基金、嘉鱼县妇女联合会、嘉鱼县教育局的支持下&#xff0c;嘉鱼县蒲公英社会工作服务中心走进嘉鱼县第一小学开展预防儿童烧烫伤科普…