自学内容网 自学内容网

[Unity]在TileMap上控制Camera移动、缩放

环境:

  1. unity2021.3.14f1c1
  2. Camera类型Orthographic
  3. TileMap为XY方向摆放

功能:

  1. 单点触摸或鼠标操作移动Camera。
  2. 使用BoxCollider2D控制地图范围。
  3. 鼠标滚轮或多点触摸控制缩放。
  4. 缩放维持中心点在屏幕的固定位置。

代码:

using System;
using UnityEngine;

public class TileMapCameraController : MonoBehaviour
{
    [SerializeField]
    GameObject targetMap;
    [SerializeField]
    Camera targetCam;

    private bool enableControl = true;
    private float camInitSize = 20;
    private float camMinSize = 5;
    private float camMaxSize = 30;
    private float camSizeScrollWheelV = 10;

    private Vector2 firstTouchPos;
    private Vector2 cameraFirstPos;
    private bool isMoving = false;
    private bool isBegan = false;
    private bool isOnScale = false;
    private float camOriginZ = 0;
    private Vector3 mapMin;
    private Vector3 mapMax;
    private Vector3 camNewPos = new Vector3();

    // 双触点初始距离
    private float baseDis;
    // 双触点初始中心
    private Vector2 baseMidScreen;
    // 双触点初始中心
    private Vector3 baseMidWorld;
    // 双触点初始镜头size
    private float baseSize;
    private float baseScale = 1;

    void Awake()
    {
        Init();
    }

    private void Init()
    {
        if (targetMap)
        {
            var bounds = targetMap.GetComponent<BoxCollider2D>().bounds;
            mapMax = bounds.max;
            mapMin = bounds.min;
        }
        if (targetCam)
        {
            targetCam.orthographicSize = camInitSize;
            camOriginZ = targetCam.transform.position.z;
        }
    }

    public void Init(GameObject map, Camera cam)
    {
        targetMap = map;
        targetCam = cam;
        Init();
    }

    void Update()
    {
        if (!enableControl || !targetCam) return;
        // touch
        UpdateTouch();
        // mouse
        UpdateMouse();
    }

    private void UpdateTouch()
    {
        if (Input.touchCount == 1)
        {
            Touch t = Input.touches[0];
            if (t.phase == TouchPhase.Began)
            {
                isBegan = true;
                firstTouchPos = t.position;
                cameraFirstPos = targetCam.transform.position;
            }
            else if (t.phase == TouchPhase.Moved)
            {
                if (isBegan)
                {
                    isMoving = true;
                    MoveCam(firstTouchPos, t.position);
                }
            }
            else if (t.phase == TouchPhase.Ended || t.phase == TouchPhase.Canceled)
            {
                if (isBegan)
                {
                    isBegan = false;
                    isMoving = false;
                    MoveCam(firstTouchPos, t.position);
                }
            }
        }
        else if (Input.touchCount > 1)
        {
            isOnScale = true;
            Touch t1 = Input.touches[0];
            Touch t2 = Input.touches[1];
            if (t1.phase == TouchPhase.Canceled || t2.phase == TouchPhase.Canceled || t1.phase == TouchPhase.Ended || t2.phase == TouchPhase.Ended)
            {
                isOnScale = false;
                return;
            }
            bool isNew = t1.phase == TouchPhase.Began || t2.phase == TouchPhase.Began;

            if (isNew)//两个触控点中任意一个刚按下时
            {
                baseDis = Vector2.Distance(t1.position, t2.position);
                // 焦点
                baseMidScreen = (t1.position + t2.position) / 2;
                baseMidWorld = targetCam.ScreenToWorldPoint(baseMidScreen);
                baseSize = targetCam.orthographicSize;
            }
            else
            {
                isBegan = false;
                //两个触控点 任意一个移动时
                if (t1.phase == TouchPhase.Moved || t2.phase == TouchPhase.Moved)
                {
                    //当前的两个触控点的距离
                    float nowDis = Vector2.Distance(t1.position, t2.position);
                    //根据两个触控点的当前距离和初始距离的比值等比例改变缩放值
                    float size = baseDis / nowDis * baseSize;
                    float delta = (size - baseSize) * baseScale;
                    size = baseSize + delta;
                    SetCamSize(size);
                    Vector3 mid = targetCam.ScreenToWorldPoint(baseMidScreen);
                    Vector3 adjust = baseMidWorld - mid;
                    FocusTo(targetCam.transform.position + adjust);
                }
            }
        }
    }

