欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Unity-保卫萝卜-翻书效果的实现(基于Scroll View组件)

程序员文章站 2022-07-12 23:33:40
...

前言:(需求:鼠标一次滑动一个页面 或者 多个页面)
在我们的游戏制作(虚拟仿真)的过程中,有的时候会使用翻书的一个效果进行控制页面的

首先上公式: UI 宽度 = 原宽度 + (单元格长度 + 间隙) * (单元格数量 - 1)

第一种方法:使用比例进行控制滑动页数
Unity-保卫萝卜-翻书效果的实现(基于Scroll View组件)首先将Scroll View 将Content的长度 单位化变成了 0-1 的区间(这里使用到 Unity ScrollRect组件中的一个API,scrollrect.horizontalNormalizedPosition);先将物体的中心点取到并且计算滑动到的位置,Camera中心点距离当前那个单元格(物体的中心点)中心点最近就将物体固定在中心点。根据鼠标滚动的一个距离进行计算滑动所占的比例,根据比例来进行调整位置。接着往下面走的话就是我们书写脚本,首先是定义成员变量。然后就是拿到 Scroll View 组件来完成翻书效果;

成员变量:
Content:容器的总长度 后面进行单位化(0-1)
Unity-保卫萝卜-翻书效果的实现(基于Scroll View组件)
StartMouseX:鼠标的开始位置、要知道用户开始滑动的位置(使用接口事件的方式)
EndMouseX:鼠标结束位置、松开的位置(使用接口事件的方式)
注:因为作者左边做的是水平方向的移动,所以只需取 X 的位置即可
Lerp:开始位置-结束位置>0。结束的X坐标大于开始的X坐标=右滑
           开始位置-结束位置<0。左滑动
           根据插值决定滑动几个格子。
Distance:
                (1)移动一个单元用户鼠标鼠标需要多少距离?
                 这里的话作者自己测试的是 : 左偏移(如下图 Left)+ 一个单元格的数量
                 Unity-保卫萝卜-翻书效果的实现(基于Scroll View组件)
                 大家可以需要根据自己项目进行测试
              (lerp > 移动一个单元格需要的距离进行比较 )移动一个单元格
                         <                                                               不进行移动
                 (2)移动多个单元格需要多少距离?
                 这里的公式是:左偏移 + 单元格长度
                                          后面每一个单元格的长度都是 : 一个单元格 + 间隔(当前单元格与上一单元格的距离)
由上面总结出:
比例计算公式 : 一个单元格中心点(物体) / Content 长度(容器的长度)
考虑到一直滑动的情况,所以需要两个目标上限值,Max 与 Min,当往右边进行滑动的时候直接进行归 1,往左边进行滑动的时候直接将 值归零。如果没有这一步操作的话。可能你就会口吐芬芳了。因为不论你左滑还是右滑的时候你都会看不到物体的。
Max:上限值
Min:下限值
接下来上代码----------------------------------------------

//==========================
// - FileName:      SliderCanMoveScrollView.cs         
// - Created:       true.	
// - CreateTime:    2020/02/27 15:43:01	
// - Email:         aaa@qq.com		
// - Region:        China WUHAN	
// - Description:   
//==========================
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using DG.Tweening;

public class SliderCanMoveScrollView : MonoBehaviour ,IBeginDragHandler,IEndDragHandler{
    private ScrollRect scrollRect;
    //容器的长度
    private float contentLength;
    //鼠标开始位置
    private float beginMousePositonX;
    //结束位置
    private float endMousePositionX;
    //上一位置的比例(单元格的中心点)
    private float lastProportion;
    //上下限
    private float Max;
    private float Min;
    //第一个单元格的距离
    private float firstItemLength;
    //滑动一个单元格的距离
    private float oneItemLength;
    //滑动一个单元格比例
    private float oneItemProportion;
    //单元格索引
    private int currentIndex;

    //单元格长度
    public int cellLength;
    //间隔
    public int spacing;
    //左偏移
    public int LeftOffset;
    //单元格个数
    public int totalItemNum;
    

