Unity实现3D轮转图和2D轮转图

一、3D轮转图

       想要实现3D轮转图的效果,需要在场景里面创建一个空对象,然后创建生成轮转图的脚本,

创建好脚本之后,我们需要先明确几个变量:

1.生成物体的数量

2,生成物体范围的半径

3,物体移动的弧度

这三个变量缺一不可,在代码中这样体现:

   //你生成的cube
    public GameObject prefab;
    //生成cube的数量
    public int num = 10;
    //cube组成圆的半径
    public int r = 10;
    public float moveAng = 0;//移动后的弧度

之后就开始生成了,生成物体,物体的位置是算出来的

void Start()
    {
        ang = 2 * Mathf.PI / num;
        OnMove();
    }
    public void OnMove()
    {
        for (int i = 0; i < num; i++)
        {
            float x = Mathf.Sin(ang * i + moveAng) * r;
            float y = Mathf.Cos(ang * i + moveAng) * r;
            if (list.Count <= i)
            {
                GameObject cell = Instantiate(prefab, transform);
                list.Add(cell);
                sotrs.Add(cell);
            }
            list[i].transform.localPosition = new Vector3(x, 0, y);
        }
    }

这里的listsortsGameObject类型的集合

之后创建完物体之后,我们可以在场景中通过调整moveAng的值来控制旋转

之后我们要通过鼠标的拖拽凯控制旋转了

首先创建脚本,这个脚本是挂载到你生成的物体上的,

 private void OnMouseDrag()
    {
        Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);
        Vector3 mouse = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pos.z));

        float dis = mouse.x - transform.position.x;
        transform.parent.GetComponent<Cyclogam>().OnDrag(dis);
    }

之后在生成物体的脚本上写

   public void OnDrag(float dis)
    {
        tweener.Kill();
        float dragAng = dis / r;
        moveAng -= dragAng;
        OnMove();
    }

这样就可以实现通过鼠标拖这旋转了

我们还可以加一点缓冲效果

首先先加上这样的代码在生成物体的脚本上

 public void Inertia(float dis)
    {
        float time = Mathf.Abs(dis / cutspeed);
        tweener = DOTween.To((a) =>
        {
            float dragAng = dis / r;
            moveAng -= dragAng;
            OnMove();
        }, dis, 0, time).OnComplete(() =>
        {
            Align(list.IndexOf(sotrs[0]));
        });
    }
    public void Align(int n)
    {
        //找到z最小的
        sotrs.Sort((a, b) =>
        {
            if (a.transform.localPosition.z < b.transform.localPosition.z)
            {
                return -1;
            }
            else if (a.transform.localPosition.z == b.transform.localPosition.z)
            {
                return 0;
            }
            else
            {
                return 1;
            }
        });
        //找到z最小的在list里的下标
        int id = list.IndexOf(sotrs[0]);
        //正方形
        int zheng = id - n;
        //反方向的长度=总长度-正方向长度
        int fan = num - Mathf.Abs(zheng);
        fan = zheng < 0 ? fan : -fan;
        int interval = Mathf.Abs(zheng) < Mathf.Abs(fan) ? zheng : fan;
        float interca = (id - n) * ang;
        float alianAng = Mathf.Asin(sotrs[0].transform.localPosition.x / r)+ interca;
        float alignDis = alianAng * r;
        float aligntime = Mathf.Abs(alignDis / cutspeed);

        DOTween.To((b) =>
        {
            moveAng = b;
            OnMove();
        }, moveAng, moveAng + alianAng, aligntime);
    }

然后再挂载在生成物体上的脚本上加上这样的代码:

private void OnMouseUp()
    {
        Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);
        Vector3 mouse = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pos.z));

        float dis = mouse.x - transform.position.x;
        transform.parent.GetComponent<Cyclogam>().Inertia(dis);
    }

加上之后可以直接去实验,下面附上全部代码

生成物体的脚本:

