【unity实战】Cinemachine虚拟相机实战,使用InputSystem+Cinemachine+CharacterController复刻各种主流游戏的相机控制

效果


前言

这里主要是探讨如何使用InputSystem+Cinemachine+CharacterController复刻各种主流游戏的相机控制,我们主要专注Cinemachine实战效果,所以并不会深入讨论Cinemachine和CharacterController比较细节的参数介绍。

注意:前面为了测试方便,我还是先用的旧的输入系统代替InputSystem

如果对Cinemachine虚拟相机的使用不了解的,可以查看这篇文章:
【推荐100个unity插件之10】Unity最全的最详细的Cinemachine(虚拟相机系统)介绍,详细案例讲解,快速上手
如果对CharacterController的使用不了解的,可以查看这两篇文章:
【unity小技巧】unity最完美的CharacterController 3d角色控制器,实现移动、跳跃、下蹲、奔跑、上下坡、物理碰撞效果,复制粘贴即用
【unity实战】Cinemachine虚拟相机+Character
Controller实现俯视角、第三人称角色控制,复制粘贴即用

Cinemachine虚拟相机模块参数解释

Follow跟随策略

在这里插入图片描述

跟随策略说明
Do Nothing不移动虚拟相机
Framing Transposer跟随目标移动,并在屏幕空间保持相机和跟随目标的相对位置。
Hard Lock to Target虚拟相机和跟随目标使用相同位置。
Orbital Transposer相机和跟随目标的相对位置是可变的,还能接收用户的输入。常见于玩家控制的相机。
Tracked Dolly相机沿着预先设置的轨道移动。
Transposer跟随目标移动,并在世界空间保持相机和跟随目标的相对位置固定。

LookAt瞄准策略

在这里插入图片描述

瞄准策略说明
Composer将目标保持在相机镜头内,可以设置多种约束
Group Composer将多个目标保持在相机镜头内
Hard Look At将Look At目标固定在镜头中心的位置
POV根据用户的输入旋转相机
Same As Follow Target将相机的旋转和跟随目标的旋转同步

一、2d虚拟相机

参考:【制作100个unity游戏之26】unity2d横版卷轴动作类游戏

新增相机

新增2d虚拟相机
在这里插入图片描述
在这里插入图片描述
可以添加pixel perfect.相机,他能帮助,在我们的像素旋转或产生畸变的时候,不会出现像素扭曲,保持我们的单位像素
在这里插入图片描述
区域限制
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

效果

在这里插入图片描述

二、第三人称RPG

案例

最经典的像《原神》和最近很火的《黑神话悟空》
在这里插入图片描述
在这里插入图片描述

特点

相机视角旋转不影响人物旋转,人物移动方向以相机视角方向为主

主角控制代码

