Unity3d學習之路-簡單選擇板
簡單選擇板
實現要求
UI效果製作,進入NGUI官方網站,使用UGUI實現Scroll View選擇板
實現過程
基礎UI設定
首先建立一個Scroll View,設定ScrollRect的Anchors在中心。在Unity2018版本中會出現一個水平的滾動條和豎直的滾動條,刪除豎直的滾動條,並且在Scroll Rect中設定Vertical Scrollbar為None
為Content新增Grid Layout Group元件,Content的Pivot設定為0,0.5 ,將Content調至合適的寬度和高度,在Content裡新增11個Image,設定好圖片
在Scroll View新增一個Panel作為中心框,並且調整透明度以及新增一個邊框。Panel的邊框是用一張黑色的圖片製作的,名字叫Board(2),Image Type設定為Sliced,不勾選Fill Center
最終效果
在Scroll View外,新增一個Toggle,並且設定文字
實現遊戲邏輯
- Content的子物體居中
在遊戲執行一開始,獲得滾動框的長度,然後根據每個子物體的寬度和間隔,計算出每個子物體分別在中心位置時的x軸座標。在中心框出現且滑動或滾動結束後,找出裡中心點最近的子物體,並且將該子物體移動到之前計算好的位置。
public class CenterOnChild : MonoBehaviour, IEndDragHandler, IDragHandler
{
public float centerSpeed = 10f; //將子物體拉到中心位置時的速度
public GameObject panel; //中心的選中框
private ScrollRect scrollView;
private Transform container; //可滾動部分的內容
private bool centering = false;
private bool drag = false;
private bool check = false; //是否選擇需要讓子物體在中心位置
private List<float> childrenPos = new List<float>(); //儲存每個子物體在中心時的x軸位置
private float targetPos; //當前子物體應該在中心時的x軸位置
void Start()
{
scrollView = GetComponent<ScrollRect>();
container = scrollView.content;
GridLayoutGroup grid = container.GetComponent<GridLayoutGroup>();
//計算第一個子物體位於中心時的位置
float childPos = scrollView.GetComponent<RectTransform>().rect.width * 0.5f - grid.cellSize.x * 0.5f;
childrenPos.Add(childPos);
//快取所有子物體位於中心時的位置
for (int i = 0; i < container.childCount - 1; i++)
{
childPos -= grid.cellSize.x + grid.spacing.x;
childrenPos.Add(childPos);
}
}
void Update()
{
if (centering && Input.GetAxis("Mouse ScrollWheel")==0 && check)
{
//獲得子物體當前位置
Vector3 vec = container.localPosition;
//將子物體的位置移到應該在中心時候的位置
vec.x = Mathf.Lerp(container.localPosition.x, targetPos, centerSpeed * Time.deltaTime);
container.localPosition = vec;
//如果位置相等則不用再移動
if (Mathf.Abs(container.localPosition.x - targetPos) < 0.01f)
{
centering = false;
}
}
}
public void OnEndDrag(PointerEventData eventData)
{
//拖動結束,需要移到中心位置
centering = true;
drag = false;
//找到最近的目標位置
targetPos = FindClosestPos(container.localPosition.x);
}
public void OnDrag(PointerEventData eventData)
{
//拖動中
drag = true;
centering = false;
}
//滑動條移動
public void ScrollbarDrag()
{
//不是直接拖動滑動框裡面的內容
if(!drag)
{
centering = true;
targetPos = FindClosestPos(container.localPosition.x);
}
}
private float FindClosestPos(float currentPos)
{
float closest = 0;
float distance = Mathf.Infinity;
for (int i = 0; i < childrenPos.Count; i++)
{
float pos = childrenPos[i];
float dis = Mathf.Abs(pos - currentPos);
//找尋距離當前位置最近的子物體中心位置
if (dis < distance)
{
distance = dis;
closest = pos;
}
}
//返回需要移動到最近的位置
return closest;
}
//改變選中勾選框
public void CheckToggle()
{
check = !check;
if(check)
{
//當選中時需要將最近的一個子物體移到中心框裡
centering = true;
targetPos = FindClosestPos(container.localPosition.x);
//中心框顯示
panel.SetActive(true);
}
else
{
panel.SetActive(false);
}
}
}
- 選中整個框體可以隨滑鼠移動
獲得滑鼠按下點的座標,使它轉化為UI介面的座標,設定選中框體的位置為滑鼠的位置
public class DragMove : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
public void OnBeginDrag(PointerEventData eventData)
{
SetPosition(eventData);
}
public void OnDrag(PointerEventData eventData)
{
SetPosition(eventData);
}
public void OnEndDrag(PointerEventData eventData)
{
SetPosition(eventData);
}
private void SetPosition(PointerEventData eventData)
{
var rectTransform = gameObject.GetComponent<RectTransform>();
Vector3 globalMousePos;
//將螢幕空間點轉換為位於給定RectTransform平面上的世界空間中的位置
if (RectTransformUtility.ScreenPointToWorldPointInRectangle(rectTransform, eventData.position, eventData.pressEventCamera, out globalMousePos))
{
rectTransform.position = globalMousePos;
}
}
}
UI與遊戲邏輯的結合
將CenterOnChild指令碼掛載到Scroll View上,將DragMove指令碼掛在到想要隨滑鼠移動的UI上。選中Scrollbar Horizontal,在On Value Changed新增Scroll View的CenterOnChild指令碼的
ScrollbarDrag
函式。選中Toggle,在On Value Changed新增Scroll View的CenterOnChild指令碼的CheckToggle
函式。當這兩個的值發生改變的時候就會呼叫這兩個函式。一開始的時候將Toggle不勾選,Panel隱藏。
實現效果
小結
Scroll View的製作一開始是按照網上的一篇教程走,一個空物體上新增各種與UI相關的元件構成的,後來發現Scroll View在Unity裡已經可以直接使用了,而且包含豎直和水平方向的滾動條。從空物體的元件堆積慢慢的實現一個效果更容易去理解這個效果是怎樣實現的。指令碼繼承IBeginDragHandler
, IDragHandler
, IEndDragHandler
這三個介面,能讓我們更容易對UI控制元件進行拖動時候進行邏輯編寫
完整專案和遊戲視訊請點選傳送門