本文介绍如何实现用于Avatar角色的相机控制脚本,支持第一人称、第三人称以及两种模式之间的切换,工具已上传至SKFramework
框架的Package Manager
中:
Avatar
:相机跟随的Avatar角色;Control Mode
:控制模式 第一人称/第三人称;Mode Change Key
:切换第一/第三人称模式的快捷键,若不支持切换设为None即可;Forward Align With Avatar
:视角前方是否与Avatar对齐,为flase时表示视角可以在水平方向旋转;Horizontal Sensitivity
:水平方向旋转的灵敏度;Vertical Sensitivity
:垂直方向旋转的灵敏度;Rot Y Min Limit
:垂直方向上旋转最小值限制;Rot Y Max Limit
:垂直方向上旋转最大值限制;Rotation Lerp Time
:插值到目标旋转值所需的时间;Height
:相机与Avatar角色的高度差;Distance
:相机与Avatar角色的默认距离;Min Distance Limit
:相机距人物最小距离限制;Max Distance Limit
:相机距人物最大距离限制;fpmDistance
:第一人称模式所用的固定距离(第一人称时距离固定);scollSensitivity
:鼠标滚轮的灵敏度(第三人称时可滚动距离);Invert Scroll Direction
:反转鼠标滚轮滚动的反向;Horizontal Offset
:与Avatar在水平方向上的偏移值(仅在Forward Align With Avatar
为true时开启使用,可以让Avatar在视野中偏左或偏右);Obstacle Layer
:用于避障检测的Layer层级如下例所示,将场景中障碍物体的Layer设为Obstacle
避障检测时检测该层级:
Ctrl Avatar Rot When FP Mode
:是否在第一人称模式下旋转视角时,同步旋转Avatar角色的朝向;
影响相机坐标的元素包括Avatar与相机的距离(Distance)、Avatar与相机的高度差(Height)、目标旋转值、水平方向上的偏移量(Horizontal Offset)及避障检测的影响。
//鼠标滚轮滚动改变距离
distance -= Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime * 100f * scollSensitivity * (invertScrollDirection ? -1f : 1f);
//距离钳制
distance = Mathf.Clamp(distance, minDistanceLimit, maxDistanceLimit);
//插值方式计算距离
targetDistance = controlMode == ControlMode.ThirdPersonControl? Mathf.Lerp(targetDistance, distance, Time.deltaTime * scollSensitivity): fpmDistance;
//目标坐标值
Vector3 targetPosition = targetRotation * Vector3.forward * -targetDistance + avatar.position + Vector3.up * height;
SphereCast
球形物理检测,检测碰撞点并向前移动://避障检测
private Vector3 ObstacleAvoidance(Vector3 current, Vector3 target, float radius, float maxDistance)
{Ray ray = new Ray(target, current - target);if (Physics.SphereCast(ray, radius, out RaycastHit hit, maxDistance, obstacleLayer)){return ray.GetPoint(hit.distance - radius * 2f);}return current;
}
//避障
targetPosition = ObstacleAvoidance(targetPosition, avatar.position + Vector3.up * height, .1f, distance);
transform.position = targetPosition + Vector3.left * horizontalOffset;
//检测鼠标右键按下
if (Input.GetMouseButton(1))
{horizontal = forwardAlignWithAvatar ? 0f : Input.GetAxis("Mouse X") * Time.deltaTime * 100f * horizontalSensitivity;vertical = Input.GetAxis("Mouse Y") * Time.deltaTime * 100f * verticalSensitivity;rotX += horizontal;rotY -= vertical;//钳制旋转y值角度rotY = Mathf.Clamp(rotY, rotYMinLimit, rotYMaxLimit);
}
//目标旋转值
Quaternion targetRotation = Quaternion.Euler(rotY, rotX, 0f);
//旋转值插值率
float rotationLerpPct = 1f - Mathf.Exp(Mathf.Log(1f - .99f) / rotationLerpTime * Time.deltaTime);
//插值方式计算旋转值
targetRotation = Quaternion.Lerp(transform.rotation, targetRotation, rotationLerpPct);
transform.rotation = targetRotation;//第一人称控制模式 相机视角旋转的同时控制Avatar角色的旋转
if (controlMode == ControlMode.FirstPersonControl && ctrlAvatarRotWhenFPMode)
{Vector3 euler = Vector3.zero;//只取相机的RotYeuler.y = targetRotation.eulerAngles.y;avatar.rotation = Quaternion.Euler(euler);
}
if (Input.GetKeyDown(modeChangeKey))
{controlMode = controlMode == ControlMode.FirstPersonControl? ControlMode.ThirdPersonControl: ControlMode.FirstPersonControl;
}
MonoBehaviour
生命周期函数LateUpdate
中,确保Avatar角色运动完成后,相机再进行跟随。
上一篇:软件质量保证与测试(测试部分)