本文前篇 Unity透视相机下场景移动缩放-海岛奇兵3
接着前篇继续写。
主要记录以下内容:
-
边界处理
-
计算视口宽高和查看视口工具 GeWenL/CameraView
-
Move操作优化:
- 触摸点跟着手指Move
- 在边界的移动,拆分移动的X和Y,忽略越界方向,仅保留合法的轴;
-
Zoom缩放操作优化:在边界的向内放大(放大时,向内移动,不超出边界)
边界处理
地图边界示意图.png用屏幕四个角来检测四个边界;
LeftOutBoundary:左边是否越界;
RightOutBoundary:右边是否越界;
DownOutBoundary:下边是否越界;
UpOutBoundary:上边是否越界;
为什么要用四个变量来记录每个边界是否越界呢?
用于Move和Zoom缩放在边界时的操作优化。
在已经检测越界的情况下,进行Move(有边界方向的分量)和Zoom缩放操作必定会判定为非法,从而舍弃掉这次的操作。这样的体验并不好。
详细优化操作见3 、4节;Move、Zoom操作初篇见 Unity透视相机下场景移动缩放-海岛奇兵3
private List<Vector2> ScreenCornerPosList = new List<Vector2> { Vector2.zero
, new Vector2(0, Screen.height)
, new Vector2(Screen.width, Screen.height)
, new Vector2(Screen.width, 0) };
// 检测边界 是否合法 true合法 false越界非法
private bool CheckBoundary()
{
LeftOutBoundary = false;
RightOutBoundary = false;
DownOutBoundary = false;
UpOutBoundary = false;
if (ScreenCornerPosList != null)
{
foreach (var screenPos in ScreenCornerPosList)
{
Ray ray = _cameraMain.ScreenPointToRay(screenPos);
var hits = Physics.RaycastAll(ray, 1000);
if (hits == null || hits.Length <= 0)
{
continue;
}
for (var i = 0; i < hits.Length; ++i)
{
var go = hits[i].collider.gameObject;
if (go.layer == Const.Lay_MapBorder)
{
switch (go.name)
{
case "left":
LeftOutBoundary = true;
break;
case "right":
RightOutBoundary = true;
break;
case "up":
UpOutBoundary = true;
break;
case "down":
DownOutBoundary = true;
break;
default:
break;
}
}
}
}
}
return !(LeftOutBoundary || RightOutBoundary || DownOutBoundary || UpOutBoundary);
}
计算视口宽高和查看视口工具
可以直观的看到视口离边界的距离
绘制视口区域.png
视口script.png
GitHub完整CameraView.cs地址: GeWenL/CameraView
关键部分代码 求距离相机distance的视口宽高:(这个计算会在Zoom缩放操作优化中使用)
Vector3[] GetCorners(float distance)
{
...
float halfFOV = (theCamera.fieldOfView * 0.5f) * Mathf.Deg2Rad;
float aspect = theCamera.aspect;
float height = distance * Mathf.Tan(halfFOV);
float width = height * aspect;
...
}
Move操作优化
-
触摸点跟着手指Move
相机X移动值 = 手指滑动的距离X / 屏幕宽度 * 相机视口宽度
相机Z移动值 = 手指滑动的距离Y / 屏幕高度 * 相机视口高度
这样能保证,相机移动前后,手指在地图上触摸到的物体 保持不变。
且相机在进行缩放操作之后,移动手感一致。比如地图缩小后,视口宽度、高度变大,移动距离按比例变大。_halfFOVTan = Mathf.Tan((_OriginalFov * 0.5f) * Mathf.Deg2Rad); float hight = GetCameraDis() * _halfFOVTan * 2;// 参照图片(计算透视相机视口宽高示意图) float width = hight * _cameraMain.aspect; _IncreMoveVector.x = -swipeVector.x / Screen.width * width; _IncreMoveVector.z = -swipeVector.y / Screen.height * hight;
-
在边界的移动,拆分移动的X和Y,忽略越界方向,仅保留合法的轴;
- 当右边越界(RightOutBoundary),且玩家还向左滑动(_IncreMoveVector.x > 0)
或者左边越界(LeftOutBoundary),且玩家还向右滑动(_IncreMoveVector.x < 0)
舍弃这次玩家滑动的X分量,上下滑动的值保留;这样斜着滑动时,地图还能上下滑动,不会完全舍弃。
if ((_IncreMoveVector.x > 0 && RightOutBoundary) || (_IncreMoveVector.x < 0 && LeftOutBoundary)) { _IncreMoveVector.x = 0; }
- 当上边越界(UpOutBoundary),且玩家还向下滑动(_IncreMoveVector.y > 0)
或者下边越界(DownOutBoundary),且玩家还向上滑动(_IncreMoveVector.y < 0)
舍弃这次玩家滑动的上下分量,左右滑动的值保留;这样斜着滑动时,地图还能左右滑动,不会完全舍弃。
if ((_IncreMoveVector.z > 0 && UpOutBoundary) || (_IncreMoveVector.z < 0 && DownOutBoundary)) { _IncreMoveVector.z = 0; }
- 当右边越界(RightOutBoundary),且玩家还向左滑动(_IncreMoveVector.x > 0)
Move操作代码如下:
// 移动摄像机
// swipeVector.x > 0 向右 swipeVector.x < 0 向左
// swipeVector.y > 0 向上 swipeVector.y < 0 向下
private void Move(Vector2 swipeVector)
{
if (swipeVector == Vector2.zero)
{
return;
}
float hight = GetCameraDis() * _halfFOVTan * 2;
float width = hight * _cameraMain.aspect;
_IncreMoveVector.x = -swipeVector.x / Screen.width * width;
_IncreMoveVector.z = -swipeVector.y / Screen.height * hight;
if ((_IncreMoveVector.x > 0 && RightOutBoundary) || (_IncreMoveVector.x < 0 && LeftOutBoundary))
{
_IncreMoveVector.x = 0;
}
if ((_IncreMoveVector.z > 0 && UpOutBoundary) || (_IncreMoveVector.z < 0 && DownOutBoundary))
{
_IncreMoveVector.z = 0;
}
}
Zoom缩放操作优化
缩小是指地图缩小,等同于相机拉远,视口放大。
- 当左右或上下 视口同时越界,则说明地图已缩小到最小,不能再缩小。
若此次操作是缩小,则return; - 一边越界,或2条相邻的边越界,则在缩小的同时,向内移动相机。调用ZoomSetMove函数;
计算视口放大前后,视口宽高的差异;
// 摄像机拉近拉远
// deltaPinch > 0 为放大 - 由内向外
// deltaPinch < 0为缩小 - 由外向内
private void Zoom(float deltaPinch)
{
//Debug.Log("Zoom deltaPinch=" + deltaPinch);
if (deltaPinch < 0 && ((RightOutBoundary && LeftOutBoundary) || (UpOutBoundary && DownOutBoundary)))
{
_IncreCameraDis = 0;
return;
}
...
if (_IncreCameraDis > 0 && (RightOutBoundary || LeftOutBoundary || UpOutBoundary || DownOutBoundary))
{
ZoomSetMove();
}
}
private void ZoomSetMove()
{
_IncreMoveVector = Vector3.zero;
float aspect = _cameraMain.aspect;
float halfDiff = _IncreCameraDis * _halfFOVTan * 1.1f;
if (LeftOutBoundary)
{
_IncreMoveVector.x = halfDiff * aspect;
}
if (RightOutBoundary)
{
_IncreMoveVector.x = -halfDiff * aspect;
}
if (UpOutBoundary)
{
_IncreMoveVector.z = -halfDiff;
}
if (DownOutBoundary)
{
_IncreMoveVector.z = halfDiff;
}
}
相关文章
- Unity实现类似【海岛奇兵】探索场景概览1
- Unity实现UI信息跟随场景移动缩放-海岛奇兵2
- Unity透视相机下场景移动缩放-海岛奇兵3
- Unity Pinch手势缩放(Zoom)聚焦-海岛奇兵5
- Unity 海岛奇兵资源收取效果(6)
网友评论