Unity透視相機下地圖邊界處理-海島奇兵4

本文前篇 Unity透視相機下場景移動縮放-海島奇兵3
接著前篇繼續(xù)寫。

主要記錄以下內(nèi)容:

  1. 邊界處理

  2. 計算視口寬高和查看視口工具 GeWenL/CameraView

  3. Move操作優(yōu)化:

    1. 觸摸點跟著手指Move
    2. 在邊界的移動,拆分移動的X和Y,忽略越界方向,僅保留合法的軸;
  4. Zoom縮放操作優(yōu)化:在邊界的向內(nèi)放大(放大時,向內(nèi)移動,不超出邊界)

邊界處理

地圖邊界示意圖.png

用屏幕四個角來檢測四個邊界;
LeftOutBoundary:左邊是否越界;
RightOutBoundary:右邊是否越界;
DownOutBoundary:下邊是否越界;
UpOutBoundary:上邊是否越界;

為什么要用四個變量來記錄每個邊界是否越界呢?

用于Move和Zoom縮放在邊界時的操作優(yōu)化。
在已經(jīng)檢測越界的情況下,進(jìn)行Move(有邊界方向的分量)和Zoom縮放操作必定會判定為非法,從而舍棄掉這次的操作。這樣的體驗并不好。
詳細(xì)優(yōu)化操作見3 、4節(jié);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);
}

計算視口寬高和查看視口工具

可以直觀的看到視口離邊界的距離


繪制視口區(qū)域.png

視口script.png

GitHub完整CameraView.cs地址: GeWenL/CameraView
關(guān)鍵部分代碼 求距離相機distance的視口寬高:(這個計算會在Zoom縮放操作優(yōu)化中使用)

計算透視相機視口寬高示意圖.png
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操作優(yōu)化

  1. 觸摸點跟著手指Move
    相機X移動值 = 手指滑動的距離X / 屏幕寬度 * 相機視口寬度
    相機Z移動值 = 手指滑動的距離Y / 屏幕高度 * 相機視口高度
    這樣能保證,相機移動前后,手指在地圖上觸摸到的物體 保持不變。
    且相機在進(jìn)行縮放操作之后,移動手感一致。比如地圖縮小后,視口寬度、高度變大,移動距離按比例變大。

     _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;
    
  2. 在邊界的移動,拆分移動的X和Y,忽略越界方向,僅保留合法的軸;

    1. 當(dāng)右邊越界(RightOutBoundary),且玩家還向左滑動(_IncreMoveVector.x > 0)
      或者左邊越界(LeftOutBoundary),且玩家還向右滑動(_IncreMoveVector.x < 0)

    舍棄這次玩家滑動的X分量,上下滑動的值保留;這樣斜著滑動時,地圖還能上下滑動,不會完全舍棄。

     if ((_IncreMoveVector.x > 0 && RightOutBoundary) || (_IncreMoveVector.x < 0 && LeftOutBoundary))
     {
         _IncreMoveVector.x = 0;
     }
    
    1. 當(dāng)上邊越界(UpOutBoundary),且玩家還向下滑動(_IncreMoveVector.y > 0)
      或者下邊越界(DownOutBoundary),且玩家還向上滑動(_IncreMoveVector.y < 0)

    舍棄這次玩家滑動的上下分量,左右滑動的值保留;這樣斜著滑動時,地圖還能左右滑動,不會完全舍棄。

     if ((_IncreMoveVector.z > 0 && UpOutBoundary) || (_IncreMoveVector.z < 0 && DownOutBoundary))
     {
         _IncreMoveVector.z = 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縮放操作優(yōu)化

縮小是指地圖縮小,等同于相機拉遠(yuǎn),視口放大。

  1. 當(dāng)左右或上下 視口同時越界,則說明地圖已縮小到最小,不能再縮小。
    若此次操作是縮小,則return;
  2. 一邊越界,或2條相鄰的邊越界,則在縮小的同時,向內(nèi)移動相機。調(diào)用ZoomSetMove函數(shù);
    計算視口放大前后,視口寬高的差異;
ZoomSetMove.png
// 攝像機拉近拉遠(yuǎn) 
// deltaPinch > 0 為放大 - 由內(nèi)向外
// deltaPinch < 0為縮小  - 由外向內(nèi)
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;
    }
}

下一篇繼續(xù)優(yōu)化Zoom縮放-聚焦觸摸點

相關(guān)文章

  1. Unity實現(xiàn)類似【海島奇兵】探索場景概覽1
  2. Unity實現(xiàn)UI信息跟隨場景移動縮放-海島奇兵2
  3. Unity透視相機下場景移動縮放-海島奇兵3
  4. Unity Pinch手勢縮放(Zoom)聚焦-海島奇兵5
  5. Unity 海島奇兵資源收取效果(6)

參考

  1. Unity3D研究院之獲取攝像機的視口區(qū)域http://www.xuanyusong.com/archives/3036
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容