Unity相机环绕,移动,缩放脚本

Unity相机环绕,移动,缩放脚本

环绕限制高低
缩放限制大小

unity结构示意图请添加图片描述

using DG.Tweening;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;

public class FXCameraControl : MonoBehaviour
{
    private const string MOUSESCROLLWHEEL = "Mouse ScrollWheel"; // 鼠标滚轮.
    private const string MOUSEX = "Mouse X";
    private const string MOUSEY = "Mouse Y";

    [Header("---------------基础---------------")]
    public bool isDrawGizmos = true;
    public Transform operatingTrn;  //操作点
    public Transform cameraTrn;     //相机
    public CamModel camModel = CamModel.WorldRoaming;
    [Header("-----世界漫游-----")]
    public float SJ_Zoom_Min = 2f;
    public float SJ_Zoom_Max = 30f;
    [Header("-----作业面视角-----")]
    public float ZYM_Zoom_Min = 6f;
    public float ZYM_Zoom_Max = 18f;
    public float ZYM_Radius = 5f; //作业面半径

    [Header("---------------缩放---------------")]
    public float currentZoomDistance;   //初始距离||移动时距离
    public float minZoomDistance = 2f;       //最小缩放距离
    public float maxZoomDistance = 3f;       //最大缩放距离
    public float zoomSpeed = 5f;             //缩放速度    

    [Header("---------------移动---------------")]
    public float moveSpeed = 0.3f;             //移动速度    

    [Header("---------------旋转---------------")]
    public float rotateSpeed = 1f;           //旋转速度
    public float minCamHeight = 0.1f;          //最小相机高度
    public float maxCamHeight = 25f;          //最大相机高度
    public float currentCamHeight;      //当前相机高度

    [Header("---------------private---------------")]
    [SerializeField]
    private int segments = 32;       //圆的线段数
    [SerializeField]
    private float angle;        //当前角度
    [SerializeField]
    private float camRadius;       //圆半径
    [SerializeField]
    private Vector3 operatingResetPos;   //操作点重置位置
    [SerializeField]
    private Vector3 cameraResetPos;   //相机重置位置
    [SerializeField]
    private bool isResetPosEnd = true; //是否重置结束

    private void Start()
    {
        Init();
    }

    private void LateUpdate()
    {
        //实时更新用到的参数,同步操作
        UpdateParameter();

        if (isResetPosEnd)
        {
            UpdateZoom();
            UpdateMove();
            UpdateRotate();
        }

        LookAtOperatingTrn();
        DebugDrawLine();
    }

    private void OnDrawGizmos()
    {
        if (!isDrawGizmos) return;
        DebugDrawCircle(segments, operatingTrn.position, camRadius, currentCamHeight);
        DebugDrawCircle(segments, operatingTrn.position, ZYM_Radius, operatingTrn.position.y);
    }

    private void Init()
    {
        ModelInit();
        //初始距离
        currentZoomDistance = Vector3.Distance(operatingTrn.position, cameraTrn.position);
        //初始半径
        camRadius = Vector2.Distance(new Vector2(operatingTrn.position.x, operatingTrn.position.z), new Vector2(cameraTrn.position.x, cameraTrn.position.z));
        //初始高度
        currentCamHeight = cameraTrn.position.y;
        //重置角度
        AngleRefersh();
        //获取相机和操作点重置位置
        operatingResetPos = operatingTrn.position;
        cameraResetPos = cameraTrn.position;
    }

    private void ModelInit()
    {
        switch (camModel)
        {
            case CamModel.WorldRoaming:
                //世界漫游
                minZoomDistance = SJ_Zoom_Min;
                maxZoomDistance = SJ_Zoom_Max;
                break;
            case CamModel.WorkingSurface:
                //作业面
                operatingTrn.position = Vector3.zero;
                minZoomDistance = ZYM_Zoom_Min;
                maxZoomDistance = ZYM_Zoom_Max;
                break;
            default:
                break;
        }
    }

