UGUI中ScrollRect本来是用来做水平和垂直的滑动列表的。并且内置了惯性滑动和边界弹性限制。但经过一些设置,完全可以用来做一个可以拖动的地图功能。首先,介绍一下属性的意思。
Content: 这是ScrollRect显示内容的实际区域。
Horizontal: 是否可以水平滚动
Vertical: 是否可以垂直滚动
MovementType: 运动到边界的限制类型, 有不限制,弹性,限制三种
Inertia: 是否有 滑动的惯性
DecelerationRate: 惯性减速率
ScrollSensitivity: 滚动敏感度
ViewPort: 可是区域的大小
还有2个是水平和垂直的滚动条,做地图的话不需要显示。
如果用来制作地图,基本思路是。让ScroolRect可以水平和垂直滑动,惯性衰减运动和滑动敏感度可以直接使用,边界限制使用Clamped就是边界严格限制。最重要的是,Content设置为地图的真实大小比如 3000 * 30000的组件,而可视区域的大小就是屏幕的大小。这样地图就能够在屏幕区域内容易拖动。
如果还需要给地图增加多点触摸缩放的功能,就需要复写ScrollRect来处理。如下一个完整可以使用的封装:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
namespace Framework
{
public class MyScrollRect : ScrollRect
{
private int touchNum = 0;
public override void OnBeginDrag (PointerEventData eventData)
{
if(Input.touchCount > 1)
{
return;
}
base.OnBeginDrag(eventData);
}
public override void OnDrag (PointerEventData eventData)
{
if (Input.touchCount > 1)
{
touchNum = Input.touchCount;
return;
}
else if(Input.touchCount == 1 && touchNum > 1)
{
touchNum = Input.touchCount;
base.OnBeginDrag(eventData);
return;
}
base.OnDrag(eventData);
}
private float preX;
private float preY;
void Update()
{
if (Input.touchCount == 2)
{
Touch t1 = Input.GetTouch(0);
Touch t2 = Input.GetTouch(1);
Vector3 p1 = t1.position;
Vector3 p2 = t2.position;
float newX = Mathf.Abs(p1.x - p2.x);
float newY = Mathf.Abs(p1.y - p2.y);
if (t2.phase == TouchPhase.Began)
{
preX = newX;
preY = newY;
}
else if (t1.phase == TouchPhase.Moved && t2.phase == TouchPhase.Moved)
{
RectTransform rt = base.content;
float scale = (newX + newY - preX - preY) / (rt.rect.width * 0.9f) + rt.localScale.x;
if (scale > 1 && scale < 3)
{
rt.localScale = new Vector3(scale, scale, 0);
float maxX = base.content.rect.width * scale / 2 - base.viewport.rect.width / 2;
float minX = -maxX;
float maxY = base.content.rect.height * scale / 2 - base.viewport.rect.height / 2;
float minY = -maxY;
Vector3 pos = rt.position;
if (pos.x > maxX)
{
pos.x = maxX;
}
else if (pos.x < minX)
{
pos.x = minX;
}
if (pos.y > maxY)
{
pos.y = maxY;
}
else if (pos.y < minY)
{
pos.y = minY;
}
rt.position = pos;
}
}
preX = newX;
preY = newY;
}
}
}
}
思路是,多点触摸我们使用系统的Input来获得数值,在update函数中不断的检测触摸。 然后重写父类的OnBeginDrag和OnDrag,在多点触摸的时候不触发,单点拖动的时候在调用父类的函数。
多点触摸缩放,主要使用两个触摸点的变化量,来给地图内容区域做缩放,并且注意在边界的时候缩放需要同步检测最大最小编辑位置,放置出现地图区域小于屏幕的情况。