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

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

主要記錄以下內容:

  1. 邊界處理

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

  3. Move操作優化:

    1. 觸摸點跟著手指Move
    2. 在邊界的移動,拆分移動的X和Y,忽略越界方向,僅保留合法的軸;
  4. 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縮放操作優化中使用)

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

  1. 觸摸點跟著手指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;
    
  2. 在邊界的移動,拆分移動的X和Y,忽略越界方向,僅保留合法的軸;

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

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

     if ((_IncreMoveVector.x > 0 && RightOutBoundary) || (_IncreMoveVector.x < 0 && LeftOutBoundary))
     {
         _IncreMoveVector.x = 0;
     }
    
    1. 當上邊越界(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縮放操作優化

縮小是指地圖縮小,等同于相機拉遠,視口放大。

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

下一篇繼續優化Zoom縮放-聚焦觸摸點

相關文章

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

參考

  1. Unity3D研究院之獲取攝像機的視口區域http://www.xuanyusong.com/archives/3036
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,716評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,746評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,991評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,706評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,036評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,203評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,725評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,451評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,677評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,161評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,857評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,266評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,606評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,407評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,643評論 2 380

推薦閱讀更多精彩內容