//你生成的cube
    public GameObject prefab;
    //生成cube的数量
    public int num = 10;
    //cube组成圆的半径
    public int r = 10;
    public float moveAng = 0;//移动后的弧度
    public float cutspeed = 10;//减速
    //存储生成的cube
    List<GameObject> list = new List<GameObject>();
    List<GameObject> sotrs = new List<GameObject>();
    float ang;
    Tweener tweener;
    // Start is called before the first frame update
    void Start()
    {
        ang = 2 * Mathf.PI / num;
        OnMove();
    }
    public void OnMove()
    {
        for (int i = 0; i < num; i++)
        {
            float x = Mathf.Sin(ang * i + moveAng) * r;
            float y = Mathf.Cos(ang * i + moveAng) * r;
            if (list.Count <= i)
            {
                GameObject cell = Instantiate(prefab, transform);
                list.Add(cell);
                sotrs.Add(cell);
            }
            list[i].transform.localPosition = new Vector3(x, 0, y);
        }
    }
    public void OnDrag(float dis)
    {
        tweener.Kill();
        float dragAng = dis / r;
        moveAng -= dragAng;
        OnMove();
    }
    public void Inertia(float dis)
    {
        float time = Mathf.Abs(dis / cutspeed);
        tweener = DOTween.To((a) =>
        {
            float dragAng = dis / r;
            moveAng -= dragAng;
            OnMove();
        }, dis, 0, time).OnComplete(() =>
        {
            Align(list.IndexOf(sotrs[0]));
        });
    }
    public void Align(int n)
    {
        //找到z最小的
        sotrs.Sort((a, b) =>
        {
            if (a.transform.localPosition.z < b.transform.localPosition.z)
            {
                return -1;
            }
            else if (a.transform.localPosition.z == b.transform.localPosition.z)
            {
                return 0;
            }
            else
            {
                return 1;
            }
        });
        //找到z最小的在list里的下标
        int id = list.IndexOf(sotrs[0]);
        //正方形
        int zheng = id - n;
        //反方向的长度=总长度-正方向长度
        int fan = num - Mathf.Abs(zheng);
        fan = zheng < 0 ? fan : -fan;
        int interval = Mathf.Abs(zheng) < Mathf.Abs(fan) ? zheng : fan;
        float interca = (id - n) * ang;
        float alianAng = Mathf.Asin(sotrs[0].transform.localPosition.x / r)+ interca;
        float alignDis = alianAng * r;
        float aligntime = Mathf.Abs(alignDis / cutspeed);

        DOTween.To((b) =>
        {
            moveAng = b;
            OnMove();
        }, moveAng, moveAng + alianAng, aligntime);
    }

    // Update is called once per frame
    void Update()
    {

    }

物体身上的脚本:

 // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {

    }

    private void OnMouseDrag()
    {
        Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);
        Vector3 mouse = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pos.z));

        float dis = mouse.x - transform.position.x;
        transform.parent.GetComponent<Cyclogam>().OnDrag(dis);
    }
    private void OnMouseUp()
    {
        Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);
        Vector3 mouse = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pos.z));

        float dis = mouse.x - transform.position.x;
        transform.parent.GetComponent<Cyclogam>().Inertia(dis);
    }

二、2d轮转图

2d轮转图的逻辑跟3d轮转图的差不多,基本上你3d轮转图理解之后2d轮转图就也差不多了

首先还是跟3d轮转图一样先创建物体

public GameObject prefab;
    public int num;
    public float r;
    public float max = 1;
    public float min = 0.5f;
    public float ang;
    public float moveAng = 0;
    public float cutspeed = 50f;//减速
    List<GameObject> GList = new List<GameObject>(); 
    List<GameObject> sorts = new List<GameObject>(); 
void Start()
    {
        r = prefab.GetComponent<RectTransform>().sizeDelta.x * num / (2 * Mathf.PI);
        ang = 2 * Mathf.PI / num;
        OnMove();
    }
public void OnMove()
    {
        for (int i = 0; i < num; i++)
        {
            float x = Mathf.Sin(ang * i + moveAng) * r;
            float z = Mathf.Cos(ang * i + moveAng) * r;
            if (GList.Count<=i)
            {
                GameObject cell = Instantiate(prefab, transform);
                GList.Add(cell);
                sorts.Add(cell);
            }
            GList[i].transform.localPosition = new Vector3(x, 0, 0);
            float scale = (z + r) / (2 * r) * (max - min) + min;
            GList[i].transform.localScale = Vector3.one * scale;
        }
        
    }

附上效果图:

 