using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    private CharacterController characterController;

    [Header("输入")]
    float horizontal;
    float vertical;
    Vector3 direction;//输入创建移动方向向量
    
    [Header("移动")]
    public float speed = 5f; // 玩家移动的速度
    Vector3 moveDirection;//角色的移动方向

    [Header("旋转")]
    public float turnSpeed = 10f; // 角色转向速度
    Camera mainCamera;

    [Header("跳跃")]
    public float JumpHeight = 3f;//跳跃高度
    public float Gravity = -39.8f;//重力
    private Vector3 velocityGravity; // 重力速度

    [Header("地面检测")]
    public bool isGround;

    void Start()
    {
        characterController = GetComponent<CharacterController>(); // 初始化角色控制器
        mainCamera = Camera.main;
    }

    void Update()
    {
        SetPlayerMove();

        SetPlayerRotation();

        SetPlayerGravity();

        SetPlayerJump();
    }

    //处理角色移动
    void SetPlayerMove(){
        // 获取输入
        horizontal = Input.GetAxis("Horizontal");
        vertical = Input.GetAxis("Vertical");
        // 根据输入创建移动方向向量
        direction = new Vector3(horizontal, 0, vertical);

        // 计算相机的前方和右方方向
        Vector3 cameraForward = mainCamera.transform.forward;
        Vector3 cameraRight = mainCamera.transform.right;
        // 将相机的前方方向的 y 分量设置为 0,这样角色只会在水平面上移动
        cameraForward.y = 0;
        
        moveDirection = cameraForward * vertical + cameraRight * horizontal;// 计算角色的移动方向
        // 移动角色
        characterController.Move(moveDirection.normalized * speed * Time.deltaTime);
    }

    // 处理角色旋转
    void SetPlayerRotation()
    {
        if (direction != Vector3.zero)
        {
            // 计算目标旋转四元数
            Quaternion targetRotation = Quaternion.LookRotation(moveDirection, transform.up);// 计算旋转的四元数
            // 平滑过渡到目标旋转
            transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, turnSpeed * Time.deltaTime);
        }
    }

    // 处理角色跳跃
    void SetPlayerJump()
    {
        // 跳跃处理
        if (isGround && Input.GetButtonDown("Jump"))
        {
            velocityGravity.y = Mathf.Sqrt(JumpHeight * -2 * Gravity);
        }
    }

    // 处理角色重力
    void SetPlayerGravity()
    {
        // 应用重力
        characterController.Move(velocityGravity * Time.deltaTime);

        //地面检测
        isGround = characterController.isGrounded;
        if (isGround)
        {
            // 当isGrounded为true时,将Y轴方向的速度设为了一个较小的负值,这是为了确保能稳定触碰地面,避免isGrounded误判为false
            velocityGravity.y = -2f;
        }
        else
        {
            // 更新重力影响的速度
            velocityGravity.y += Gravity * Time.deltaTime;
        }
    }

    //物理碰撞效果
    private void OnControllerColliderHit(ControllerColliderHit hit)
    {
        //获取碰撞体上的 Rigidbody 组件。
        Rigidbody body = hit.rigidbody;

        //检查获取到的 Rigidbody 是否为空或者是否为静态物体(isKinematic)
        if (body == null || body.isKinematic)return;

        // 我们不想把物体推到我们下面 
        if (hit.moveDirection.y < -0.3)return;

        //根据移动方向计算推动方向,
        //我们只将物体推向两侧,从不上下 
        Vector3 pushDir = new Vector3(hit.moveDirection.x, 0, hit.moveDirection.z);

        // 在碰撞点施加冲量 ForceMode.Impulse:添加一个瞬间的冲击力到刚体,且自动应用它的质量
        body.AddForceAtPosition(pushDir * 0.1f, hit.point, ForceMode.Impulse);
    }
}

虚拟相机

等距离相机

新增Virtual Camera虚拟相机,配置参数

Framing Transposer向前看目标
POV根据用户的输入旋转相机

Follow Target Forward:Follow属性的forward
Look At Target Forward:Look At属性的forward
在这里插入图片描述
效果,相机距离主角固定距离旋转
在这里插入图片描述

钻裆看头顶相机

新增CinemachineFreeLook相机

默认情况下,镜头的上下左右的环绕移动是颠倒的,我们需手动将其改正过来

我们可通过 TopRig、MiddleRig、BottomRig 来分别调节相机的顶部、中部、底部的活动范围
然后 TopRig 的 Height 一般都高出三个模型左右,
BottomRig 的 Height 设置在正好到模型的脚底,
MiddleRig 的 Height 一般都设置得高出模型一头
在这里插入图片描述
效果

相机跟踪多个目标 Boss战锁定视角

Target Group Camera配置
在这里插入图片描述
Virtual Camera配置

Group Composer将多个目标保持在相机镜头内配置
在这里插入图片描述
在这里插入图片描述

效果,这里我手动设置蓝色方块为boss
在这里插入图片描述
代码动态添加锁定的敌人

publicGameObject jugador;//目标
CinemachineTargetGroup cinemachineTargetGroup = GetComponent<CinemachineTargetGroup>();

// 将目标的transform添加到CinemachineTargetGroup中
cinemachineTargetGroup.AddMember(jugador.transform, 1, 1);

三、第一人称 FPS

案例

《七日杀》《 csgo》 《穿越火线cf》等等
在这里插入图片描述
在这里插入图片描述

特点

第一人称视角,角色跟着相机转

角色控制代码

