返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >Unity实现仿3D轮转图效果
  • 459
分享到

Unity实现仿3D轮转图效果

2024-04-02 19:04:59 459人浏览 独家记忆
摘要

本文实例为大家分享了Unity实现仿3D轮转图效果的具体代码,供大家参考,具体内容如下 一、效果演示 二、实现思路 ——获取位置:可以将每个item的运行轨

本文实例为大家分享了Unity实现仿3D轮转图效果的具体代码,供大家参考,具体内容如下

一、效果演示

二、实现思路

——获取位置:可以将每个item的运行轨迹看作一个椭圆,分为四段进行观察,四个黑点视为四个item,观察四个黑点的位置,比例值为0.125和0.375的位置相同,比例值为0.625和0.875的位置相同,比例值为0.375和0.625的位置相反,可得结论
[0,0.25]:轨迹总长度*当前比例值
(0.25,0.5]:轨迹总长度 * (0.5 - 当前比例值)
(0.5,0.75]:轨迹总长度 * (0.5 - 当前比例值)
(0.75,1]:轨迹总长度 * (当前比例值 - 1)

——获取缩放值:可以将每个item的运行轨迹看作一个椭圆,分为四段进行观察,四个黑点视为四个item,观察四个黑点的位置,比例值为0时缩放值应为最大,比例值为0.5时缩放值应为最小,可得结论
[0-0.5]:缩放最大值 - 比例值 * (缩放最大值 - 缩放最小值) * 2
(0.5-1]:缩放最大值 - (1 - 比例值) * (缩放最大值 - 缩放最小值) * 2

——获取层级:使用UGUI的自然层级进行排序(越靠下越后渲染),拷贝一份列表item数据列表按照缩放值从小到大的顺序排序,再通过SetSiblingIndex依次设置层级

三、使用

——常规使用
SetData:传入item预制体和列表中item个数
OnSetItem:绑定设置item的方法
SetList:设置列表的显示

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:移动到某一个下标位置,isScroll表示是否滑动到指定位置
——GetListItemData:获取到某个下标的item数据
——CenterIndex:当前中心点item下标

四、代码实现

using System.Collections.Generic;
using UnityEngine;
using System;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Linq;
 
