Unity中,在开发战斗系统的时候需要镜头从第三人称自由镜头切换到锁定怪物镜头的情况,从而使得玩家方便进行战斗与自由移动。用Cinemachine虚拟相机的LookAt来进行锁定的效果始终不符合预期(也可能是我没有调到合适的参数),于是就试着参考网上的教程来自己制作镜头和镜头切换了,这里就大概记录一下吧,顺便给自己整理下思路:
- 创建空对象CameraHolder,将他的位置放在角色的后脑勺,并创建子对象Pivot(意思是中心点,转动中枢),将主相机放在Pivot内,调整相机的位置使得相机能照到角色全身。
- 创建Camera Manager脚本,并挂载到Camera Holder处,以下是定义的一些参数。
- 声明的参数和初始化如下:
public Transform targetTransform; //相机跟随目标(即玩家)
public Transform lockTarget; //相机锁定的目标(即敌人)
public Transform pivot; //相机中心点对象
public float followSpeed = 0.1f; //相机跟随速度
public float rotateSpeed = 1; //相机旋转速度
public float TopClamp = 70.0f; //相机俯视最大角
public float BottomClamp = -60.0f; //相机仰视最大角
public Image lockDot; //锁定圆点UI
public bool isLocked; //是否锁定标志
private float lookAngle; //横向角度
private float pivotAngle; //纵向角度
private Transform _transform;
private void Awake()
{
_transform = this.transform;
lockDot.enabled = false;
isLocked = false;
}
- 编写脚本函数,主要的函数有三个:
1、根据鼠标移动让镜头延迟跟随的函数:
public void Tick(float delta)
{
// 相机延迟跟随
Vector3 targetPosition = Vector3.Lerp(_transform.position, targetTransform.position, delta / followSpeed);
_transform.position = targetPosition;
}
2、镜头转角函数(是实现切换镜头的核心函数,我以自己的理解写了一些注解,仅供参考):
public void HandleRotation(float delta, float mouseX, float mouseY)
{
if (lockTarget == null)
{
// 无锁定时的转向
lookAngle += mouseX * (delta / rotateSpeed); //根据鼠标横向输入转化当前镜头横向角度
pivotAngle += mouseY * (delta / rotateSpeed); //根据鼠标纵向输入转化当前镜头纵向角度
pivotAngle = Mathf.Clamp(pivotAngle, BottomClamp, TopClamp); //限制纵向角度
Vector3 euler = Vector3.zero;
euler.y = lookAngle;
euler.x = pivotAngle;
Quaternion targetRotation = Quaternion.Euler(euler);
//让镜头的旋转角赋值为当前所应该转到的横纵角
_transform.rotation = targetRotation;
pivot.rotation = Quaternion.Lerp(pivot.rotation, targetRotation, delta/ 0.25f);
}
else
{
// 锁定时转向
Vector3 lockPos = lockTarget.position;
Vector3 dir = lockPos - _transform.position;
dir.Normalize();
dir.y = 0;
Quaternion targetRotation = Quaternion.LookRotation(dir); //镜头目标转向为玩家角色到当前锁定目标的向量的横向平面分量
Vector3 pivotDir = lockPos - pivot.position;
pivotDir.Normalize();
Quaternion pivotTargetRotation = Quaternion.LookRotation(pivotDir);
Vector3 e = pivotTargetRotation.eulerAngles;
e.y = 0; //只考虑垂直转向,即pivot指向玩家角色到当前锁定目标的向量的纵向分量
//让镜头角度和pivot角度线性变化,实现丝滑转换自由镜头和锁定镜头
_transform.rotation = Quaternion.Lerp(_transform.rotation, targetRotation, Time.fixedDeltaTime / 0.25f);
pivot.localEulerAngles = Vector3.Lerp(pivot.localEulerAngles, e, Time.fixedDeltaTime / 0.25f);
pivotAngle = 0; //清空当前的纵向角度,使得解锁镜头时镜头不会出现突变
lookAngle = _transform.eulerAngles.y; //使读入的镜头横向角度始终为当前角度值,同样是为了使得解锁镜头时镜头不会出现突变
}
}
3、通过外部按键切换锁定状态函数:
public void SwitchLockOnState()
{
if(lockTarget == null)
{
Vector3 modelOrigin = targetTransform.position;
Vector3 boxCenter = modelOrigin + targetTransform.transform.forward * 6.0f;
Collider[] cols = Physics.OverlapBox(boxCenter, new Vector3(2.0f, 2.0f, 5f), targetTransform.transform.rotation, LayerMask.GetMask("Enemy"));
if(cols != null)
foreach(var col in cols)
{
lockTarget = col.gameObject.transform;
// lockTarget.position += col.gameObject.GetComponent<CapsuleCollider>().center;
lockDot.enabled = true;
isLocked = true;
targetTransform.GetComponentInParent<Animator>().SetBool("isLocked", true);
break;
}
}
else
{
lockTarget = null;
lockDot.enabled = false;
isLocked = false;
targetTransform.GetComponentInParent<Animator>().SetBool("isLocked", false);
}
// print("镜头锁定!");
}
- 函数调用
Tick与HandleRotation可在你的角色控制器中调用,以官方的ThirdPersonController.cs为例,可以加在原来的CameraRotation函数中:
private void CameraRotation()
{
// if there is an input and camera position is not fixed
if (_input.look.sqrMagnitude >= _threshold && !LockCameraPosition)
{
//Don't multiply mouse input by Time.deltaTime;
float deltaTimeMultiplier = IsCurrentDeviceMouse ? 1.0f : Time.deltaTime;
_cinemachineTargetYaw += _input.look.x * deltaTimeMultiplier;
_cinemachineTargetPitch += _input.look.y * deltaTimeMultiplier;
}
CameraManager.Tick(Time.fixedDeltaTime);
CameraManager.HandleRotation(Time.fixedDeltaTime, _input.look.x, _input.look.y);
}
SwitchLockOnState()在任意Update函数调用即可,这里依旧在ThirdPersonController.cs调用:
private void Update()
{
_hasAnimator = TryGetComponent(out _animator);
JumpAndGravity();
GroundedCheck();
Move();
SwitchWeapon();
//Attack();
if (_input.lockOn)
{
CameraManager.SwitchLockOnState();
_input.lockOn = false;
}
}
大功告成,将对应的物件置入脚本中,就可以使用你定义的锁定键来实现敌人的锁定和解锁啦!
希望这个笔记能帮到正在学习Unity的你
参考教程: