Unity3dUGUI图片循环轮播效果

简介: 测试.gif参数using UnityEngine.UI;using UnityEngine.EventSystems;using System;using UnityEngine;/// /// 图片轮播组件...
img_adafcf7f62396c5d0589f865ee01a5f6.gif
测试.gif
img_9481ee5486d3eb5ed3a6abb26b929114.png
参数
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;
using UnityEngine;

/// <summary>
/// 图片轮播组件
/// </summary>
public class NewCarouselImage : UIBehaviour, IBeginDragHandler, IInitializePotentialDragHandler, IDragHandler, IEndDragHandler, ICanvasElement
{
    /// <summary>
    /// 滚动方向H or V
    /// </summary>
    public enum AxisType
    {
        Horizontal,
        Vertical
    }

    /// <summary>
    /// 图片轮播方向
    /// </summary>
    public enum LoopDirType
    {
        RightOrUp = -1,
        LeftOrDown = 1,
    }

    /// <summary>
    /// 子物体size
    /// </summary>
    public Vector2 mCellSize;

    /// <summary>
    /// 子物体间隔
    /// </summary>
    public Vector2 mSpacing;

    /// <summary>
    /// 方向
    /// </summary>
    public AxisType MMoveAxisType;

    /// <summary>
    /// 轮播方向-- 1为向左移动,-1为向右移动
    /// </summary>
    public LoopDirType mLoopDirType = LoopDirType.LeftOrDown;

    /// <summary>
    /// Tween时的步数
    /// </summary>
    [Range(1, 500)]
    public int mTweenStepNum = 150;

    /// <summary>
    /// 自动轮播
    /// </summary>
    public bool mAutoLoop = false;

    /// <summary>
    /// 可否拖动
    /// </summary>
    public bool mDrag = false;

    /// <summary>
    /// 下一次播放间隔时间
    /// </summary>
    public float mLoopSpaceTime = 1;

    /// <summary>
    /// 位于正中的子元素变化的事件,参数为index
    /// </summary>
    [HideInInspector]
    public Action<int> mOnIndexChange;
    /// <summary>
    /// 当前处于正中的元素
    /// </summary>
    public int CurrentIndex
    {
        get
        {
            return m_index;
        }
    }

    private bool m_Dragging = false;
    private bool m_IsNormalizing = false;
    private Vector2 m_CurrentPos;
    private int m_currentStep = 0;
    private RectTransform viewRectTran;
    private Vector2 m_PrePos;
    private int m_index = 0, m_preIndex = 0;
    private RectTransform header;
    private bool contentCheckCache = true;

    private float currTimeDelta = 0;
    private float viewRectXMin
    {
        get
        {
            Vector3[] v = new Vector3[4];
            viewRectTran.GetWorldCorners(v);
            return v[0].x;
        }
    }
    private float viewRectXMax
    {
        get
        {
            Vector3[] v = new Vector3[4];
            viewRectTran.GetWorldCorners(v);
            return v[3].x;
        }
    }
    private float viewRectYMin
    {
        get
        {
            Vector3[] v = new Vector3[4];
            viewRectTran.GetWorldCorners(v);
            return v[0].y;
        }
    }
    private float viewRectYMax
    {
        get
        {
            Vector3[] v = new Vector3[4];
            viewRectTran.GetWorldCorners(v);
            return v[2].y;
        }
    }

    public int CellCount
    {
        get
        {
            return transform.childCount;
        }
    }
    protected override void Awake()
    {
        base.Awake();
        viewRectTran = GetComponent<RectTransform>();
        header = GetChild(viewRectTran, 0);
    }



