• 【Unity3d】ScrollRect自动定位到某点


    游戏中的大地图或者道具展示,都会有自动滑动到指定位置或道具的功能需求,下面我就介绍一下如何实现地图的自动定位。

    首先,我们要知道ScrollRect滑动的本质就是改变其normalizedPosition。normalizedPosition有两个垂直方向和水平方向的分量分别叫做verticalNormalizedPosition和horizontalNormlizedPosition,两者的数值都处在闭区间【0-1】。那么这个数值是如何计算出来的呢?其实很简单,我画个示意图说明一下。

     如上图所示,红框代表的是Content,蓝框是可视范围ViewPort,当两者处于上图的状态时,normalizedPosition就是(0,0),这也是它的缺省值。如果把位于Content上的A点移动至P点(就是把目标置于ViewPort的中心)的位置,normalizedPostion的计算方式就是

          normalizedPosition = new Vector[Mathf.Clamp01((A - P).X / delta_Width) , Mathf.Clamp01((A - P).Y / delta_Height)]

    如果MovementType已经是Clamp,那就可以把Mathf.Clamp01去掉。delta_Width是Content和ViewPort的宽度差,delta_Height是高度差。

    计算方式很直观,核心代码也很简单。

    private Vector2 CenterPoint(RectTransform target)
        {
            var content = worldMap.content.GetChild(0).GetComponent<RectTransform>();
            var viewport = worldMap.viewport;
            Vector3 targetPosition = worldMap.GetComponent<RectTransform>().InverseTransformPoint(Clear_Pivot_Offset(target));
            Vector3 viewportPosition = worldMap.GetComponent<RectTransform>().InverseTransformPoint(Clear_Pivot_Offset(viewport));
            Vector3 distance_vec = viewportPosition - targetPosition;        
            var height_Delta = content.rect.height - viewport.rect.height;
            var width_Delta = content.rect.width - viewport.rect.width;      
            var ratio_x = distance_vec.x / width_Delta;
            var ratio_y = distance_vec.y / height_Delta; 
            var ratioDistance = new Vector2(ratio_x, ratio_y);
            var newPosition = worldMap.normalizedPosition - ratioDistance;
            return new Vector2(Mathf.Clamp01(newPosition.x), Mathf.Clamp01(newPosition.y));        
        }
    
        private Vector3 Clear_Pivot_Offset(RectTransform rec)
        {
            var offset = new Vector3((0.5f - rec.pivot.x) * rec.rect.width, 
            (0.5f - rec.pivot.y) * rec.rect.height, 0.0f);
            var newPosition = rec.localPosition + offset;
            return rec.parent.TransformPoint(newPosition);
        }

    第一个方法CenterPoint没啥说的,就是把算法代码化。值得注意的是Clear_Pivot_Offset方法,这个方法的作用是消除Pivot数值的影响,Pivot不是(0.5,0.5)时,最后所计算出来的结果会有误差,各位不妨去掉此函数试一试。如果不明白Pivot的概念,可以看下这个链接,解释得很清楚——https://msd.misuland.com/pd/3070888525579681950。

    当新的normalizedPosition求出后,便可以实现缓动效果了,代码如下。

    void Update()
        {         
            if (_isSlide)
            {
                _currentTime += Time.deltaTime;
                _ratio = _currentTime / _limitTime;
                if (_currentTime >= _limitTime)
                {
                    _isSlide = false;
                    _ratio = _limitTime;
                    Debug.Log("Arrived");
                    _currentTime = 0.0f;
                    foreach (var btn in button)
                    {
                        btn.interactable = true;
                    }
                }
                var tempPosition = Vector2.Lerp(_startPosition, _newPosition, _ratio);
                worldMap.normalizedPosition = tempPosition;           
            }
        }

    完整的工程我已经上传至github,链接:https://github.com/codeghosts/ScrollRectAutoSlide

  • 相关阅读:
    分布式锁获取token
    美团-2019Q2述职总结
    linux df 日志删除命令分析
    MySQL、HBase、ES的特点和区别
    C++函数返回局部变量
    C语言 数组初始化的三种常用方法({0}, memset, for循环赋值)以及原理
    C Mysql API连接Mysql
    C++运算符重载
    C++对象赋值的四种方式
    C/C++下scanf的%匹配以及过滤字符串问题
  • 原文地址:https://www.cnblogs.com/RongQi/p/12920080.html
Copyright © 2020-2023  润新知