    private void AngleRefersh()
    {
        // 计算当前相机位置在物体的水平面上的投影点
        Vector3 projectPos = new Vector3(cameraTrn.position.x, operatingTrn.position.y, cameraTrn.position.z);

        Vector3 v1 = new Vector3(cameraTrn.position.x, 0, cameraTrn.position.z) - new Vector3(operatingTrn.position.x, 0, operatingTrn.position.z);
        // 计算当前相机位置相对于物体中心的水平旋转角度
        float horizontalAngle = Vector3.Angle(Vector3.right, projectPos - operatingTrn.position);

        if (cameraTrn.position.z <= 0)
        {
            angle = 360 - horizontalAngle;
        }
        else
        {
            angle = horizontalAngle;
        }
    }

    public void ChangeCamModel(CamModel _camModel)
    {
        camModel = _camModel;
        Debug.Log("当前相机模式:" + camModel);
        ModelInit();
        UpdateParameter();
        Rotate();
        Zoom();
    }

    private void UpdateParameter()
    {
        camRadius = Vector2.Distance(new Vector2(operatingTrn.position.x, operatingTrn.position.z), new Vector2(cameraTrn.position.x, cameraTrn.position.z));
        currentCamHeight = Mathf.Clamp(cameraTrn.position.y, minCamHeight, maxCamHeight);
        currentZoomDistance = Vector3.Distance(operatingTrn.position, cameraTrn.position);
    }

    private void UpdateZoom()
    {
        if (Input.mouseScrollDelta.y != 0)
        {
            Zoom();
        }
    }

    private void UpdateMove()
    {
        if (camModel == CamModel.WorkingSurface) return;

        if (Input.GetMouseButton(0))
        {
            Move();
        }
    }

    private void UpdateRotate()
    {
        if (Input.GetMouseButton(1))
        {
            Rotate();
            //防止在旋转视角时候,使得相机缩放超出最大最小距离
            Zoom();
        }
    }

    private void Zoom()
    {
        //鼠标滑轮值
        float scrollWheelValue = Input.GetAxis(MOUSESCROLLWHEEL);

        //更新当前距离
        currentZoomDistance = currentZoomDistance - (scrollWheelValue * zoomSpeed);

        // 计算A点到B点的向量
        Vector3 vectorAB = cameraTrn.position - operatingTrn.position;

        // 将向量AB归一化
        Vector3 normalizedVectorAB = vectorAB.normalized;

        //限制距离
        currentZoomDistance = Mathf.Clamp(currentZoomDistance, minZoomDistance, maxZoomDistance);

        // 计算新的A点到B点的距离
        float newDistance = Vector3.Distance(operatingTrn.position, cameraTrn.position) - currentZoomDistance;

        // 计算新的A点的位置
        Vector3 newpointA = cameraTrn.position - normalizedVectorAB * newDistance;

        //限制高度
        currentCamHeight = Mathf.Clamp(newpointA.y, minCamHeight, maxCamHeight);

        //更新位置
        cameraTrn.transform.position = new Vector3(newpointA.x, currentCamHeight, newpointA.z);
    }

    private void Move()
    {
        float deltaX = Input.GetAxis(MOUSEX) * moveSpeed;
        float deltaY = Input.GetAxis(MOUSEY) * moveSpeed;
        Vector3 newPosX = -deltaX * cameraTrn.right;
        Vector3 newPosY = -deltaY * cameraTrn.forward;
        operatingTrn.position += new Vector3(newPosX.x, 0, newPosX.z);
        operatingTrn.position += new Vector3(newPosY.x, 0, newPosY.z);
    }

    private void Rotate()
    {
        float deltaX = Input.GetAxis(MOUSEX) * rotateSpeed;
        float deltaY = Input.GetAxis(MOUSEY) * rotateSpeed;

        currentCamHeight = Mathf.Clamp(cameraTrn.position.y - deltaY, minCamHeight, maxCamHeight);

        angle -= deltaX;
        while (angle > 360.0f)
        {
            angle -= 360.0f;
        }

        float x = operatingTrn.position.x + camRadius * Mathf.Cos(angle * Mathf.Deg2Rad);
        float z = operatingTrn.position.z + camRadius * Mathf.Sin(angle * Mathf.Deg2Rad);
        float y = currentCamHeight;
        cameraTrn.position = new Vector3(x, y, z);
    }

    private void LookAtOperatingTrn()
    {
        switch (camModel)
        {
            case CamModel.WorldRoaming:

                cameraTrn.LookAt(operatingTrn);

                break;
            case CamModel.WorkingSurface:

                Vector3 targetPos = GetWorkingSurfaceLookArPos();
                cameraTrn.LookAt(targetPos);

                break;
            default:
                break;
        }

    }