    public void resizeChildren()
    {
        Vector2 delta;
        if (MMoveAxisType == AxisType.Horizontal)
        {
            delta = new Vector2(mCellSize.x + mSpacing.x, 0);
        }
        else
        {
            delta = new Vector2(0, mCellSize.y + mSpacing.y);
        }
        for (int i = 0; i < CellCount; i++)
        {
            var t = GetChild(viewRectTran, i);
            if (t)
            {
                t.localPosition = delta * i;
                t.sizeDelta = mCellSize;
            }
        }
        m_IsNormalizing = false;
        m_CurrentPos = Vector2.zero;
        m_currentStep = 0;
    }
    /// <summary>
    /// 加子物体到当前列表的最后面
    /// </summary>
    /// <param name="t"></param>
    public virtual void AddChild(RectTransform t)
    {
        if (t != null)
        {
            t.SetParent(viewRectTran, false);
            t.SetAsLastSibling();
            Vector2 delta;
            if (MMoveAxisType == AxisType.Horizontal)
            {
                delta = new Vector2(mCellSize.x + mSpacing.x, 0);
            }
            else
            {
                delta = new Vector2(0, mCellSize.y + mSpacing.y);
            }
            if (CellCount == 0)
            {
                t.localPosition = Vector3.zero;
                header = t;
            }
            else
            {
                t.localPosition = delta + (Vector2)GetChild(viewRectTran, CellCount - 1).localPosition;
            }
        }
    }
    protected override void OnEnable()
    {
        base.OnEnable();

        mOnIndexChange += OnChangeIndex;

        resizeChildren();
        return;
        if (Application.isPlaying)
        {
            if (ContentIsLongerThanRect())
            {
                int s;
                do
                {
                    s = GetBoundaryState();
                    LoopCell(s);
                } while (s != 0);
            }
        }
    }

    protected override void OnDisable()
    {
        base.OnDisable();
        mOnIndexChange -= OnChangeIndex;

    }

    protected virtual void Update()
    {
        if (ContentIsLongerThanRect())
        {
            //实现在必要时loop子元素
            if (Application.isPlaying)
            {
                int s = GetBoundaryState();
                LoopCell(s);
            }
            //缓动回指定位置
            if (m_IsNormalizing && EnsureListCanAdjust())
            {
                if (m_currentStep == mTweenStepNum)
                {
                    m_IsNormalizing = false;
                    m_currentStep = 0;
                    m_CurrentPos = Vector2.zero;
                    return;
                }
                Vector2 delta = m_CurrentPos / mTweenStepNum;
                m_currentStep++;
                TweenToCorrect(-delta);
            }
            //自动loop
            if (mAutoLoop && !m_IsNormalizing && EnsureListCanAdjust())
            {
                currTimeDelta += Time.deltaTime;
                if (currTimeDelta > mLoopSpaceTime)
                {
                    currTimeDelta = 0;
                    MoveToIndex(m_index + (int)mLoopDirType);
                }
            }
            //检测index是否变化
            if (MMoveAxisType == AxisType.Horizontal)
            {
                m_index = (int)(header.localPosition.x / (mCellSize.x + mSpacing.x - 1));
            }
            else
            {
                m_index = (int)(header.localPosition.y / (mCellSize.y + mSpacing.y - 1));
            }
            if (m_index <= 0)
            {
                m_index = Mathf.Abs(m_index);
            }
            else
            {
                m_index = CellCount - m_index;
            }
            if (m_index != m_preIndex)
            {
                if (mOnIndexChange != null)
                {
                    mOnIndexChange(m_index);
                }
            }
            m_preIndex = m_index;
        }
    }
    public virtual void OnBeginDrag(PointerEventData eventData)
    {
        if (!mDrag || !contentCheckCache)
        {
            return;
        }
        Vector2 vector;
        if (((eventData.button == PointerEventData.InputButton.Left) && this.IsActive()) && RectTransformUtility.ScreenPointToLocalPointInRectangle(this.viewRectTran, eventData.position, eventData.pressEventCamera, out vector))
        {
            this.m_Dragging = true;
            m_PrePos = vector;
        }
    }

    public virtual void OnInitializePotentialDrag(PointerEventData eventData)
    {
        if (!mDrag)
        {
            return;
        }
        return;
    }

