2D图片——轮转效果

废话不多说,直接上代码!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using Unity.VisualScripting;

public class RotationChart2D : MonoBehaviour, IDragHandler, IEndDragHandler//继承拖拽中接口,结束拖拽接口
{
    public Image prefab; // 预制体
    public float max = 1; // 缩放最大值
    public float min = 0.5f; // 缩放最小值
    public int n = 10; // 个数
    public float spacing = 100; // UI间距的单位是像素
    public float cut = 100; // 减速度
    float c; // 周长
    float r; // 半径
    float ang; // 每个角的弧度
    float moveAng = 0; // 移动的弧度
    List<Image> list = new List<Image>(); // 实例化存储的Image集合
    List<Transform> sortList = new List<Transform>(); // 存储实例化Image的Transform集合

    void Start()
    {
        // 计算周长
        c = (prefab.rectTransform.rect.width + spacing) * n;
        // 计算半径
        r = c / (2 * Mathf.PI);
        // 计算每个角的弧度
        ang = 2 * Mathf.PI / n;

        Move();
    }

    public void Move()
    {
        for (int i = 0; i < n; i++) // n 实例化的图片个数
        {
            // 判断集合中有就不创建,没有再创建
            if (list.Count <= i)
            {
                list.Add(Instantiate(prefab, transform)); // 实例化预制体,作为当前对象的子物体
                list[i].transform.GetChild(0).GetComponent<Image>().sprite = Resources.Load<Sprite>("Pictures/" + i); // 设置预制体子物体的 Image 组件的 sprite
                list[i].transform.name = i.ToString(); // 设置预制体的名称
                sortList.Add(list[i].transform); // 将预制体的 Transform 组件添加到 sortList 中
            }
            float x = Mathf.Sin(i * ang + moveAng) * r; // 根据角度计算 x 坐标
            float z = Mathf.Cos(i * ang + moveAng) * r; // 根据角度计算 z 坐标
            // 通过 z 计算近大远小
            // 计算 z 0 到 1 的比值,跟雷达图计算 nv 坐标时相同
            float p = (z + r) / (2 * r);
            // 线性插值公式
            float scale = (max - min) * p + min;
            // 设置预制体位置和缩放
            list[i].rectTransform.anchoredPosition = new Vector2(x, 0);
            list[i].transform.localScale = Vector3.one * scale;
        }
        // 对 sortList 进行排序,根据缩放大小
        sortList.Sort((a, b) =>
        {
            if (a.localScale.x < b.localScale.x) //短一些的放后面
            {
                return -1;
            }
            else if (a.localScale.x == b.localScale.x)
            {
                return 0;
            }
            else
            {
                return 1;
            }
        });
        // 对 sortList 中的元素按序重新设置 siblingIndex
        for (int i = 0; i < sortList.Count; i++)
        {
            sortList[i].SetSiblingIndex(i);//设置对象在父节点中的顺序
        }
    }

    public void OnDrag(PointerEventData eventData)//拖拽中
    {
        // 每帧拖动的距离
        float dis = eventData.delta.x;

        // 通过距离计算弧度
        float dragAng = dis / r;

        moveAng += dragAng; 

        Move(); //重新排序
    }

    public void OnEndDrag(PointerEventData eventData) //结束拖拽
    {
        float speed = eventData.delta.x;//速度
        float time = Mathf.Abs(speed) / cut;//事件
        DOTween.To((a) =>
        {
            // 通过距离计算弧度
            float dragAng = a / r;
            moveAng += dragAng;
            Move();//重新排序
        }, speed, 0, time).OnComplete(() =>//DoTween.To执行完毕之后 运行一下方法
        {
            Align();//对齐
        });
    }

    public void Align()
    {
        float AlignAng = Mathf.Asin(sortList[n - 1].GetComponent<RectTransform>().anchoredPosition.x / r); // 计算对齐的弧度
        float Aligndis = AlignAng * r; // 计算对齐的距离
        float time = Mathf.Abs(Aligndis) / cut; // 计算对齐需要的时间
        DOTween.To((a) =>
        {
            moveAng = a;
            Move();
        }, moveAng, moveAng - AlignAng, time);
    }
}

注意事项:1.图片资源的路径要正确

                  2.脚本挂载空对象身上(空对象是Canvas的子对象)

                  3.如果想要改变数据有一点要注意,比如说Max图片缩放的最大值

                  因为我这里是public(公共)的意思,你可以把public删掉再修改数值。如果不想删除                      public,还想修改数值的话,那就在脚本中改变数值,再去挂载脚本对象那里,手动修                    改数值。为什么这么麻烦?因为脚本数值和检视面板上的数值不是同步的,如果你只                      修改了脚本里的,你会发现检视面板那里脚本的数值没有发生变化。运行后你会看到                      它的数值还是检视面板的数值。所以数值一般都以检视面板的显示为准,public类型每                    次改值只要改面板的就行,不用管代码里是多少。所以,也可以直接就在挂载脚本的                      那里直接修改数值,但是如果担心后期扩展的时候数据混乱的话,那我还是建议让两                      个数值同步一下。

效果展示:

 效果动图后期,图片变大,就是我在运行的时候,在检视面板上直接修改了Max这个公共数值

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值