using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    private CharacterController characterController;

    [Header("输入")]
    float horizontal;
    float vertical;
    Vector3 direction;//输入创建移动方向向量
    
    [Header("移动")]
    public float speed = 5f; // 玩家移动的速度
    Vector3 moveDirection;//角色的移动方向

    [Header("旋转")]
    public float turnSpeed = 30f; // 角色转向速度
    Camera mainCamera;

    [Header("跳跃")]
    public float JumpHeight = 3f;//跳跃高度
    public float Gravity = -39.8f;//重力
    private Vector3 velocityGravity; // 重力速度

    [Header("地面检测")]
    public bool isGround;

    void Start()
    {
        characterController = GetComponent<CharacterController>(); // 初始化角色控制器
        mainCamera = Camera.main;
    }

    void Update()
    {
        SetPlayerMove();

        SetPlayerRotation();

        SetPlayerGravity();

        SetPlayerJump();
    }

    //处理角色移动
    void SetPlayerMove(){
        // 获取输入
        horizontal = Input.GetAxis("Horizontal");
        vertical = Input.GetAxis("Vertical");
        // 根据输入创建移动方向向量
        direction = new Vector3(horizontal, 0, vertical);
        
        //将该向量从局部坐标系转换为世界坐标系,得到最终的移动方向
        moveDirection  = transform.TransformDirection(direction);
        characterController.Move(moveDirection.normalized * speed * Time.deltaTime);
    }

    // 处理角色旋转
    void SetPlayerRotation()
    {
        // 进行平滑过渡到目标旋转(如果需要平滑效果)
        transform.rotation = Quaternion.Slerp(transform.rotation, mainCamera.transform.rotation, turnSpeed * Time.deltaTime);
    }

    // 处理角色跳跃
    void SetPlayerJump()
    {
        // 跳跃处理
        if (isGround && Input.GetButtonDown("Jump"))
        {
            velocityGravity.y = Mathf.Sqrt(JumpHeight * -2 * Gravity);
        }
    }

    // 处理角色重力
    void SetPlayerGravity()
    {
        // 应用重力
        characterController.Move(velocityGravity * Time.deltaTime);

        //地面检测
        isGround = characterController.isGrounded;
        if (isGround)
        {
            // 当isGrounded为true时,将Y轴方向的速度设为了一个较小的负值,这是为了确保能稳定触碰地面,避免isGrounded误判为false
            velocityGravity.y = -2f;
        }
        else
        {
            // 更新重力影响的速度
            velocityGravity.y += Gravity * Time.deltaTime;
        }
    }

    //物理碰撞效果
    private void OnControllerColliderHit(ControllerColliderHit hit)
    {
        //获取碰撞体上的 Rigidbody 组件。
        Rigidbody body = hit.rigidbody;

        //检查获取到的 Rigidbody 是否为空或者是否为静态物体(isKinematic)
        if (body == null || body.isKinematic)return;

        // 我们不想把物体推到我们下面 
        if (hit.moveDirection.y < -0.3)return;

        //根据移动方向计算推动方向,
        //我们只将物体推向两侧,从不上下 
        Vector3 pushDir = new Vector3(hit.moveDirection.x, 0, hit.moveDirection.z);

        // 在碰撞点施加冲量 ForceMode.Impulse:添加一个瞬间的冲击力到刚体,且自动应用它的质量
        body.AddForceAtPosition(pushDir * 0.1f, hit.point, ForceMode.Impulse);
    }
}

虚拟相机

新增Virtual Camera相机

Follow跟随主角头部
Noise设置轻微上下浮动,类似人物呼吸的效果
在这里插入图片描述

效果

在这里插入图片描述

四、越肩视角 第三人称射击游戏TPS 瞄准视角

案例

《和平精英》《绝地求生PUBG》等吃鸡类tps游戏
在这里插入图片描述

特点

角色跟着相机视野转

角色代码控制