    public void CameraResetPos()
    {
        isResetPosEnd = false;
        operatingTrn.DOMove(operatingResetPos, 1f);
        cameraTrn.DOMove(cameraResetPos, 1f).onComplete += () =>
        {
            isResetPosEnd = true;
            AngleRefersh();
        };
    }

    private Vector3 GetWorkingSurfaceLookArPos()
    {
        float distance = 60;

        Vector2 center = new Vector2(operatingTrn.position.x, operatingTrn.position.z);

        Vector2 pointA = new Vector2(cameraTrn.position.x, cameraTrn.position.z);

        Vector3 pointB_V3 = (new Vector3(operatingTrn.position.x, 0, operatingTrn.position.z) - new Vector3(cameraTrn.position.x, 0, cameraTrn.position.z)).normalized * distance;

        Vector2 pointB = new Vector2(pointB_V3.x, pointB_V3.z); 

        Vector3 intersectionPos = GetIntersectionPos(pointA, pointB, center, ZYM_Radius);

        if (isDrawGizmos)
        {
            Debug.DrawLine(new Vector3(pointA.x, 0, pointA.y), pointB_V3, Color.red);
            Debug.DrawLine(cameraTrn.position, intersectionPos, Color.blue);
            Debug.DrawLine(cameraTrn.position, new Vector3(pointA.x, 0, pointA.y), Color.red);
        }

        return intersectionPos;
    }

    private Vector3 GetIntersectionPos(Vector2 pointA, Vector2 pointB, Vector2 center, float radius)
    {
        Vector2 direction = pointB - pointA;
        float a = Vector2.Dot(direction, direction);
        float b = 2 * Vector2.Dot(direction, pointA - center);
        float c = Vector2.Dot(pointA - center, pointA - center) - radius * radius;
        float discriminant = b * b - 4 * a * c;
        Vector2 intersection1;
        Vector2 intersection2;
        if (discriminant >= 0)
        {
            float t1 = (-b + Mathf.Sqrt(discriminant)) / (2 * a);
            float t2 = (-b - Mathf.Sqrt(discriminant)) / (2 * a);
            intersection1 = pointA + t1 * direction;
            intersection2 = pointA + t2 * direction;
            //Debug.Log("Intersection 1: " + intersection1);
            //Debug.Log("Intersection 2: " + intersection2);
            return new Vector3(intersection1.x, 0, intersection1.y);
        }
        else
        {
            Debug.Log("没有交点");
        }
        return Vector3.zero;
    }

    void OnGUI()
    {
        if (GUI.Button(new Rect(10, 600, 200, 60), "切换相机模式"))
        {
            ChangeCamModel(camModel == CamModel.WorkingSurface ? CamModel.WorldRoaming : CamModel.WorkingSurface);
        }
        //if (GUI.Button(new Rect(10, 100, 200, 60), "重置位置"))
        //{
        //    CameraResetPos();
        //}
    }

    private void DebugDrawLine()
    {
        Debug.DrawLine(operatingTrn.position, cameraTrn.position, Color.green);

        //Debug.DrawLine(Vector3.zero, Vector3.right * 30, Color.blue);
    }

