Unity的滑动控制相机跟随和第三人称视角三

Unity的相机跟随和第三人称视角三

第三人称相机优化

Unity第三人称相机视角一
Unity第三人称相机视角二

介绍

之前相机视角讲过了两篇文章了,但是都是自动旋转视角,今天来了新需求,自动视角的时候,人没办法看全场上所有的景象,所以可以自己控制相机的视口方向,说白了就是做一个拖拽事件,再根据拖动的大小来控制相机视口旋转量,这样就完成了相机的可控视口旋转。

讲解

我上面的那个Gif可以看到,我创建了一个有拖动事件的UI,开始拖拽,拖拽中,结束拖拽。

在开始的时候我们采集他的开始拖拽点,然后在拖拽中进行插值运算计算进行镜头的左右旋转。

这个Gif里面我代码也加入了原来的人物中心点的位移,比如偏左一点或者偏右一点又或者是在正中心,这里我所使用的是Dotween这个插件,这里按键Q是切换镜头,ERT是镜头左侧,右侧,正中心的设置按键。

拖动事件

这里创建了一个UI来继承拖拽事件,可以把这个UI的透明通道调整到看不到的程度,我这里是为了大家方便看到我没有设置为0。

MoveTouch.cs

csharp 复制代码
using UnityEngine;
using UnityEngine.EventSystems;

public class MoveTouchTest : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    /// <summary>
    /// 跟随相机
    /// </summary>
    public FollowCameraTest followCameraTest;
     
    /// <summary>
    /// 是否在拖拽中
    /// </summary>
    public bool IsDrag = false;

    /// <summary>
    /// 开始位置
    /// </summary>
    private float startPosX;

    /// <summary>
    /// 旋转的角度
    /// </summary>
    public float angle = 1;

    public void OnBeginDrag(PointerEventData eventData)
    {
        IsDrag = true;
        startPosX = eventData.position.x;
    }

    public void OnDrag(PointerEventData eventData)
    {
        if (!followCameraTest.IsHasBall) return;

        if (!IsDrag) return;
 
        followCameraTest.transform.localEulerAngles += new Vector3(0, (eventData.position.x - startPosX) * angle, 0);

        startPosX = eventData.position.x;
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        IsDrag = false;
    }
    private void OnEnable()
    {
        IsDrag = false;
    }

    private void OnDisable()
    {
        IsDrag = false;
    }
}

相机逻辑

我用电脑测试的所以下面代码加了个鼠标滚轮控制镜头的旋转。

FollowCameraTest .cs

csharp 复制代码
using DG.Tweening;
using Unity.VisualScripting;
using UnityEngine;

public class FollowCameraTest : MonoBehaviour
{
    public Transform target; // 要跟随的目标对象
    public Transform football; // 其次要跟随的目标
    public Vector3 camPosOffset = new Vector3(0, 1.5f, -5);   // 相机与目标之间的距离偏移量
    public Vector3 camEulerOffset = new Vector3(6, 0, 0);   // 相机与目标之间的距离偏移量
    public float smoothSpeed = 0.05f; // 相机跟随平滑度
    public float rotateSpeed = 0.08f; // 相机旋转平滑度
    public float fov = 45;
    public bool IsHasBall = true;

    public Camera m_cam;
    public float moveTime = 1f;

    public float angle = 5;

    private void Start()
    {
        m_cam.transform.localPosition = camPosOffset;
        m_cam.transform.localEulerAngles = camEulerOffset;
        transform.position = target.transform.position;
        m_cam.fieldOfView = fov;
    }


    public void LateUpdate()
    {
        if (target == null) return;
        if (Input.GetKeyDown(KeyCode.Q)) 
        {
            IsHasBall = !IsHasBall;
        }
        if (Input.GetKeyDown(KeyCode.E)) 
        {
            if (m_cam != null) m_cam.transform.DOLocalMoveX(-1, moveTime);
        }
        if (Input.GetKeyDown(KeyCode.R))
        {
            if (m_cam != null) m_cam.transform.DOLocalMoveX(1, moveTime);
        }
        if (Input.GetKeyDown(KeyCode.T))
        {
            if (m_cam != null) m_cam.transform.DOLocalMoveX(0, moveTime);
        }
        //相机缓动过程
        transform.position = Vector3.Lerp(transform.position, target.transform.position, smoothSpeed);

        

        if (IsHasBall)
        {
        	//这里我用的电脑方便测试加了一个滚轮的方式去旋转镜头,需要可以打开 不需要就不用管
        	//float mouseWheel = Input.GetAxis("Mouse ScrollWheel");
            //transform.localEulerAngles += mouseWheel * angle * Vector3.up;
        }
        else
        {
            Vector3 tar = ((target.position + football.position) * 0.5f - target.transform.position).normalized;
            tar.y = 0;
            transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(tar), rotateSpeed);
        }
    }
}

人物移动逻辑

RoleCtrlTest.cs

csharp 复制代码
using UnityEngine;

public class RoleCtrlTest : MonoBehaviour
{
    public float moveSpeed = 5f; // 人物移动速度

    public float rotateSpeed = 5f;

    public FollowCameraTest followCamera;

    void Update()
    {
        Vector3 moveDir = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
        moveDir = RotateRound(moveDir, Vector3.zero, Vector3.up, followCamera.transform.localEulerAngles.y);

        if (followCamera.IsHasBall)
        {
            transform.position += moveDir * moveSpeed * Time.deltaTime;

            transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(moveDir), rotateSpeed);
        }
        else
        {
            if (moveDir == Vector3.zero) return;
            transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(moveDir), rotateSpeed);
            transform.position += transform.forward * moveSpeed * Time.deltaTime;
        }
    }

    protected Vector3 RotateRound(Vector3 position, Vector3 center, Vector3 axis, float angle)
    {
        Vector3 point = Quaternion.AngleAxis(angle, axis) * (position - center);
        Vector3 resultVec3 = center + point;
        return resultVec3;
    }
}

总结

对比之前自动旋转的,这个版我觉着会更舒服一些,因为这个版的镜头更加可控制一些,但是这个也会让你操作变得复杂,无疑增加了一种操作负担。

相关推荐
℡枫叶℡15 小时前
Unity - 图集大小与内存占用
unity·图集内存
_ZHOURUI_H_15 小时前
Unity MyFramework 用法说明(二十五):使用 AtlasManager 统一管理图集与 Sprite 引用
ui·unity·游戏引擎·unity3d·游戏开发
新手unity自用笔记16 小时前
Unity网络基础_2
unity·游戏引擎
音视频牛哥18 小时前
从数字孪生到机器人操控:Android Unity3D下RTMP/RTSP多路低延迟播放实践
android·unity·音视频·unity rtsp播放器·unity rtmp播放器·rtsp player·rtmp player
派葛穆19 小时前
Unity-原生 JsonUtility 实现 JSON 与TMP UI 交互实战
unity
chenzhou__20 小时前
独立游戏开发日志 ①:从信号博弈到涂色对战——一次玩法重构始
笔记·后端·学习·unity·go·独立游戏
五仁烧饼20 小时前
Unity Addressables 资源依赖治理:规则约束、自动修复与全链路防护
java·unity·游戏引擎
qq_370773091 天前
Unity游戏xLua逆向实战:从SO版本识别到Lua脚本热替换全链路
游戏·unity·lua
mxwin2 天前
Unity Shader 水面 Shader 教程 从 Gerstner 波浪到屏幕折射、焦散、泡沫的完整实现
unity·游戏引擎
噗噗夹的TA之旅2 天前
Shader 学习 21:自定义 Render Feature
学习·游戏·unity·c#·游戏引擎·图形渲染