本文前篇 Unity透視相機下場景移動縮放-海島奇兵3
接著前篇繼續寫。
主要記錄以下內容:
邊界處理
計算視口寬高和查看視口工具 GeWenL/CameraView
-
Move操作優化:
- 觸摸點跟著手指Move
- 在邊界的移動,拆分移動的X和Y,忽略越界方向,僅保留合法的軸;
Zoom縮放操作優化:在邊界的向內放大(放大時,向內移動,不超出邊界)
邊界處理
用屏幕四個角來檢測四個邊界;
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);
}
計算視口寬高和查看視口工具
可以直觀的看到視口離邊界的距離
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)