U
章 03镜头与操作6 课 — 点击打开
03 / 06 · 8 分钟
镜头与操作

Cinemachine 与镜头震动

到目前为止的项目

Assets/

Scenes/

Arena.unity

CameraTargetCinemachineBrainCM vcamImpulse source / listenerOrbitCamera.cs→Cinemachine vcam

项目设置

Cinemachine package

你已经有的这一课新增这一课替换

第三步,也是最后一步。Cinemachine 把 FollowCamera 和 OrbitCamera 都换成了只靠配置的组件 —— 而且它处理穿墙、阻尼和转场,都比你刚写的那段代码更好。

动态图解

还是同一个环绕思路,但阻尼、防穿墙和取景都是自带的。

安装与设置

  1. 1

    Window▸Package Manager▸Unity Registry → 搜索 Cinemachine → Install。

  2. 2

    GameObject▸Cinemachine▸Virtual Camera(Cinemachine 3 里叫 CinemachineCamera)。

  3. 3

    Unity 会自动给 Main Camera 加上一个 CinemachineBrain。真正驱动实际相机的是这个 brain。

  4. 4

    在虚拟相机上把 Follow 设为 Knight,Look At 设为 Knight 的 CameraTarget。

在脑子里怎么想

  • 虚拟相机并不是相机,它是一张配方单:站在这里、看向那里、阻尼给这么多。

  • Main Camera 上的 Brain 会挑出当前启用、Priority 最高的那个虚拟相机,然后朝它混合过去。

  • 所以切相机就是改一下 Priority 或者调用 SetActive —— 转场部分是白送的。

两次点击搞定第三人称环绕相机

  1. 1

    在虚拟相机上把 Body 设为 Third Person Follow(CM3 里是 Orbital Follow)。

  2. 2

    设置 Camera Distance 6、Shoulder Offset X 0.5、Damping 0.3 / 0.3 / 0.3。

  3. 3

    把 Camera Collision Filter 设成你的环境层 —— 穿墙问题到此结束。

  4. 4

    如果装置的朝向本来就对,Aim 用 Do Nothing;要一直把目标框在画面里就用 Composer。

✓ Hand-written camera

你懂它的原理,每一行都在自己手里。做小游戏很合适。

✓ Cinemachine

防穿墙、阻尼、震屏、转场、过场动画 —— 前人都解决好了,而且经过实战检验。

用 Impulse 做镜头震动

  1. 1

    给虚拟相机加上 Cinemachine Impulse Listener。

  2. 2

    给会爆炸或者能打中人的东西加上 Cinemachine Impulse Source。

  3. 3

    在代码里调用 GenerateImpulse(),范围内的每个 listener 都会跟着震。

HitShake.cs
using UnityEngine;
using Unity.Cinemachine;      // Cinemachine 2: using Cinemachine;

public class HitShake : MonoBehaviour
{
    [SerializeField] private CinemachineImpulseSource source;

    public void Shake(float strength = 1f)
    {
        source.GenerateImpulseWithForce(strength);
    }
}

为技能或过场切换相机

C# 脚本
[SerializeField] private CinemachineCamera gameplayCam;
[SerializeField] private CinemachineCamera ultimateCam;

public void PlayUltimate()
{
    ultimateCam.Priority = 20;      // higher wins
    Invoke(nameof(BackToGameplay), 2f);
}

void BackToGameplay() => ultimateCam.Priority = 0;