using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    private CharacterController characterController;

    [Header("输入")]
    float horizontal;
    float vertical;
    Vector3 direction;//输入创建移动方向向量
    
    [Header("移动")]
    public float speed = 5f; // 玩家移动的速度
    Vector3 moveDirection;//角色的移动方向

    [Header("旋转")]
    public float turnSpeed = 30f; // 角色转向速度
    Camera mainCamera;

    [Header("跳跃")]
    public float JumpHeight = 3f;//跳跃高度
    public float Gravity = -39.8f;//重力
    private Vector3 velocityGravity; // 重力速度

    [Header("地面检测")]
    public bool isGround;

    void Start()
    {
        characterController = GetComponent<CharacterController>(); // 初始化角色控制器
        mainCamera = Camera.main;
    }

    void Update()
    {
        SetPlayerMove();

        SetPlayerRotation();

        SetPlayerGravity();

        SetPlayerJump();
    }

    //处理角色移动
    void SetPlayerMove(){
        // 获取输入
        horizontal = Input.GetAxis("Horizontal");
        vertical = Input.GetAxis("Vertical");
        // 根据输入创建移动方向向量
        direction = new Vector3(horizontal, 0, vertical);
        
        //将该向量从局部坐标系转换为世界坐标系,得到最终的移动方向
        moveDirection  = transform.TransformDirection(direction);
        characterController.Move(moveDirection.normalized * speed * Time.deltaTime);
    }

    // 处理角色旋转
    void SetPlayerRotation()
    {
        // 获取相机的旋转(只考虑 Y 轴的旋转)
        float yRotation = mainCamera.transform.eulerAngles.y;
        // 计算角色的目标旋转,只考虑 Y 轴的旋转
        Quaternion targetRotation = Quaternion.Euler(0, yRotation, 0);
        //进行平滑过渡到目标旋转(如果需要平滑效果)
        transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, turnSpeed * Time.deltaTime);
    }

    // 处理角色跳跃
    void SetPlayerJump()
    {
        // 跳跃处理
        if (isGround && Input.GetButtonDown("Jump"))
        {
            velocityGravity.y = Mathf.Sqrt(JumpHeight * -2 * Gravity);
        }
    }

    // 处理角色重力
    void SetPlayerGravity()
    {
        // 应用重力
        characterController.Move(velocityGravity * Time.deltaTime);

        //地面检测
        isGround = characterController.isGrounded;
        if (isGround)
        {
            // 当isGrounded为true时,将Y轴方向的速度设为了一个较小的负值,这是为了确保能稳定触碰地面,避免isGrounded误判为false
            velocityGravity.y = -2f;
        }
        else
        {
            // 更新重力影响的速度
            velocityGravity.y += Gravity * Time.deltaTime;
        }
    }

    //物理碰撞效果
    private void OnControllerColliderHit(ControllerColliderHit hit)
    {
        //获取碰撞体上的 Rigidbody 组件。
        Rigidbody body = hit.rigidbody;

        //检查获取到的 Rigidbody 是否为空或者是否为静态物体(isKinematic)
        if (body == null || body.isKinematic)return;

        // 我们不想把物体推到我们下面 
        if (hit.moveDirection.y < -0.3)return;

        //根据移动方向计算推动方向,
        //我们只将物体推向两侧,从不上下 
        Vector3 pushDir = new Vector3(hit.moveDirection.x, 0, hit.moveDirection.z);

        // 在碰撞点施加冲量 ForceMode.Impulse:添加一个瞬间的冲击力到刚体,且自动应用它的质量
        body.AddForceAtPosition(pushDir * 0.1f, hit.point, ForceMode.Impulse);
    }
}

相机

在这里插入图片描述

效果

在这里插入图片描述

五、俯视角射击游戏 2.5d俯视角射击

案例

《律动之城》《贪婪大地》等
在这里插入图片描述
在这里插入图片描述

特点

相机跟随角色不旋转,角色一直面向鼠标方向

代码