    public void DebugDrawCircle(int _segments, Vector3 _center, float _radius, float _height = 0)
    {
        _center = new Vector3(_center.x, _height, _center.z);
        Gizmos.color = Color.yellow;
        float anglePerSegment = 360.0f / _segments;
        Vector3 start = _center + _radius * Vector3.right;
        Vector3 end = start;
        for (int i = 0; i < _segments; i++)
        {
            end = _center + Quaternion.Euler(0.0f, anglePerSegment, 0.0f) * (end - _center).normalized * _radius;
            Gizmos.DrawLine(start, end);
            start = end;
        }
        Gizmos.DrawLine(end, _center + _radius * Vector3.right);
    }

}
public enum CamModel
{
    /// <summary> 世界漫游 </summary>
    WorldRoaming,
    /// <summary> 作业面 </summary>
    WorkingSurface,
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在Unity中,要在运行情况下移动相机,我们可以编写一个相机移动脚本。 首先,我们需要在场景中创建一个相机对象,并将此脚本添加到相机对象上。接下来,在脚本中声明一些私有变量,用于控制相机移动。 我们可以使用Input.GetAxis函数来获取用户输入的移动方向。例如,我们可以使用"Horizontal"和"Vertical"来获取水平和垂直方向上的输入。 在Update函数中,我们可以使用上述输入值来计算相机的目标位置。例如,我们可以使用transform.Translate函数来移动相机的位置。我们可以将相机的位置设置为当前位置与移动方向的乘积,以实现相机移动。 为了使相机平滑移动,我们可以使用Lerp函数来插值相机的位置。这需要使用一个目标位置和一个插值系数,在每帧更新时,将当前位置移向目标位置。 在脚本中,还可以添加一些逻辑,例如限制相机移动范围,或者添加其他控制逻辑。 最后,我们需要将此脚本附加到相机对象上,并在Unity中启动游戏进行测试。在游戏运行情况下,我们可以通过输入控制相机移动,并观察相机的实时位置变化。 通过编写和调试相机移动脚本,我们可以实现在Unity中运行情况下移动相机的功能。 ### 回答2: Unity运行时移动相机有多种方法,可以使用脚本来实现。以下是一个简单的相机移动脚本示例,可以通过键盘输入来控制相机移动。 首先,在Unity中创建一个新的C#脚本,然后将其命名为"CameraMovement"。 在脚本中,我们需要声明一些变量,用于控制相机移动速度和灵敏度。 ```c# using System.Collections; using System.Collections.Generic; using UnityEngine; public class CameraMovement : MonoBehaviour { public float movementSpeed = 5f; public float rotationSpeed = 5f; // Update is called once per frame void Update() { // 相机的前后移动 float translation = Input.GetAxis("Vertical") * movementSpeed; translation *= Time.deltaTime; transform.Translate(0, 0, translation); // 相机的左右旋转 float rotation = Input.GetAxis("Horizontal") * rotationSpeed; rotation *= Time.deltaTime; transform.Rotate(0, rotation, 0); } } ``` 在脚本中的Update函数中,我们根据用户输入的按键来移动相机。通过使用Input.GetAxis函数获取水平方向和垂直方向的输入值,然后乘以移动速度和灵敏度,再乘以Time.deltaTime,以确保移动的平滑性。 上面的脚本将通过键盘的上下箭头键控制相机的前进后退,并使用键盘的左右箭头键控制相机的左右旋转。 要使该脚本生效,将其附加到Unity场景中的相机对象上。然后,当您在Unity编辑器中点击“播放”按钮时,您就可以使用键盘来移动和旋转相机了。 这只是一个基本的相机移动脚本示例,您可以根据需要进行修改和扩展,以实现更复杂的相机移动效果。 ### 回答3: Unity是一款强大的游戏引擎,可以轻松创建各种类型的游戏。在Unity中,我们可以通过编写脚本控制相机移动。 在Unity移动相机有很多种方法,其中一种常见的方法是使用脚本控制相机的位置和旋转。下面是一个简单的示例脚本: ```c# using System.Collections; using System.Collections.Generic; using UnityEngine; public class CameraMovement : MonoBehaviour { public float speed = 5f; // 相机移动速度 void Update() { // 获取键盘输入 float moveHorizontal = Input.GetAxis("Horizontal"); float moveVertical = Input.GetAxis("Vertical"); // 根据输入移动相机的位置 Vector3 movement = new Vector3(moveHorizontal, 0f, moveVertical) * speed * Time.deltaTime; transform.position += movement; // 控制相机旋转 if (Input.GetKey(KeyCode.Q)) { transform.Rotate(Vector3.up, -speed * Time.deltaTime); } else if (Input.GetKey(KeyCode.E)) { transform.Rotate(Vector3.up, speed * Time.deltaTime); } } } ``` 上述代码中,我们首先定义了一个`speed`变量来控制相机移动速度。在`Update()`函数中,我们使用`Input.GetAxis()`函数来获取键盘的输入值,然后根据输入移动相机的位置,其中`Time.deltaTime`是一个时间因子,可以保证在不同帧率下相机移动的速度相同。 此外,我们还可以使用`Input.GetKey()`函数来检测按键,并使用`Transform.Rotate()`函数来控制相机的旋转。 通过编写类似的脚本,我们就可以在Unity的运行环境中移动相机,实现自定义相机控制功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值