Unity轮盘滚动效果

这里使用平面2d来模拟一个3d转换,原理很简单,假设有一个圆形,所有的物体都平均的分布在这个圆环轨迹上面。这个圆环轨迹就是所有物体运行的轨道,是个垂直于你(摄像机)的方向,在靠近摄像机的位置(实际是居中位置),物体尺寸越大,越靠后和靠近两边,物体尺寸越小。

生成的子物体,上面挂上这个脚本。
using System;
using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class RotationDiagramItem : MonoBehaviour,IDragHandler,IEndDragHandler
{
public int PosId;
private Action _moveAction;
private Image _image;
private float _offsetX;
private float _aniTime = 1;

private Image Image
{
    get
    {
        if (_image == null)
            _image = GetComponent<Image>();

        return _image;
    }
}

private RectTransform _rect;

private RectTransform Rect
{
    get
    {
        if (_rect == null)
            _rect = GetComponent<RectTransform>();

        return _rect;
    }
}

public void SetParent(Transform parent)
{
    transform.SetParent(parent);
}

public void SetSprite(Sprite sprite)
{
    Image.sprite = sprite;
}

public void SetPosData(ItemPosData data)
{
    Rect.DOAnchorPos(Vector2.right*data.X, _aniTime);
    Rect.DOScale(Vector3.one*data.ScaleTimes, _aniTime);
    
    StartCoroutine(Wait(data));
}

private IEnumerator Wait(ItemPosData data)
{
    yield return new WaitForSeconds(_aniTime*0.5f);
    transform.SetSiblingIndex(data.Order);
}

public void OnDrag(PointerEventData eventData)
{
    _offsetX += eventData.delta.x;
}

public void OnEndDrag(PointerEventData eventData)
{
    _moveAction(_offsetX);
    _offsetX = 0;
}

public void AddMoveListener(Action<float> onMove)
{
    _moveAction = onMove;
}

public void ChangeId(int symbol,int totalItemNum)
{
    int id = PosId;
    id += symbol;
    if (id < 0)
    {
        id += totalItemNum;
    }
    PosId = id%totalItemNum;
}

}


using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;

public class RotationDiagram2D : MonoBehaviour
{
public Vector2 ItemSize;
public Sprite[] ItemSprites;
public float Offset;
public float ScaleTimesMin;
public float ScaleTimesMax;

private List<RotationDiagramItem> _items;
private List<ItemPosData> _posData;

// Start is called before the first frame update
void Start()
{
    _items = new List<RotationDiagramItem>();
    _posData = new List<ItemPosData>();
    CreateItem();
    CalulateData();
    SetItemData();
}

private GameObject CreateTemplate()
{
    GameObject item = new GameObject("Template");
    item.AddComponent<RectTransform>().sizeDelta = ItemSize;
    item.AddComponent<Image>();
    item.AddComponent<RotationDiagramItem>();
    return item;
}

private void CreateItem()
{
    GameObject template = CreateTemplate();
    RotationDiagramItem itemTemp = null;
    foreach (Sprite sprite in ItemSprites)
    {
        itemTemp = Instantiate(template).GetComponent<RotationDiagramItem>();
        itemTemp.SetParent(transform);
        itemTemp.SetSprite(sprite);
        itemTemp.AddMoveListener(Change);
        _items.Add(itemTemp);
    }

    Destroy(template);
}

private void Change(float offsetX)
{
    int symbol = offsetX > 0 ? 1 : -1;
    Change(symbol);
}

private void Change(int symbol)
{
    foreach (RotationDiagramItem item in _items)
    {
        item.ChangeId(symbol, _items.Count);
    }

    for (int i = 0; i < _posData.Count; i++)
    {
        _items[i].SetPosData(_posData[_items[i].PosId]);
    }
}

private void CalulateData()
{
    List<ItemData> itemDatas = new List<ItemData>();

    float length = (ItemSize.x + Offset)*_items.Count;
    float radioOffset = 1/(float) _items.Count;

    float radio = 0;
    for (int i = 0; i < _items.Count; i++)
    {
        ItemData itemData = new ItemData();
        itemData.PosId = i;
        itemDatas.Add(itemData);

        _items[i].PosId = i;

        ItemPosData data = new ItemPosData();
        data.X = GetX(radio, length);
        data.ScaleTimes = GetScaleTimes(radio, ScaleTimesMax, ScaleTimesMin);

        radio += radioOffset;
        _posData.Add(data);
    }

    itemDatas = itemDatas.OrderBy(u => _posData[u.PosId].ScaleTimes).ToList();

    for (int i = 0; i < itemDatas.Count; i++)
    {
        _posData[itemDatas[i].PosId].Order = i;
    }
}

private void SetItemData()
{
    for (int i = 0; i < _posData.Count; i++)
    {
        _items[i].SetPosData(_posData[i]);
    }
}

private float GetX(float radio, float length)
{
    if (radio > 1 || radio < 0)
    {
        Debug.LogError("当前比例必须是0-1的值");
        return 0;
    }

    if (radio >= 0 && radio < 0.25f)
    {
        return length * radio;
    }
    else if (radio >= 0.25f && radio < 0.75f)
    {
        return length * (0.5f - radio);
    }
    else
    {
        return length * (radio - 1);
    }
}

public float GetScaleTimes(float radio, float max, float min)
{
    if (radio > 1 || radio < 0)
    {
        Debug.LogError("当前比例必须是0-1的值");
        return 0;
    }

    float scaleOffset = (max - min) / 0.5f;

    if (radio < 0.5f)
    {
        return max - scaleOffset * radio;
    }
    else
    {
        return max - scaleOffset * (1 - radio);
    }
}

}

public class ItemPosData
{
public float X;
public float ScaleTimes;
public int Order;
}

public struct ItemData
{
public int PosId;
}

父物体挂上这个脚本。然后需要在父物体的脚本上面设定调整脚本的参数,运行即可。

在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值