using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    private CharacterController characterController;

    [Header("输入")]
    float horizontal;
    float vertical;
    Vector3 direction;//输入创建移动方向向量

    [Header("移动")]
    public float speed = 5f; // 玩家移动的速度
    Vector3 moveDirection;//角色的移动方向

    [Header("旋转")]
    public float turnSpeed = 30f; // 角色转向速度
    Camera mainCamera;

    [Header("跳跃")]
    public float JumpHeight = 3f;//跳跃高度
    public float Gravity = -39.8f;//重力
    private Vector3 velocityGravity; // 重力速度

    [Header("地面检测")]
    public bool isGround;

    void Start()
    {
        characterController = GetComponent<CharacterController>(); // 初始化角色控制器
        mainCamera = Camera.main;
    }

    void Update()
    {
        SetPlayerMove();

        SetPlayerRotation();

        SetPlayerGravity();

        SetPlayerJump();
    }

    //处理角色移动
    void SetPlayerMove()
    {
        // 获取输入
        horizontal = Input.GetAxis("Horizontal");
        vertical = Input.GetAxis("Vertical");
        // 根据输入创建移动方向向量
        direction = new Vector3(horizontal, 0, vertical);
        
        moveDirection = direction;
        characterController.Move(direction.normalized * speed * Time.deltaTime);
    }

    // 处理角色旋转
    void SetPlayerRotation()
    {
        // 将玩家的位置从世界坐标转换为屏幕坐标
        Vector3 playerScreenPoint = mainCamera.WorldToScreenPoint(transform.position);
        // 获取鼠标位置与玩家屏幕位置之间的方向向量
        Vector3 point = Input.mousePosition - playerScreenPoint;
        // 获取方向向量2d屏幕坐标xy的夹角 Mathf.Atan2获取的是xy弧度值 Mathf.Rad2Deg用于将弧度转换为度数
        float angleY = Mathf.Atan2(point.x, point.y) * Mathf.Rad2Deg;
        Quaternion targetRotation = Quaternion.Euler(0, angleY, 0);
        // 平滑过渡到目标旋转
        transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, turnSpeed * Time.deltaTime);
    }

    // 处理角色跳跃
    void SetPlayerJump()
    {
        // 跳跃处理
        if (isGround && Input.GetButtonDown("Jump"))
        {
            velocityGravity.y = Mathf.Sqrt(JumpHeight * -2 * Gravity);
        }
    }

    // 处理角色重力
    void SetPlayerGravity()
    {
        // 应用重力
        characterController.Move(velocityGravity * Time.deltaTime);

        //地面检测
        isGround = characterController.isGrounded;
        if (isGround)
        {
            // 当isGrounded为true时,将Y轴方向的速度设为了一个较小的负值,这是为了确保能稳定触碰地面,避免isGrounded误判为false
            velocityGravity.y = -2f;
        }
        else
        {
            // 更新重力影响的速度
            velocityGravity.y += Gravity * Time.deltaTime;
        }
    }

    //物理碰撞效果
    private void OnControllerColliderHit(ControllerColliderHit hit)
    {
        //获取碰撞体上的 Rigidbody 组件。
        Rigidbody body = hit.rigidbody;

        //检查获取到的 Rigidbody 是否为空或者是否为静态物体(isKinematic)
        if (body == null || body.isKinematic) return;

        // 我们不想把物体推到我们下面 
        if (hit.moveDirection.y < -0.3) return;

        //根据移动方向计算推动方向,
        //我们只将物体推向两侧,从不上下 
        Vector3 pushDir = new Vector3(hit.moveDirection.x, 0, hit.moveDirection.z);

        // 在碰撞点施加冲量 ForceMode.Impulse:添加一个瞬间的冲击力到刚体,且自动应用它的质量
        body.AddForceAtPosition(pushDir * 0.1f, hit.point, ForceMode.Impulse);
    }
}

相机

Lock To Target On Assign 模式:当相机跟踪目标被设置的时候,把相机设置到目标物体的局部坐标系中,但不跟随目标物体的旋转而移动。简单讲就是:你动我动,你转我不动
在这里插入图片描述

效果

在这里插入图片描述

六、俯视角动作RPG

案例

如王者荣耀等MOBA类手游
在这里插入图片描述

特点

相机跟随主角,角色一直朝向移动方向

代码

