美文网首页Unity分享征服Unity3dunity3D技术分享
Unity透视相机下地图边界处理-海岛奇兵4

Unity透视相机下地图边界处理-海岛奇兵4

作者: 云木unity | 来源:发表于2017-11-08 15:05 被阅读185次

本文前篇 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

相关文章

网友评论

    本文标题:Unity透视相机下地图边界处理-海岛奇兵4

    本文链接:https://www.haomeiwen.com/subject/tkbxmxtx.html