遊戲中的大地圖或者道具展現,都會有自動滑動到指定位置或道具的功能需求,下面我就介紹一下如何實現地圖的自動定位。git
首先,咱們要知道ScrollRect滑動的本質就是改變其normalizedPosition。normalizedPosition有兩個垂直方向和水平方向的份量分別叫作verticalNormalizedPosition和horizontalNormlizedPosition,二者的數值都處在閉區間【0-1】。那麼這個數值是如何計算出來的呢?其實很簡單,我畫個示意圖說明一下。github
如上圖所示,紅框表明的是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)]ide
若是MovementType已是Clamp,那就能夠把Mathf.Clamp01去掉。delta_Width是Content和ViewPort的寬度差,delta_Height是高度差。函數
計算方式很直觀,核心代碼也很簡單。spa
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。code
當新的normalizedPosition求出後,即可以實現緩動效果了,代碼以下。orm
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/ScrollRectAutoSlideblog