using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    private CharacterController characterController;

    [Header("输入")]
    float horizontal;
    float vertical;
    Vector3 direction;//输入创建移动方向向量

    [Header("移动")]
    public float speed = 5f; // 玩家移动的速度
    Vector3 moveDirection;//角色的移动方向

    [Header("旋转")]
    public float turnSpeed = 30f; // 角色转向速度
    Camera mainCamera;

    [Header("跳跃")]
    public float JumpHeight = 3f;//跳跃高度
    public float Gravity = -39.8f;//重力
    private Vector3 velocityGravity; // 重力速度

    [Header("地面检测")]
    public bool isGround;

    void Start()
    {
        characterController = GetComponent<CharacterController>(); // 初始化角色控制器
        mainCamera = Camera.main;
    }

    void Update()
    {
        SetPlayerMove();

        SetPlayerRotation();

        SetPlayerGravity();

        SetPlayerJump();
    }

    //处理角色移动
    void SetPlayerMove()
    {
        // 获取输入
        horizontal = Input.GetAxis("Horizontal");
        vertical = Input.GetAxis("Vertical");
        // 根据输入创建移动方向向量
        direction = new Vector3(horizontal, 0, vertical);
        
        moveDirection = direction;
        characterController.Move(direction.normalized * speed * Time.deltaTime);
    }

    // 处理角色旋转
    void SetPlayerRotation()
    {
        if (direction != Vector3.zero)
        {
            // 计算目标旋转四元数
            Quaternion targetRotation = Quaternion.LookRotation(moveDirection, transform.up);// 计算旋转的四元数
            // 平滑过渡到目标旋转
            transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, turnSpeed * Time.deltaTime);
        }
    }

    // 处理角色跳跃
    void SetPlayerJump()
    {
        // 跳跃处理
        if (isGround && Input.GetButtonDown("Jump"))
        {
            velocityGravity.y = Mathf.Sqrt(JumpHeight * -2 * Gravity);
        }
    }

    // 处理角色重力
    void SetPlayerGravity()
    {
        // 应用重力
        characterController.Move(velocityGravity * Time.deltaTime);

        //地面检测
        isGround = characterController.isGrounded;
        if (isGround)
        {
            // 当isGrounded为true时,将Y轴方向的速度设为了一个较小的负值,这是为了确保能稳定触碰地面,避免isGrounded误判为false
            velocityGravity.y = -2f;
        }
        else
        {
            // 更新重力影响的速度
            velocityGravity.y += Gravity * Time.deltaTime;
        }
    }

    //物理碰撞效果
    private void OnControllerColliderHit(ControllerColliderHit hit)
    {
        //获取碰撞体上的 Rigidbody 组件。
        Rigidbody body = hit.rigidbody;

        //检查获取到的 Rigidbody 是否为空或者是否为静态物体(isKinematic)
        if (body == null || body.isKinematic) return;

        // 我们不想把物体推到我们下面 
        if (hit.moveDirection.y < -0.3) return;

        //根据移动方向计算推动方向,
        //我们只将物体推向两侧,从不上下 
        Vector3 pushDir = new Vector3(hit.moveDirection.x, 0, hit.moveDirection.z);

        // 在碰撞点施加冲量 ForceMode.Impulse:添加一个瞬间的冲击力到刚体,且自动应用它的质量
        body.AddForceAtPosition(pushDir * 0.1f, hit.point, ForceMode.Impulse);
    }
}

相机

和前面俯视角一样

Lock To Target On Assign 模式:当相机跟踪目标被设置的时候,把相机设置到目标物体的局部坐标系中,但不跟随目标物体的旋转而移动。简单讲就是:你动我动,你转我不动
在这里插入图片描述

效果

在这里插入图片描述

七、上帝视角 RTS视角

这种相机相对简单,其实用普通相机也可以了
参考:
【用unity实现100个游戏之3】制作一个类帝国时代、红警——RTS战略性游戏
【用unity实现100个游戏之14】Unity2d做一个建造与防御类rts游戏(附项目源码)

案例

《帝国时代》《红警等》等RTS游戏,甚至《LOL英雄联盟》自由视角其实也算是
在这里插入图片描述

特点

wasd控制相机移动,鼠标滚轮负责相机远近(也可以修改相机视野远近)

相机

在这里插入图片描述

相机控制

新增CameraHandler脚本,控制虚拟相机的移动和缩放

using UnityEngine;
using Cinemachine;

public class CameraHandler : MonoBehaviour
{
    [SerializeField] private CinemachineVirtualCamera cinemachinevirtualCamera;
    private float orthographicSize;
    private float targetOrthographicSize;