/// <summary>
/// 仿3D轮转图组件
/// </summary>
[AddComponentMenu("LFramework/UI/Rotary3DList", 50)]
[RequireComponent(typeof(Image))]
public class Rotary3DList : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    /// <summary>
    /// 列表item数据
    /// </summary>
    public class ListItemData
    {
        public int index;
        public GameObject go;
        public float targetValue;//目标位置长度值
        public float tempValue;//临时位置长度值(每次拖拽结束后才更新数值)
    }
 
    /// <summary>
    /// 轮转类型
    /// </summary>
    public enum RotaryType
    {
        Horizontal,
        Vertical,
    }
 
    public RotaryType rotaryType;//轮转类型
    public float spacing;//间隔
    public float maxScale = 1;//最大缩放值
    public float minScale = 0.5f;//最小缩放值
    public float t = 0.1f;//缓动插值
    public Action<ListItemData> OnSetItem;//设置item
    public Action<PointerEventData> OnDragBegin;//拖拽开始
    public Action<PointerEventData> OnDragging;//拖拽中
    public Action<PointerEventData> OnDragEnd;//拖拽结束
 
    //中心item下标
    public int CenterIndex
    {
        get { return GetCenterItemIndex(); }
    }
 
    int m_ItemCount;//列表item总数量
    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>();//初始每个item的位置长度值
 
    /// <summary>
    /// 设置数据
    /// </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>
    /// 初始化数据
    /// </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>
    /// 设置列表
    /// </summary>
    public void SetList()
    {
        foreach (var data in m_ListItemDataList)
        {
            OnSetItem?.Invoke(data);
        }
 
        UpdateItem(true);
    }
 
    /// <summary>
    /// 移动到某个下标位置
    /// </summary>
    public void MoveToIndex(int index, bool isScroll = true)
    {
        if (index < 0
            || index >= m_ItemCount)
        {
            Debug.LogError("下标超出范围,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;
 
        //计算item数据
        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)
    {
        //拖拽中-实时更新
        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;
            }
        }
        //非拖拽中-缓动更新
        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;
                }
            }
        }
 
        //更新层级
        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("比例值错误,比例值必须为[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("比例值错误,比例值必须为[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的下标
    /// </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数据
    /// </summary>
    public ListItemData GetListItemData(int index)
    {
        if (index < 0
           || index >= m_ItemCount)
        {
            Debug.LogError("下标超出范围,index : " + index);
            return null;
        }
 
        return m_ListItemDataList[index];
    }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。

--结束END--

本文标题: Unity实现仿3D轮转图效果

本文链接: https://lsjlt.com/news/161856.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Unity实现仿3D轮转图效果
    本文实例为大家分享了Unity实现仿3D轮转图效果的具体代码,供大家参考,具体内容如下 一、效果演示 二、实现思路 ——获取位置:可以将每个item的运行轨...
    99+
    2024-04-02
  • css怎么实现3D图像轮转效果
    这篇文章主要讲解了“css怎么实现3D图像轮转效果”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“css怎么实现3D图像轮转效果”吧!首先看html文件,div.billboard为效果的容器...
    99+
    2023-07-04
  • js实现3D轮播图效果
    本文实例为大家分享了js实现3D轮播图效果的具体代码,供大家参考,具体内容如下 主要有平移和旋转构成3d效果的轮播图,小白一只,不足之处还请大家多多指教,代码如下 css代码: ...
    99+
    2024-04-02
  • 如何使用css实现3D图像轮转效果
    这篇文章主要为大家展示了“如何使用css实现3D图像轮转效果”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何使用css实现3D图像轮转效果”这篇文章吧。首先看...
    99+
    2024-04-02
  • 怎么用js实现3D轮播图效果
    本篇内容主要讲解“怎么用js实现3D轮播图效果”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么用js实现3D轮播图效果”吧!具体内容如下:主要有平移和旋转构成3d效果的轮播图,小白一只,不足之...
    99+
    2023-06-25
  • Unity Shader实现3D翻页效果
    本文实例为大家分享了Unity Shader实现3D翻页效果的具体代码,供大家参考,具体内容如下 参考文章:UnityShader使用Plane实现翻书效果 效果图: 原理:Sh...
    99+
    2024-04-02
  • Android集成Unity,实现3D看房效果
    引子 前几天有人找小编问能不能把3D模型放入到Unity中,再把Unity放入到Android APP中,在APP中实现观看房屋家具的功能,这次小编便来分享一下吧,如果还需要了解Android 集成Unity知识的,可以翻我主页其他文章 ...
    99+
    2023-08-31
    android unity 3d
  • Flutter仿网易实现广告卡片3D翻转效果
    目录前言实现思路1、获取各种距离2、翻转完整代码小结前言 在逛网易新闻时,发现列表中的广告在你滑动的时候会有一个3D旋转的交互引你的注意,不得不说这些产品为了让用户看广告花样百出,那...
    99+
    2024-04-02
  • JavaScript仿小米轮播图效果
    本文是自己仿写的小米轮播图的写法,通过透明度改变进行轮播的,新手,写的可能不是很好,有啥不合理的情况,望提出,指正,全部的代码放最下面 有很多写法重复,有空的时候,我把重复的代码封装...
    99+
    2024-04-02
  • iOS实现3D卡片式轮播效果
    本文实例为大家分享了iOS实现3D卡片式轮播效果的具体代码,供大家参考,具体内容如下 效果: 参考UITableView的UITableViewDataSource和UITable...
    99+
    2022-05-28
    iOS 3D 轮播
  • css3中怎么实现图形3d翻转效果
    css3中怎么实现图形3d翻转效果,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。<!DOCTYPE html&...
    99+
    2024-04-02
  • html5怎么实现图片的3D旋转效果
    本篇内容主要讲解“html5怎么实现图片的3D旋转效果”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“html5怎么实现图片的3D旋转效果”吧!   完整代码如...
    99+
    2024-04-02
  • Flutter仿网易怎么实现广告卡片3D翻转效果
    这篇文章主要介绍“Flutter仿网易怎么实现广告卡片3D翻转效果”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Flutter仿网易怎么实现广告卡片3D翻转效果”文章能帮助大家解决问题。先看下网易新...
    99+
    2023-06-30
  • Android实现轮播图效果
    本文实例为大家分享了Android实现轮播图效果的具体代码,供大家参考,具体内容如下 1.代码放在LinearLayout中, <com.jude.rollviewpage...
    99+
    2024-04-02
  • bootstrap实现轮播图效果
    本文实例为大家分享了bootstrap实现轮播图效果的具体代码,供大家参考,具体内容如下 实现效果 步骤 1、下载bootstrap和jquery-3.6.0.min.js,并在h...
    99+
    2024-04-02
  • React实现轮播图效果
    本文实例为大家分享了React实现轮播图效果的具体代码,供大家参考,具体内容如下 效果: 轮播功能用到了react-slick组件,安装: npm install react-sl...
    99+
    2024-04-02
  • vue实现3D环形图效果
    本文实例为大家分享了vue实现3D环形图效果的具体代码,供大家参考,具体内容如下 1.引入highcharts 2.main.js引入highcharts import highch...
    99+
    2024-04-02
  • vue+highcharts实现3D饼图效果
    本文实例为大家分享了vue+highcharts实现3D饼图效果的具体代码,供大家参考,具体内容如下 这是最终效果 <template> <div class="...
    99+
    2024-04-02
  • css3代码如何实现图形3d翻转效果
    这篇“css3代码如何实现图形3d翻转效果”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“css3代码如何实现图形3d翻转效果...
    99+
    2023-07-04
  • css3如何实现3d翻转效果
    今天小编给大家分享的是css3如何实现3d翻转效果,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获的哦。什么是csscss是一种用来表现HTML或XML等文件样式的计算机语言,主要是用来设计...
    99+
    2023-06-14
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作