简单选择板
实现要求
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控件进行拖动时候进行逻辑编写
完整项目和游戏视频请点击传送门