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,在多点触摸的时候不触发,单点拖动的时候在调用父类的函数。
多点触摸缩放,主要使用两个触摸点的变化量,来给地图内容区域做缩放,并且注意在边界的时候缩放需要同步检测最大最小编辑位置,放置出现地图区域小于屏幕的情况。