    // 获取初始的正交大小
    private void Start()
    {
        orthographicSize = cinemachinevirtualCamera.m_Lens.OrthographicSize;
        targetOrthographicSize = orthographicSize;
    }

    private void Update()
    {
        HandleMovement();
        HandleZoom();
    }

    // 处理摄像机移动
    private void HandleMovement()
    {
        float x = Input.GetAxisRaw("Horizontal");
        float y = Input.GetAxisRaw("Vertical");
        Vector3 moveDir = new Vector3(x, y).normalized;
        float moveSpeed = 60f;
        transform.position += moveDir * moveSpeed * Time.deltaTime;
    }

    // 处理缩放
    private void HandleZoom()
    {
        float zoomAmount = 2f;
        targetOrthographicSize += Input.mouseScrollDelta.y * zoomAmount;
        float minOrthographicSize = 10;
        float maxOrthographicSize = 30;
        targetOrthographicSize = Mathf.Clamp(targetOrthographicSize, minOrthographicSize, maxOrthographicSize);
        float zoomSpeed = 5f;
        orthographicSize = Mathf.Lerp(orthographicSize, targetOrthographicSize, Time.deltaTime * zoomSpeed);

        // 设置摄像机的正交大小
        cinemachinevirtualCamera.m_Lens.OrthographicSize = orthographicSize;
    }
}

效果

在这里插入图片描述
也可以添加CinemachineFollowZoom组件动态调整镜头FOV,自带阻尼配置
在这里插入图片描述

八、类似《LOL英雄联盟》的固定视角,镜头绕人物环绕缩放

参考:【制作100个unity游戏之22】3DRPG游戏开发06——敌人和攻击

特点

滚轮控制相机远近,AD按键控制摄像头绕人物左右旋转

相机

新增CinemachineFreeLook相机

CinemachineFreeLook虚拟相机可以修改控制相机旋转的虚拟轴参数,也就可以实现滚轮控制远近,AD按键控制摄像头左右
在这里插入图片描述
修改参数达到一个好的效果
在这里插入图片描述

效果

在这里插入图片描述
还可以修改摄像机bingding mode参数,比如我们选择Lock To Traeget With World Up,摄像机就会自动跟随人物进行旋转
在这里插入图片描述

八、相机避障不穿墙

在虚拟相机基础上加了CinemachineCollider,避免相机穿墙的问题,保持LookAt目标的视线不受遮挡。

Collide Against:被认定为障碍物的Layer,这里Default图层就是地面和障碍物图层
Ignore Tag:忽略碰撞检测的Tag,这里设置的是Player,也就是不与主角做碰撞检测(也就是说摄像机有可能从主角身上穿过去)
Transparent Layers:透明层,透明层的物体被认为是透明的,不作为障碍物处理。
在这里插入图片描述
效果
在这里插入图片描述

九、InputSystem滚轮修改相机远近

其实就是修改FOV这个值
在这里插入图片描述
InputSystem绑定滚轮输入
在这里插入图片描述
在这里插入图片描述
限制滚轮值的大小,比如这里我配置最小-4 最大4
在这里插入图片描述
修改

public class CameraFOVController : MonoBehaviour
{
    public CinemachineVirtualCamera virtualCamera; // 拖拽虚拟相机到这里
    public float fovChangeSpeed = 1f; // FOV 变化速度

    private void Update()
    {
        // 获取滚轮输入
        float scrollValue = Mouse.current.scroll.ReadValue().y;

        if (virtualCamera != null)
        {
            // 获取当前 FOV
            float currentFOV = virtualCamera.m_Lens.FieldOfView;

            // 修改 FOV
            currentFOV -= scrollValue * fovChangeSpeed;
            
            //限制 FOV 范围
            currentFOV = Mathf.Clamp(currentFOV, 10f, 100f); 

            // 应用新的 FOV
            virtualCamera.m_Lens.FieldOfView = currentFOV;
        }
    }
}

十、根据InputSystem的鼠标指针输入旋转相机视野

