星盟冲突,星区视角下的缩放效果图:
一. 手势系统
使用插件EasyTouch监听移动缩放
EasyTouch.On_Pinch += CameraController.Instance.OnPinch;
EasyTouch.On_Swipe += CameraController.Instance.OnSwipe;
EasyTouch.On_Drag += CameraController.Instance.OnSwipe;
// 只监听一个手指的滑动手势 用gesture.touchCount判断
public void OnSwipe(Gesture gesture)
{
if (gesture.touchCount > 1)
{
return;
}
Move(gesture.swipeVector);
}
public void OnPinch(Gesture gesture)
{
Zoom(gesture.deltaPinch);
}
// 移动摄像机
private void Move(Vector2 swipeVector)
{
...
}
// 摄像机拉近拉远
private void Zoom(float deltaPinch)
{
...
}
二. 相机lookat一个坐标点的简单模型
相机以某个视角eulerAngles,距离目标坐标点distanceFromTarget,lookat这个坐标点:
private void CameraLookatPos(Vector3 eulerAngles, float distanceFromTarget)
{
Vector3 lookatPos = GetLookatPos();
Quaternion q = Quaternion.Euler(eulerAngles);
transform.position = lookatPos - q * Vector3.forward * distanceFromTarget
transform.eulerAngles = eulerAngles
}
脚本挂在Camera上
三. 相机移动缩放
- 使用增量记录本次移动缩放的变化值
- 在LateUpdate中,根据相机距离,插值计算当前相机视角,设置相机位置
- 地图边界检测
- 若合法,则把移动缩放增量加到总值;
- 若检测到越界,非法,则把移动缩放增量舍弃,并在同一帧 重新设置位置position与角度eulerAngles
代码经过删减简化,外部设置参数部分删除,仅展示移动缩放的处理流程
private Vector3 _MovePos = Vector3.zero; // Move操作的总位移offset
private float distanceFromTarget;// 当前相机距目标的距离,缩放操作才能改变
private Vector3 _IncreMoveVector = Vector3.zero; // Move操作的本次操作增量
private float _IncreCameraDis = 0; // Zoom 缩放操作的本次操作增量
private Vector3 _cameraEuler = Vector3.zero; // 相机距离最近时的视角,外部设置
... MIN_CAMERA_DIS; // 相机高度最低,外部设置
... VERTICAL_CAMERA_DIS; // 相机高度-垂直点,外部设置
... MAX_CAMERA_DIS; // 相机高度最高,外部设置
... FINAL_ANGLE; // 缩小到最小的视角,默认是90度 俯视,外部设置
// 移动摄像机 记录增量
private void Move(Vector2 swipeVector)
{
// 计算的偏移与边界处理有关
_IncreMoveVector.x = 计算的偏移X;//-swipeVector.x * MOVE_FACTOR;
_IncreMoveVector.z = 计算的偏移Z;//-swipeVector.y * MOVE_FACTOR;
}
// 摄像机拉近拉远 记录增量
private void Zoom(float deltaPinch)
{
// 计算的偏移与边界处理有关
_IncreCameraDis = Mathf.Min(MAX_CAMERA_DIS, Mathf.Max(MIN_CAMERA_DIS, distanceFromTarget + deltaPinch * PINCH_FACTOR)) - distanceFromTarget;
}
private Vector3 GetMovePos()
{
return _MovePos + _IncreMoveVector;
}
private float GetCameraDis()
{
return distanceFromTarget + _IncreCameraDis;
}
// 线性插值 得出当前高度的视角
private Quaternion GetCameraCurrAngle(float t)
{
if (t < 0 || t >= 1)
{
return Quaternion.Euler(FINAL_ANGLE, _cameraEuler.y, 0);
}
return Quaternion.Lerp(Quaternion.Euler(_cameraEuler.x, _cameraEuler.y, 0), Quaternion.Euler(FINAL_ANGLE, _cameraEuler.y, 0), t);
}
private void CameraGesture()
{
Vector3 lookatPos = GetLookatPos();
Quaternion q = GetCameraCurrAngle((GetCameraDis() - MIN_CAMERA_DIS) / (VERTICAL_CAMERA_DIS - MIN_CAMERA_DIS));
transform.position = lookatPos - q * Vector3.forward * GetCameraDis() + GetMovePos();
transform.eulerAngles = q.eulerAngles;
}
private void UpdateCamera()
{
...
CameraGesture()
...
}
private void LateUpdate()
{
UpdateCamera();
if (_IncreCameraDis == 0 || _IncreMoveVector == Vector3.zero)
{
return;
}
// 边界检测
if (CheckBoundary()) // 校验本次移动缩放合法,则把移动缩放增量加到总值
{
_MovePos += _IncreMoveVector;
distanceFromTarget += _IncreCameraDis;
_IncreMoveVector = Vector3.zero;
_IncreCameraDis = 0;
}
else // 校验本次移动缩放越界,非法,则把移动缩放增量舍弃,并在同一帧 重新设置位置position与角度eulerAngles
{
_IncreMoveVector = Vector3.zero;
_IncreCameraDis = 0;
UpdateCamera();
}
}