之后就可以通过拖拽的方法让生成物体进行旋转了,

  public void OnDrag(PointerEventData eventData)
    {
        moveAng += eventData.delta.x / r;
        OnMove();
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        float time = Mathf.Abs(eventData.delta.x / cutspeed);
        DOTween.To((a) =>
        {
            moveAng += a / r;
            OnMove();
        }, eventData.delta.x, 0, time).OnComplete(() =>
        {
            Align(GList.IndexOf(sorts[num - 1]));
        });
    }
    public void Align(int n)
    {
        int id = GList.IndexOf(sorts[num - 1]);
        int zheng = id - n;
        int fan = num - Mathf.Abs(zheng);
        fan = zheng < 0 ? fan : -fan;
        int interval = Mathf.Abs(zheng) < Mathf.Abs(zheng) ? zheng : fan;
        float intervalAng = interval * ang;
        float AlignAng = Mathf.Asin(sorts[num - 1].transform.localPosition.x / r) + intervalAng;
        float time =Mathf.Abs(AlignAng * r / cutspeed);
        DOTween.To((b) =>
        {
            moveAng = b;
            OnMove();
        }, moveAng, moveAng - AlignAng, time).OnComplete(() =>
        {
            Debug.Log(n);
        });
    }

这里需要添加using UnityEngine.EventSystems;命名空间,继承IDragHandler,IEndDragHandler这两个接口,之后就饿可以使用OnDrag方法和OnEndDrag方法

这样就可以实现拖拽旋转和旋转之后可以进行缓冲的效果了

因为在2d轮转图上在后面的图片需要变小所以我们在OnMove方法中添加代码

  sorts.Sort((a,b) =>
        {
            if (a.transform.localScale.z<b.transform.localScale.z)
            {
                return -1;
            }
            else if (a.transform.localScale.z == b.transform.localScale.z)
            {
                return 0;
            }
            else
            {
                return 1;
            }
        });
        for (int i = 0; i < sorts.Count; i++)
        {
            sorts[i].transform.SetSiblingIndex(i);
        }

这样就可以实现2d轮转图的拖拽旋转,在后面的物体变小的效果了

附上全部代码

 public GameObject prefab;
    public int num;
    public float r;
    public float max = 1;
    public float min = 0.5f;
    public float ang;
    public float moveAng = 0;
    public float cutspeed = 50f;//减速
    List<GameObject> GList = new List<GameObject>(); 
    List<GameObject> sorts = new List<GameObject>(); 
    // Start is called before the first frame update
    void Start()
    {
        r = prefab.GetComponent<RectTransform>().sizeDelta.x * num / (2 * Mathf.PI);
        ang = 2 * Mathf.PI / num;
        OnMove();
    }
    public void OnMove()
    {
        for (int i = 0; i < num; i++)
        {
            float x = Mathf.Sin(ang * i + moveAng) * r;
            float z = Mathf.Cos(ang * i + moveAng) * r;
            if (GList.Count<=i)
            {
                GameObject cell = Instantiate(prefab, transform);
                GList.Add(cell);
                sorts.Add(cell);
            }
            GList[i].transform.localPosition = new Vector3(x, 0, 0);
            float scale = (z + r) / (2 * r) * (max - min) + min;
            GList[i].transform.localScale = Vector3.one * scale;
        }
        sorts.Sort((a,b) =>
        {
            if (a.transform.localScale.z<b.transform.localScale.z)
            {
                return -1;
            }
            else if (a.transform.localScale.z == b.transform.localScale.z)
            {
                return 0;
            }
            else
            {
                return 1;
            }
        });
        for (int i = 0; i < sorts.Count; i++)
        {
            sorts[i].transform.SetSiblingIndex(i);
        }
    }

    public void OnDrag(PointerEventData eventData)
    {
        moveAng += eventData.delta.x / r;
        OnMove();
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        float time = Mathf.Abs(eventData.delta.x / cutspeed);
        DOTween.To((a) =>
        {
            moveAng += a / r;
            OnMove();
        }, eventData.delta.x, 0, time).OnComplete(() =>
        {
            Align(GList.IndexOf(sorts[num - 1]));
        });
    }
    public void Align(int n)
    {
        int id = GList.IndexOf(sorts[num - 1]);
        int zheng = id - n;
        int fan = num - Mathf.Abs(zheng);
        fan = zheng < 0 ? fan : -fan;
        int interval = Mathf.Abs(zheng) < Mathf.Abs(zheng) ? zheng : fan;
        float intervalAng = interval * ang;
        float AlignAng = Mathf.Asin(sorts[num - 1].transform.localPosition.x / r) + intervalAng;
        float time =Mathf.Abs(AlignAng * r / cutspeed);
        DOTween.To((b) =>
        {
            moveAng = b;
            OnMove();
        }, moveAng, moveAng - AlignAng, time).OnComplete(() =>
        {
            Debug.Log(n);
        });
    }

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值