以CinemachineFreeLook为例,可以看到,在X Axis和 Y Axis中,依赖里Input Axis Name,而这里的默认值是旧的输入系统,我们需要把这两个值覆盖为新的输入系统。
在这里插入图片描述
而官方为我们提供解决方法,添加组件Cinemachine Input Provider
在这里插入图片描述
在Input Aciton中添加一个Action用于处理鼠标操作,Action的Control Type 选择Vector2。
在这里插入图片描述
在绑定按键时,使用鼠标/指针的Delta作为变动值来处理
在这里插入图片描述

保存action后,去选择配置XY Axis即可。
在这里插入图片描述

十一、根据InputSystem滚轮控制相机远近缩放 按住鼠标右键控制相机视野旋转

案例

类似《和平精英》等TPS小眼睛查看视野的效果

绑定获取按住鼠标右键输入

绑定One Modifier按钮控制,One Modifier复合输入允许你将一个主要输入与一个修饰输入组合起来。修饰输入会影响主要输入的行为。例如,你可以用它来实现一个动作需要按住某个修饰键的功能。比如我接下来要绑定的鼠标右键点击输入+鼠标移动输入,就是实现了按住鼠标右键再移动才能控制相机视野旋转

Pass Through监听持续输入
Any 获取任何类似参数
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Scale Vector 2的x,y=1,0,相当于按住鼠标滑动输入不影响y轴数值,如果你想镜头可以上下查看,就可以不加这个限制
在这里插入图片描述
如果要绑定其他设备按钮,可以直接复制一个绑定新设备按钮,比如支持手柄操作等(这里我只是测试数据,所以用JK按钮代替)
在这里插入图片描述

绑定滚轮输入

Scale Vector 2的x,y=0,1,相当于滚轮输入不影响x轴
在这里插入图片描述

调用

通常都在CinemachineFreeLook相机上使用,我们配置的InputSystem输入会代替原来的旧输入系统进行相机镜头的控制
在这里插入图片描述

效果

在这里插入图片描述

相机震动

参考:unity实现简单的摄像机震动效果(包括普通摄像机和虚拟摄像机)

轨道相机

CinemachinePath(轨道):通过配置多个关键点组成轨道。将轨道赋给虚拟相机的Body.Path字段,则相机被固定在轨道上;将轨道赋给CinemachineDollyCart(轨道车),轨道车将匀速在轨道移动。
在这里插入图片描述
CinemachineSmoothPath(平滑的轨道):通过配置多个关键点组成轨道,自动生成轨道片段的走线方向(CinemachinePath中被Tangenet影响)以保证平缓。
在这里插入图片描述
CinemachineDollyCart(轨道车):轨道车可沿轨道匀速行驶,将轨道车赋给虚拟相机的Follow字段则可实现相机跟随轨道车的移动。
在这里插入图片描述

自动选择最佳的子相机进行拍摄

CinemachineClearShot(虚拟相机):配置多个虚拟相机为CinemachineClearShot的子节点,CinemachineClearShot会根据权重、阻挡等,自动选择最佳的子相机进行拍摄。必须要给CinemachineClearShot配置碰撞体(Cinmachine Collider)。
在这里插入图片描述

在屏幕上显示一张图片 瞄准相机显示瞄准十字准心

新增CinemachineStoryboard,很合适给瞄准相机单独添加瞄准十字准心
在这里插入图片描述
效果
在这里插入图片描述

按动画状态切换不同相机 瞄准相机切换 释放大招切换特写相机

CinemachineStateDrivenCamera(虚拟相机):可以把动画状态和虚拟相机进行绑定,当动画状态切换的时候,虚拟相机自动进行切换。必须将切换的虚拟相机设置为此相机的子节点。

比如做一个播放瞄准动画自动切换瞄准相机的功能或者释放大招切换特写相机
在这里插入图片描述

过场动画相机

CinemachineBlentListCamera:设置一组虚拟相机的线性变化队列,每个片段可单独设置长度及渐变时间(包含在片段长度中)。
在这里插入图片描述

参考

https://docs.unity3d.com/Packages/com.unity.cinemachine@2.3/manual/

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!如果你遇到任何问题,也欢迎你评论私信或者加群找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向宇it

创作不易,感谢你的鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值