    private void UpdateMouse()
    {
        if (isOnScale) return;

        float mouseCenter = Input.GetAxis("Mouse ScrollWheel");
        if (mouseCenter < 0)
        {
            // Debug.Log("缩小");
            SetCamSizeByDelta(-camSizeScrollWheelV * mouseCenter);
        }
        else if (mouseCenter > 0)
        {
            // Debug.Log("放大");
            SetCamSizeByDelta(-camSizeScrollWheelV * mouseCenter);
        }
        if (Input.GetMouseButtonDown(0))
        {
            isBegan = true;
            firstTouchPos = Input.mousePosition;
            cameraFirstPos = targetCam.transform.position;
        }
        if (Input.GetMouseButtonUp(0))
        {
            if (isBegan)
            {
                isBegan = false;
                isMoving = false;
                MoveCam(firstTouchPos, Input.mousePosition);
            }
        }
        if (Input.GetMouseButton(0))
        {
            if (isBegan)
            {
                MoveCam(firstTouchPos, Input.mousePosition);
            }
        }
    }

    private void SetCamSizeByDelta(float delta)
    {
        float srcSize = targetCam.orthographicSize;
        float size = srcSize + delta;
        SetCamSize(size);
    }

    private void SetCamSize(float size)
    {
        size = Math.Max(camMinSize, size);
        size = Math.Min(camMaxSize, size);
        targetCam.orthographicSize = size;
        CheckCam();
    }

    private void MoveCam(Vector2 fromScreenPos, Vector2 toScreenPos)
    {
        Vector2 delta = targetCam.ScreenToWorldPoint(fromScreenPos) - targetCam.ScreenToWorldPoint(toScreenPos);
        var newPos = cameraFirstPos + delta;
        camNewPos.x = newPos.x;
        camNewPos.y = newPos.y;
        camNewPos.z = camOriginZ;
        FocusTo(camNewPos);
    }

    private void FocusTo(Vector3 worldPos)
    {
        targetCam.transform.position = worldPos;
        CheckCam();
    }

    private void CheckCam()
    {
        var cameraHalfWidth = targetCam.orthographicSize * ((float)Screen.width / Screen.height);
        var cameraHalfHeight = targetCam.orthographicSize;
        //保证不会移除包围盒
        var pos = targetCam.transform.position;
        camNewPos.x = Mathf.Clamp(pos.x, mapMin.x + cameraHalfWidth, mapMax.x - cameraHalfWidth);
        camNewPos.y = Mathf.Clamp(pos.y, mapMin.y + cameraHalfHeight, mapMax.y - cameraHalfHeight);
        camNewPos.z = camOriginZ;
        targetCam.transform.position = camNewPos;
    }
}

参考:

  1. 【Unity触控】实现缩放和360度观察模型、单击、双击、滑动-阿里云开发者社区
  2. [Unity 3D]用鼠标滚轮实现镜头放大和缩放,并添加距离限制 - 伊凡晴天 - 博客园
  3. Unity 实现鼠标拖拽查看地图_鼠标控制地图移动 unity system-CSDN博客
  4. Unity3D 鼠标拖动地图实现_unity3d 鼠标移动ui界面地图-CSDN博客


原文地址:https://blog.csdn.net/GrimRaider/article/details/143919354

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!