Unity實(shí)現(xiàn)仿3D輪轉(zhuǎn)圖效果
本文實(shí)例為大家分享了Unity實(shí)現(xiàn)仿3D輪轉(zhuǎn)圖效果的具體代碼,供大家參考,具體內(nèi)容如下
一、效果演示
二、實(shí)現(xiàn)思路
——獲取位置:可以將每個(gè)item的運(yùn)行軌跡看作一個(gè)橢圓,分為四段進(jìn)行觀察,四個(gè)黑點(diǎn)視為四個(gè)item,觀察四個(gè)黑點(diǎn)的位置,比例值為0.125和0.375的位置相同,比例值為0.625和0.875的位置相同,比例值為0.375和0.625的位置相反,可得結(jié)論
[0,0.25]:軌跡總長度*當(dāng)前比例值
(0.25,0.5]:軌跡總長度 * (0.5 - 當(dāng)前比例值)
(0.5,0.75]:軌跡總長度 * (0.5 - 當(dāng)前比例值)
(0.75,1]:軌跡總長度 * (當(dāng)前比例值 - 1)
——獲取縮放值:可以將每個(gè)item的運(yùn)行軌跡看作一個(gè)橢圓,分為四段進(jìn)行觀察,四個(gè)黑點(diǎn)視為四個(gè)item,觀察四個(gè)黑點(diǎn)的位置,比例值為0時(shí)縮放值應(yīng)為最大,比例值為0.5時(shí)縮放值應(yīng)為最小,可得結(jié)論
[0-0.5]:縮放最大值 - 比例值 * (縮放最大值 - 縮放最小值) * 2
(0.5-1]:縮放最大值 - (1 - 比例值) * (縮放最大值 - 縮放最小值) * 2
——獲取層級(jí):使用UGUI的自然層級(jí)進(jìn)行排序(越靠下越后渲染),拷貝一份列表item數(shù)據(jù)列表按照縮放值從小到大的順序排序,再通過SetSiblingIndex依次設(shè)置層級(jí)
三、使用
——常規(guī)使用
SetData:傳入item預(yù)制體和列表中item個(gè)數(shù)
OnSetItem:綁定設(shè)置item的方法
SetList:設(shè)置列表的顯示
using UnityEngine; using UnityEngine.UI; ? public class Test : MonoBehaviour { ? ? public GameObject prefab; ? ? ? public Rotary3DList rotary3DList; ? ? ? private void Start() ? ? { ? ? ? ? rotary3DList.SetData(prefab, 5); ? ? ? ? rotary3DList.OnSetItem = SetItem; ? ? ? ? rotary3DList.SetList(); ? ? } ? ? ? void SetItem(Rotary3DList.ListItemData listItemData) ? ? { ? ? ? ? listItemData.go.GetComponent<Text>().txt = listItemData.index.ToString(); ? ? } }
——MoveToIndex:移動(dòng)到某一個(gè)下標(biāo)位置,isScroll表示是否滑動(dòng)到指定位置
——GetListItemData:獲取到某個(gè)下標(biāo)的item數(shù)據(jù)
——CenterIndex:當(dāng)前中心點(diǎn)item下標(biāo)
四、代碼實(shí)現(xiàn)
using System.Collections.Generic; using UnityEngine; using System; using UnityEngine.UI; using UnityEngine.EventSystems; using System.Linq; ? /// <summary> /// 仿3D輪轉(zhuǎn)圖組件 /// </summary> [AddComponentMenu("LFramework/UI/Rotary3DList", 50)] [RequireComponent(typeof(Image))] public class Rotary3DList : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler { ? ? /// <summary> ? ? /// 列表item數(shù)據(jù) ? ? /// </summary> ? ? public class ListItemData ? ? { ? ? ? ? public int index; ? ? ? ? public GameObject go; ? ? ? ? public float targetValue;//目標(biāo)位置長度值 ? ? ? ? public float tempValue;//臨時(shí)位置長度值(每次拖拽結(jié)束后才更新數(shù)值) ? ? } ? ? ? /// <summary> ? ? /// 輪轉(zhuǎn)類型 ? ? /// </summary> ? ? public enum RotaryType ? ? { ? ? ? ? Horizontal, ? ? ? ? Vertical, ? ? } ? ? ? public RotaryType rotaryType;//輪轉(zhuǎn)類型 ? ? public float spacing;//間隔 ? ? public float maxScale = 1;//最大縮放值 ? ? public float minScale = 0.5f;//最小縮放值 ? ? public float t = 0.1f;//緩動(dòng)插值 ? ? public Action<ListItemData> OnSetItem;//設(shè)置item ? ? public Action<PointerEventData> OnDragBegin;//拖拽開始 ? ? public Action<PointerEventData> OnDragging;//拖拽中 ? ? public Action<PointerEventData> OnDragEnd;//拖拽結(jié)束 ? ? ? //中心item下標(biāo) ? ? public int CenterIndex ? ? { ? ? ? ? get { return GetCenterItemIndex(); } ? ? } ? ? ? int m_ItemCount;//列表item總數(shù)量 ? ? float m_TotalValue;//總長度值 ? ? float m_DeltaValue;//長度值增量 ? ? GameObject m_Prefab; ? ? RectTransform m_ItemContainer; ? ? List<ListItemData> m_ListItemDataList = new List<ListItemData>(); ? ? ? bool m_InDrag; ? ? float m_BeginPos; ? ? List<float> m_InitValueList = new List<float>();//初始每個(gè)item的位置長度值 ? ? ? /// <summary> ? ? /// 設(shè)置數(shù)據(jù) ? ? /// </summary> ? ? public void SetData(GameObject prefab, int itemCount) ? ? { ? ? ? ? m_ItemContainer = GetComponent<RectTransform>(); ? ? ? ? m_ItemCount = itemCount; ? ? ? ? m_Prefab = prefab; ? ? ? ? m_DeltaValue = rotaryType == RotaryType.Horizontal ? ? ? ? ? ? ? (spacing + m_Prefab.GetComponent<RectTransform>().rect.width) ? ? ? ? ? ? : (spacing + m_Prefab.GetComponent<RectTransform>().rect.height); ? ? ? ? m_TotalValue = m_DeltaValue * m_ItemCount; ? ? ? ? ? InitData(); ? ? } ? ? ? /// <summary> ? ? /// 初始化數(shù)據(jù) ? ? /// </summary> ? ? void InitData() ? ? { ? ? ? ? float tempValue = 0; ? ? ? ? for (int i = 0; i < m_ItemCount; i++) ? ? ? ? { ? ? ? ? ? ? ListItemData data = new ListItemData(); ? ? ? ? ? ? data.index = i; ? ? ? ? ? ? data.go = Instantiate(m_Prefab, transform, m_ItemContainer); ? ? ? ? ? ? data.targetValue = tempValue; ? ? ? ? ? ? data.tempValue = tempValue; ? ? ? ? ? ? m_ListItemDataList.Add(data); ? ? ? ? ? ? m_InitValueList.Add(tempValue); ? ? ? ? ? ? ? tempValue += m_DeltaValue; ? ? ? ? } ? ? ? ? m_InitValueList.Add(m_TotalValue); ? ? } ? ? ? /// <summary> ? ? /// 設(shè)置列表 ? ? /// </summary> ? ? public void SetList() ? ? { ? ? ? ? foreach (var data in m_ListItemDataList) ? ? ? ? { ? ? ? ? ? ? OnSetItem?.Invoke(data); ? ? ? ? } ? ? ? ? ? UpdateItem(true); ? ? } ? ? ? /// <summary> ? ? /// 移動(dòng)到某個(gè)下標(biāo)位置 ? ? /// </summary> ? ? public void MoveToIndex(int index, bool isScroll = true) ? ? { ? ? ? ? if (index < 0 ? ? ? ? ? ? || index >= m_ItemCount) ? ? ? ? { ? ? ? ? ? ? Debug.LogError("下標(biāo)超出范圍,index : " + index); ? ? ? ? ? ? return; ? ? ? ? } ? ? ? ? ? int indexOffset = CenterIndex - index; ? ? ? ? foreach (var data in m_ListItemDataList) ? ? ? ? { ? ? ? ? ? ? float tempValue = data.tempValue + m_DeltaValue * indexOffset < 0 ? ? ? ? ? ? ? ? ? data.tempValue + m_DeltaValue * indexOffset + m_TotalValue ? ? ? ? ? ? ? ? : data.tempValue + m_DeltaValue * indexOffset; ? ? ? ? ? ? float targetValue = tempValue % m_TotalValue; ? ? ? ? ? ? data.targetValue = targetValue; ? ? ? ? ? ? data.tempValue = targetValue; ? ? ? ? } ? ? ? ? ? UpdateItem(!isScroll); ? ? } ? ? ? public void OnBeginDrag(PointerEventData eventData) ? ? { ? ? ? ? m_InDrag = true; ? ? ? ? m_BeginPos = rotaryType == RotaryType.Horizontal ? ? ? ? ? ? ? eventData.position.x ? ? ? ? ? ? : eventData.position.y; ? ? ? ? OnDragBegin?.Invoke(eventData); ? ? } ? ? ? public void OnDrag(PointerEventData eventData) ? ? { ? ? ? ? OnDragging?.Invoke(eventData); ? ? ? ? ? float endPos = rotaryType == RotaryType.Horizontal ? ? ? ? ? ? ? eventData.position.x ? ? ? ? ? ? : eventData.position.y; ? ? ? ? float offset = endPos - m_BeginPos; ? ? ? ? ? //計(jì)算item數(shù)據(jù) ? ? ? ? if (offset > 0) ? ? ? ? { ? ? ? ? ? ? foreach (var data in m_ListItemDataList) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? float tempValue = (data.tempValue + offset) % m_TotalValue; ? ? ? ? ? ? ? ? data.targetValue = tempValue; ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? else if (offset < 0) ? ? ? ? { ? ? ? ? ? ? foreach (var data in m_ListItemDataList) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? float tempValue = data.tempValue + offset < 0 ? ? ? ? ? ? ? ? ? ? ? m_TotalValue - Mathf.Abs(data.tempValue + offset) % m_TotalValue ? ? ? ? ? ? ? ? ? ? : (data.tempValue + offset) % m_TotalValue; ? ? ? ? ? ? ? ? data.targetValue = tempValue; ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? ? public void OnEndDrag(PointerEventData eventData) ? ? { ? ? ? ? m_InDrag = false; ? ? ? ? OnDragEnd?.Invoke(eventData); ? ? ? ? ? foreach (var data in m_ListItemDataList) ? ? ? ? { ? ? ? ? ? ? float nearlyValue = GetNearlyValue(data.targetValue); ? ? ? ? ? ? data.targetValue = nearlyValue; ? ? ? ? ? ? data.tempValue = nearlyValue; ? ? ? ? } ? ? } ? ? ? private void Update() ? ? { ? ? ? ? UpdateItem(false); ? ? } ? ? ? /// <summary> ? ? /// 更新item ? ? /// </summary> ? ? void UpdateItem(bool isForce) ? ? { ? ? ? ? //拖拽中-實(shí)時(shí)更新 ? ? ? ? if (m_InDrag) ? ? ? ? { ? ? ? ? ? ? foreach (var data in m_ListItemDataList) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? float ratio = data.targetValue / m_TotalValue; ? ? ? ? ? ? ? ? ? //更新位置 ? ? ? ? ? ? ? ? float pos = GetPos(ratio); ? ? ? ? ? ? ? ? Vector2 targetPos = rotaryType == RotaryType.Horizontal ? ? ? ? ? ? ? ? ? ? ? new Vector2(pos, 0) ? ? ? ? ? ? ? ? ? ? : new Vector2(0, pos); ? ? ? ? ? ? ? ? data.go.transform.localPosition = targetPos; ? ? ? ? ? ? ? ? ? //更新縮放值 ? ? ? ? ? ? ? ? float scale = GetScale(ratio); ? ? ? ? ? ? ? ? Vector2 targetScale = Vector3.one * scale; ? ? ? ? ? ? ? ? data.go.transform.localScale = targetScale; ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? //非拖拽中-緩動(dòng)更新 ? ? ? ? else ? ? ? ? { ? ? ? ? ? ? foreach (var data in m_ListItemDataList) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? float ratio = data.targetValue / m_TotalValue; ? ? ? ? ? ? ? ? ? //更新位置 ? ? ? ? ? ? ? ? float pos = GetPos(ratio); ? ? ? ? ? ? ? ? Vector2 targetPos = rotaryType == RotaryType.Horizontal ? ? ? ? ? ? ? ? ? ? ? new Vector2(pos, 0) ? ? ? ? ? ? ? ? ? ? : new Vector2(0, pos); ? ? ? ? ? ? ? ? float targetPosOffset = rotaryType == RotaryType.Horizontal ? ? ? ? ? ? ? ? ? ? ? data.go.transform.localPosition.x - targetPos.x ? ? ? ? ? ? ? ? ? ? : data.go.transform.localPosition.y - targetPos.y; ? ? ? ? ? ? ? ? data.go.transform.localPosition = Vector2.Lerp(data.go.transform.localPosition, targetPos, isForce ? 1 : t); ? ? ? ? ? ? ? ? if (Mathf.Abs(targetPosOffset) <= 0.01f) ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? data.go.transform.localPosition = targetPos; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? //更新縮放值 ? ? ? ? ? ? ? ? float scale = GetScale(ratio); ? ? ? ? ? ? ? ? Vector2 targetScale = Vector3.one * scale; ? ? ? ? ? ? ? ? float targetScaleOffset = data.go.transform.localScale.x - targetScale.x; ? ? ? ? ? ? ? ? data.go.transform.localScale = Vector2.Lerp(data.go.transform.localScale, targetScale, isForce ? 1 : t); ? ? ? ? ? ? ? ? if (Mathf.Abs(targetScaleOffset) <= 0.01f) ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? data.go.transform.localScale = targetScale; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? ? //更新層級(jí) ? ? ? ? var listItemDataList = m_ListItemDataList.OrderBy(data => GetScale(data.targetValue / m_TotalValue)).ToList(); ? ? ? ? for (int i = 0; i < m_ItemCount; i++) ? ? ? ? { ? ? ? ? ? ? listItemDataList[i].go.transform.SetSiblingIndex(i); ? ? ? ? } ? ? } ? ? ? /// <summary> ? ? /// 得到位置 ? ? /// </summary> ? ? float GetPos(float ratio) ? ? { ? ? ? ? if (ratio < 0 ? ? ? ? ? ? && ratio > 1) ? ? ? ? { ? ? ? ? ? ? Debug.LogError("比例值錯(cuò)誤,比例值必須為[0-1],ratio : " + ratio); ? ? ? ? ? ? return 0; ? ? ? ? } ? ? ? ? ? if (ratio >= 0 && ratio <= 0.25f) ? ? ? ? { ? ? ? ? ? ? return m_TotalValue * ratio; ? ? ? ? } ? ? ? ? else if (ratio > 0.25f && ratio <= 0.75f) ? ? ? ? { ? ? ? ? ? ? return m_TotalValue * (0.5f - ratio); ? ? ? ? } ? ? ? ? else ? ? ? ? { ? ? ? ? ? ? return m_TotalValue * (ratio - 1); ? ? ? ? } ? ? } ? ? ? /// <summary> ? ? /// 得到縮放值 ? ? /// </summary> ? ? float GetScale(float ratio) ? ? { ? ? ? ? if (ratio < 0 ? ? ? ? ? ? ? ?&& ratio > 1) ? ? ? ? { ? ? ? ? ? ? Debug.LogError("比例值錯(cuò)誤,比例值必須為[0-1],ratio : " + ratio); ? ? ? ? ? ? return 0; ? ? ? ? } ? ? ? ? ? float v = (maxScale - minScale) * 2; ? ? ? ? if (ratio >= 0 && ratio <= 0.5f) ? ? ? ? { ? ? ? ? ? ? return maxScale - ratio * v; ? ? ? ? } ? ? ? ? else ? ? ? ? { ? ? ? ? ? ? return maxScale - (1 - ratio) * v; ? ? ? ? } ? ? } ? ? ? /// <summary> ? ? /// 得到距離最近的位置長度值 ? ? /// </summary> ? ? float GetNearlyValue(float curValue) ? ? { ? ? ? ? float minDis = Mathf.Abs(curValue - m_InitValueList.First()); ? ? ? ? float nearlyValue = m_InitValueList.First(); ? ? ? ? foreach (var value in m_InitValueList) ? ? ? ? { ? ? ? ? ? ? float tempDis = Mathf.Abs(curValue - value); ? ? ? ? ? ? if (tempDis < minDis) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? minDis = tempDis; ? ? ? ? ? ? ? ? nearlyValue = value == m_TotalValue ? ? ? ? ? ? ? ? ? ? ? m_InitValueList.First() ? ? ? ? ? ? ? ? ? ? : value; ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? return nearlyValue; ? ? } ? ? ? /// <summary> ? ? /// 得到中心item的下標(biāo) ? ? /// </summary> ? ? int GetCenterItemIndex() ? ? { ? ? ? ? int index = 0; ? ? ? ? float minDis = Mathf.Min(Mathf.Abs(m_ListItemDataList[0].targetValue - m_InitValueList.First()), Mathf.Abs(m_ListItemDataList[0].targetValue - m_InitValueList.Last())); ? ? ? ? foreach (var data in m_ListItemDataList) ? ? ? ? { ? ? ? ? ? ? float tempDis = Mathf.Min(Mathf.Abs(data.targetValue - m_InitValueList.First()), Mathf.Abs(data.targetValue - m_InitValueList.Last())); ? ? ? ? ? ? if (tempDis < minDis) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? minDis = tempDis; ? ? ? ? ? ? ? ? index = data.index; ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? return index; ? ? } ? ? ? /// <summary> ? ? /// 得到列表item數(shù)據(jù) ? ? /// </summary> ? ? public ListItemData GetListItemData(int index) ? ? { ? ? ? ? if (index < 0 ? ? ? ? ? ?|| index >= m_ItemCount) ? ? ? ? { ? ? ? ? ? ? Debug.LogError("下標(biāo)超出范圍,index : " + index); ? ? ? ? ? ? return null; ? ? ? ? } ? ? ? ? ? return m_ListItemDataList[index]; ? ? } }
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
輸出的文本實(shí)現(xiàn)對(duì)齊的方法(超簡單)
下面小編就為大家分享一篇c#輸出的文本實(shí)現(xiàn)對(duì)齊的方法,特別簡單!希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-12-12C# List 并發(fā)丟數(shù)據(jù)問題原因及解決方案
這篇文章主要介紹了C# List 并發(fā)丟數(shù)據(jù)問題原因及解決方案,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下2021-02-02C# 開發(fā)(創(chuàng)藍(lán)253)手機(jī)短信驗(yàn)證碼接口的實(shí)例
下面小編就為大家分享一篇C# 開發(fā)(創(chuàng)藍(lán)253)手機(jī)短信驗(yàn)證碼接口的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-01-01