    public virtual void OnDrag(PointerEventData eventData)
    {
        if (!mDrag || !contentCheckCache)
        {
            return;
        }
        Vector2 vector;
        if (((eventData.button == PointerEventData.InputButton.Left) && this.IsActive()) && RectTransformUtility.ScreenPointToLocalPointInRectangle(this.viewRectTran, eventData.position, eventData.pressEventCamera, out vector))
        {
            m_IsNormalizing = false;
            m_CurrentPos = Vector2.zero;
            m_currentStep = 0;
            Vector2 vector2 = vector - this.m_PrePos;
            Vector2 vec = CalculateOffset(vector2);
            this.SetContentPosition(vec);
            m_PrePos = vector;
        }
    }
    /// <summary>
    /// 移动到指定索引
    /// </summary>
    /// <param name="ind"></param>
    public virtual void MoveToIndex(int ind)
    {
        if (m_IsNormalizing)
        {
            return;
        }
        if (ind == m_index)
        {
            return;
        }
        this.m_IsNormalizing = true;
        Vector2 offset;
        if (MMoveAxisType == AxisType.Horizontal)
        {
            offset = new Vector2(mCellSize.x + mSpacing.x, 0);
        }
        else
        {
            offset = new Vector2(0, mCellSize.y + mSpacing.y);
        }
        var delta = CalcCorrectDeltaPos();
        int vindex = m_index;
        m_CurrentPos = delta + offset * (ind - vindex);
        m_currentStep = 0;
    }
    private Vector2 CalculateOffset(Vector2 delta)
    {
        if (MMoveAxisType == AxisType.Horizontal)
        {
            delta.y = 0;
        }
        else
        {
            delta.x = 0;
        }
        return delta;
    }
    private void SetContentPosition(Vector2 position)
    {
        foreach (RectTransform i in viewRectTran)
        {
            i.localPosition += (Vector3)position;
        }
        return;
    }

    public virtual void OnEndDrag(PointerEventData eventData)
    {
        if (!mDrag || !contentCheckCache)
        {
            return;
        }
        this.m_Dragging = false;
        this.m_IsNormalizing = true;
        m_CurrentPos = CalcCorrectDeltaPos();
        m_currentStep = 0;
    }

    public virtual void Rebuild(CanvasUpdate executing)
    {
        return;
    }
    /// <summary>
    /// List是否处于可自由调整状态
    /// </summary>
    /// <returns></returns>
    public virtual bool EnsureListCanAdjust()
    {
        return !m_Dragging && ContentIsLongerThanRect();
    }
    /// <summary>
    /// 内容是否比显示范围大
    /// </summary>
    /// <returns></returns>
    public virtual bool ContentIsLongerThanRect()
    {
        float contentLen;
        float rectLen;
        if (MMoveAxisType == AxisType.Horizontal)
        {
            contentLen = CellCount * (mCellSize.x + mSpacing.x) - mSpacing.x;
            rectLen = viewRectTran.rect.xMax - viewRectTran.rect.xMin;
        }
        else
        {
            contentLen = CellCount * (mCellSize.y + mSpacing.y) - mSpacing.y;
            rectLen = viewRectTran.rect.yMax - viewRectTran.rect.yMin;
        }
        contentCheckCache = contentLen > rectLen;
        return contentCheckCache;
    }
    /// <summary>
    /// 检测边界情况,分为0未触界,-1左(下)触界,1右(上)触界
    /// </summary>
    /// <returns></returns>
    public virtual int GetBoundaryState()
    {
        RectTransform left;
        RectTransform right;
        left = GetChild(viewRectTran, 0);
        right = GetChild(viewRectTran, CellCount - 1);
        Vector3[] l = new Vector3[4];
        left.GetWorldCorners(l);
        Vector3[] r = new Vector3[4];
        right.GetWorldCorners(r);
        if (MMoveAxisType == AxisType.Horizontal)
        {
            if (l[0].x >= viewRectXMin)
            {
                return -1;
            }
            else if (r[3].x < viewRectXMax)
            {
                return 1;
            }
        }
        else
        {
            if (l[0].y >= viewRectYMin)
            {
                return -1;
            }
            else if (r[1].y < viewRectYMax)
            {
                return 1;
            }
        }
        return 0;
    }
    /// <summary>
    /// Loop列表,分为-1把最右(上)边一个移到最左(下)边,1把最左(下)边一个移到最右(上)边
    /// </summary>
    /// <param name="dir"></param>
    protected virtual void LoopCell(int dir)
    {
        if (dir == 0)
        {
            return;
        }
        RectTransform MoveCell;
        RectTransform Tarborder;
        Vector2 TarPos;
        if (dir == 1)
        {
            MoveCell = GetChild(viewRectTran, 0);
            Tarborder = GetChild(viewRectTran, CellCount - 1);
            MoveCell.SetSiblingIndex(CellCount - 1);
        }
        else
        {
            Tarborder = GetChild(viewRectTran, 0);
            MoveCell = GetChild(viewRectTran, CellCount - 1);
            MoveCell.SetSiblingIndex(0);
        }
        if (MMoveAxisType == AxisType.Horizontal)
        {
            TarPos = Tarborder.localPosition + new Vector3((mCellSize.x + mSpacing.x) * dir, 0, 0);
        }
        else
        {
            TarPos = (Vector2)Tarborder.localPosition + new Vector2(0, (mCellSize.y + mSpacing.y) * dir);
        }
        MoveCell.localPosition = TarPos;
    }
    /// <summary>
    /// 计算一个最近的正确位置
    /// </summary>
    /// <returns></returns>
    public virtual Vector2 CalcCorrectDeltaPos()
    {
        Vector2 delta = Vector2.zero;
        float distance = float.MaxValue;
        foreach (RectTransform i in viewRectTran)
        {
            var td = Mathf.Abs(i.localPosition.x) + Mathf.Abs(i.localPosition.y);
            if (td <= distance)
            {
                distance = td;
                delta = i.localPosition;
            }
            else
            {
                break;
            }
        }
        return delta;
    }
    /// <summary>
    /// 移动指定增量
    /// </summary>
    protected virtual void TweenToCorrect(Vector2 delta)
    {
        foreach (RectTransform i in viewRectTran)
        {
            i.localPosition += (Vector3)delta;
        }
    }