    private void Awake()
    {
        scrollRect = GetComponent<ScrollRect>();
        //拿到容器长度
        contentLength = scrollRect.content.rect.xMax - 2 * LeftOffset - cellLength;
        //移动第一个单元格
        firstItemLength = cellLength / 2 + LeftOffset;
        //其他单元格
        oneItemLength = cellLength + spacing;
        //移动一个单元格的比例(移动一个单元格长度除以总长度)
        oneItemProportion = oneItemLength / contentLength;
        //上下限
        Max = 1- firstItemLength / contentLength;
        Min = firstItemLength / contentLength;//移动第一个单元格的长度 除以 容器的总长度
        //索引赋值
        currentIndex = 1;
        //从最左边开始
        scrollRect.horizontalNormalizedPosition = 0;
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        Debug.Log("开始拖拽");
        beginMousePositonX = Input.mousePosition.x;
        //Debug.Log("开始位置" + beginMousePositonX);
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        Debug.Log("结束拖拽");
        float offset = 0;
        endMousePositionX = Input.mousePosition.x;
        //Debug.Log("结束位置" + endMousePositionX);
        //插值
        //UI(世界坐标) 与鼠标(视口坐标)会发生一个偏差
        //Debug.Log("偏移" + offset);
        //Debug.Log("firstItemLength" + firstItemLength);
        offset = (beginMousePositonX - endMousePositionX) * 2;
        //偏移大于第一个单元格的距离的时候
        if (Mathf.Abs(offset)>firstItemLength)
        {
            //右滑 等于 0 的情况不考虑。使用 float
            if (offset > 0) 
            {
                //当前单元格判断是否到达最大值
                if (currentIndex >= totalItemNum)
                {
                    return;
                }
                //移动几个单元格,可以移动的数目
                int moveCount = (int)((offset - firstItemLength) / oneItemLength) + 1;
                //更新数值
                currentIndex += moveCount;
                //大于总数
                if (currentIndex>=totalItemNum)
                {
                    currentIndex = totalItemNum;
                }
                //当前的比例进行累加 需要移动的比例
                lastProportion += oneItemProportion * moveCount;
                //如果比例大于最大值的时候
                if (lastProportion >= Max)
                {
                    //停止进行滑动
                    lastProportion = 1;
                }
            }
            else //左滑
            {
                //累减
                if (currentIndex <= 1)
                {
                    return;
                }
                //移动几个单元格,可以移动的数目
                int moveCount = (int)((offset + firstItemLength) / oneItemLength) - 1;
                //更新数值
                currentIndex += moveCount;
                //大于总数
                if (currentIndex <= 1)
                {
                    currentIndex = 1;
                }
                //当前的比例进行累加 需要移动的比例
                lastProportion += oneItemProportion * moveCount;
                //如果比例大于最大值的时候
                if (lastProportion <= Min)
                {
                    //停止进行滑动
                    lastProportion = 0;
                }
            }
        } 
        //使用 Dowtenn 缓动函数进行视觉改变
        DOTween.To(() =>
        scrollRect.horizontalNormalizedPosition, lerpValue => 
        scrollRect.horizontalNormalizedPosition = lerpValue, lastProportion, 0.3f).SetEase(Ease.OutQuart);

    }
}

第二种方法:使用Conten进行:
在Unity中Content 在移动的时候进行计算距离,比如当前鼠标滑动的是100,第二次的时候就是200,第三次的时候是300,依次进行累加。如果说这边能够得到某一个值的时候,直接让物体固定在移动的位置即可。
方法二和方法一有相同的特点:所以这里直接上代码就行了。

//==========================
// - FileName:      SliderScrollView.cs         
// - Created:       true.	
// - CreateTime:    2020/02/27 17:07:11	
// - Email:         aaa@qq.com		
// - Region:        China WUHAN	
// - Description:   
//==========================
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using DG.Tweening;

public class SliderScrollView : MonoBehaviour ,IBeginDragHandler,IEndDragHandler{

    private ScrollRect scrollRect;
    //容器
    private RectTransform contentTrans;
    //起始、重点位置
    private float beginMousePosition;
    private float endMousePosition;
    //当前的物体的局部坐标,记录每次的位置
    private Vector3 currentContentLocalPos;
    //移动一个单元格的距离
    private float moveOneItemLength;
    //第几个单元格
    private int currentIndex;



    //单元格长度
    public int cellLength;
    //间隔
    public int spacing;
    //左偏移
    public int leftOffset;
    //单元格个数
    public int totalItemNum;
    
    private void Awake()
    {
        scrollRect = GetComponent<ScrollRect>();
        //拿到容器的 位置信息
        contentTrans = scrollRect.content;
        //移动一个单元格的距离
        moveOneItemLength = cellLength + spacing;
        //容器的当前位置
        currentContentLocalPos = contentTrans.localPosition;
        currentIndex = 1;
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        beginMousePosition = Input.mousePosition.x;
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        endMousePosition = Input.mousePosition.x;
        //插值
        float offSetX = 0;
        //需要滑动的距离
        float moveDistance = 0;
        //偏移的位置
        offSetX = beginMousePosition - endMousePosition;
        //右滑
        if (offSetX > 0)
        {
            //到达最右了
            if (currentIndex >= totalItemNum)
            {
                return;
            }
            //没有到的时候就让它到达
            moveDistance = -moveOneItemLength;
            //单元格加加
            currentIndex++;
        }
        else  //左滑
        {
            if (currentIndex <= 1)
            {
                return;
            }
            moveDistance = moveOneItemLength;
            //每次只滑动一次
            currentIndex--;
        }

        //缓动函数
        DOTween.To(() => contentTrans.localPosition,lerpValue => contentTrans.localPosition = lerpValue, currentContentLocalPos + new Vector3(moveDistance, 0, 0), 0.5f).SetEase(Ease.OutQuart);
        //累加局部坐标
        currentContentLocalPos += new Vector3(moveDistance, 0, 0);
        Debug.Log(currentContentLocalPos);
    }
}
相关标签: Unity 3D