    private static RectTransform GetChild(RectTransform parent, int index)
    {
        if (parent == null || index >= parent.childCount)
        {
            return null;
        }
        return parent.GetChild(index) as RectTransform;
    }

    public void LayoutComplete()
    {
    }

    public void GraphicUpdateComplete()
    {
    }

    /// <summary>
    /// 当前中心位置index回调
    /// </summary>
    /// <param name="index"></param>
    public void OnChangeIndex(int index)
    {

    }

}

相关文章
|
6月前
|
C# 图形学
【Unity 3D】C#中while do while for foreach等循环语句的讲解(附测试代码)
【Unity 3D】C#中while do while for foreach等循环语句的讲解(附测试代码)
230 0
|
图形学
unity实战之循环列表item渐显
循环列表item渐显效果
|
3月前
|
图形学 C#
超实用!深度解析Unity引擎,手把手教你从零开始构建精美的2D平面冒险游戏,涵盖资源导入、角色控制与动画、碰撞检测等核心技巧,打造沉浸式游戏体验完全指南
【8月更文挑战第31天】本文是 Unity 2D 游戏开发的全面指南,手把手教你从零开始构建精美的平面冒险游戏。首先,通过 Unity Hub 创建 2D 项目并导入游戏资源。接着,编写 `PlayerController` 脚本来实现角色移动,并添加动画以增强视觉效果。最后,通过 Collider 2D 组件实现碰撞检测等游戏机制。每一步均展示 Unity 在 2D 游戏开发中的强大功能。
159 6
|
2月前
|
测试技术 C# 图形学
掌握Unity调试与测试的终极指南:从内置调试工具到自动化测试框架,全方位保障游戏品质不踩坑,打造流畅游戏体验的必备技能大揭秘!
【9月更文挑战第1天】在开发游戏时,Unity 引擎让创意变为现实。但软件开发中难免遇到 Bug,若不解决,将严重影响用户体验。调试与测试成为确保游戏质量的最后一道防线。本文介绍如何利用 Unity 的调试工具高效排查问题,并通过 Profiler 分析性能瓶颈。此外,Unity Test Framework 支持自动化测试,提高开发效率。结合单元测试与集成测试,确保游戏逻辑正确无误。对于在线游戏,还需进行压力测试以验证服务器稳定性。总之,调试与测试贯穿游戏开发全流程,确保最终作品既好玩又稳定。
92 4
|
3月前
|
图形学 缓存 算法
掌握这五大绝招,让您的Unity游戏瞬间加载完毕,从此告别漫长等待,大幅提升玩家首次体验的满意度与留存率!
【8月更文挑战第31天】游戏的加载时间是影响玩家初次体验的关键因素,特别是在移动设备上。本文介绍了几种常见的Unity游戏加载优化方法,包括资源的预加载与异步加载、使用AssetBundles管理动态资源、纹理和模型优化、合理利用缓存系统以及脚本优化。通过具体示例代码展示了如何实现异步加载场景,并提出了针对不同资源的优化策略。综合运用这些技术可以显著缩短加载时间,提升玩家满意度。
102 5
|
2月前
|
前端开发 图形学 开发者
【独家揭秘】那些让你的游戏瞬间鲜活起来的Unity UI动画技巧:从零开始打造动态按钮,提升玩家交互体验的绝招大公开!
【9月更文挑战第1天】在游戏开发领域,Unity 是最受欢迎的游戏引擎之一,其强大的跨平台发布能力和丰富的功能集让开发者能够迅速打造出高质量的游戏。优秀的 UI 设计对于游戏至关重要,尤其是在手游市场,出色的 UI 能给玩家留下深刻的第一印象。Unity 的 UGUI 系统提供了一整套解决方案,包括 Canvas、Image 和 Button 等组件,支持添加各种动画效果。
122 3
|
2月前
|
设计模式 存储 人工智能
深度解析Unity游戏开发:从零构建可扩展与可维护的游戏架构,让你的游戏项目在模块化设计、脚本对象运用及状态模式处理中焕发新生,实现高效迭代与团队协作的完美平衡之路
【9月更文挑战第1天】游戏开发中的架构设计是项目成功的关键。良好的架构能提升开发效率并确保项目的长期可维护性和可扩展性。在使用Unity引擎时,合理的架构尤为重要。本文探讨了如何在Unity中实现可扩展且易维护的游戏架构,包括模块化设计、使用脚本对象管理数据、应用设计模式(如状态模式)及采用MVC/MVVM架构模式。通过这些方法,可以显著提高开发效率和游戏质量。例如,模块化设计将游戏拆分为独立模块。
167 3
|
3月前
|
图形学 开发者 存储
超越基础教程:深度拆解Unity地形编辑器的每一个隐藏角落,让你的游戏世界既浩瀚无垠又细节满满——从新手到高手的全面技巧升级秘籍
【8月更文挑战第31天】Unity地形编辑器是游戏开发中的重要工具,可快速创建复杂多变的游戏环境。本文通过比较不同地形编辑技术,详细介绍如何利用其功能构建广阔且精细的游戏世界,并提供具体示例代码,展示从基础地形绘制到植被与纹理添加的全过程。通过学习这些技巧,开发者能显著提升游戏画面质量和玩家体验。
126 3
|
3月前
|
图形学 机器学习/深度学习 人工智能
颠覆传统游戏开发,解锁未来娱乐新纪元:深度解析如何运用Unity引擎结合机器学习技术,打造具备自我进化能力的智能游戏角色,彻底改变你的游戏体验——从基础设置到高级应用全面指南
【8月更文挑战第31天】本文探讨了如何在Unity中利用机器学习增强游戏智能。作为领先的游戏开发引擎,Unity通过ML-Agents Toolkit等工具支持AI代理的强化学习训练,使游戏角色能自主学习完成任务。文章提供了一个迷宫游戏示例及其C#脚本,展示了环境观察、动作响应及奖励机制的设计,并介绍了如何设置训练流程。此外,还提到了Unity与其他机器学习框架(如TensorFlow和PyTorch)的集成,以实现更复杂的游戏玩法。通过这些技术,游戏的智能化程度得以显著提升,为玩家带来更丰富的体验。
61 1