相机控制脚本(两种模式)
代码如下:
/*****************************************************************
*Copyright(C) 2021 by DefaultCompany
*All rights reserved.
*FileName:CameraControlScript.cs
*Author:#小菜鸟#
*Version:1.0
*UnityVersion:#2020.3.1#
*Date:2023-03-24
*Description: 摄像机常用,两种模式,
*自由模式(鼠标右键旋转视角,WASD前后左右)
*鼠标模式(鼠标右键转动视角,鼠标左键按住移动位置),默认是无模式
*包括聚焦功能,需要配合RuntimeGizmo插件使用,不需要可以注释掉
*History:
*******************************************************************/
using System.Collections.Generic;
using UnityEngine;
using Zhen;
namespace Common
{
public class CameraControlScript : MonoBehaviour
{
public CameraMode cameraMode;
public float freedomSpeed = 50f;//自由模式移动速度
public float mouseSpeed = 5f; //鼠标模式移动速度
public float wheelSpeed = 5f;//鼠标滚轮缩放速度
public float rotateSpeed = 90.0f;//摄像机旋转速度
public float yMinLimit = -30;//摄像机上下最小角度
public float yMaxLimit = 30;//摄像机上下最大角度
private float x = 0.0f;
private float y = 0.0f;
private void Start()
{
var angles = transform.eulerAngles;
x = angles.y;
y = angles.x;
}
void Update()
{
Viewpoint();
//F按键聚焦
if (Input.GetKeyDown(KeyCode.F) && target)
{
Focus(target.gameObject);
}
}
private void LateUpdate()
{
Wheel();
switch (cameraMode)
{
case CameraMode.自由模式:
Freedom();
break;
case CameraMode.鼠标模式:
MouseControl();
break;
default:
break;
}
if (isAligning)//表示是否处于聚焦过程
{
AutoAlignView();
}
}
/// <summary>
/// 摄像机模式设置方法
/// </summary>
/// <param name="mode"></param>
public void SetCameraModeType(CameraMode mode)
{
cameraMode = mode;
}
#region ###全局使用鼠标右键转动,鼠标中键缩放
Vector2 inputAxis = new Vector2(); //鼠标输入
/// <summary>
/// 鼠标右键控制视角转动
/// </summary>
public void Viewpoint()
{
if (Input.GetMouseButton(1))
{
var angles = transform.eulerAngles;
x = angles.y;
y = angles.x;
inputAxis = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));
x += inputAxis.x * rotateSpeed * 0.02f;
y -= inputAxis.y * rotateSpeed * 0.02f;
y = ClampAngle(y, yMinLimit, yMaxLimit);
var rotation = Quaternion.Euler(y, x, 0);
transform.rotation = rotation;
}
}
/// <summary>
/// 限制视角
/// </summary>
/// <param name="angle"></param>
/// <param name="min"></param>
/// <param name="max"></param>
/// <returns></returns>
private float ClampAngle(float angle, float min, float max)
{
if (angle < -360)
{
angle += 360;
}
if (angle > 360)
{
angle -= 360;
}
return Mathf.Clamp(angle, min, max);
}
/// <summary>
/// 鼠标滚轮控制摄像机缩放
/// </summary>
void Wheel()
{
//如果先接触的是UI就return 不执行额外点击事件
if (CommonFuncScript.Instance.CheckGuiRaycastObjects())
return;
//获取鼠标滚轮的滑动量
float wheel = Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime * 1000;
//改变相机的位置
transform.Translate(Vector3.forward * wheel * wheelSpeed);
}
#endregion
#region ###摄像机自由模式
private void Freedom()
{
//w键前进
if (Input.GetKey(KeyCode.W))
{
transform.Translate(new Vector3(0, 0, freedomSpeed * Time.deltaTime), transform);
}
//s键后退
if (Input.GetKey(KeyCode.S))
{
transform.Translate(new Vector3(0, 0, -1 * freedomSpeed * Time.deltaTime), transform);
}
//a键后退
if (Input.GetKey(KeyCode.A))
{
transform.Translate(new Vector3(-1 * freedomSpeed * Time.deltaTime, 0, 0), transform);
}
//d键后退
if (Input.GetKey(KeyCode.D))
{
transform.Translate(new Vector3(Time.deltaTime * freedomSpeed, 0, 0), transform);
}
if (Input.GetKey(KeyCode.Q))
{
transform.Translate(new Vector3(0, Time.deltaTime * freedomSpeed, 0), transform);
}
if (Input.GetKey(KeyCode.E))
{
transform.Translate(new Vector3(0, -1 * Time.deltaTime * freedomSpeed, 0), transform);
}
Limit();
}
float limity = 2;
/// <summary>
/// 限制移动
/// </summary>
private void Limit()
{
if (transform.position.y < limity)
{
transform.position = new Vector3(transform.position.x, limity, transform.position.z);
}
}
#endregion
#region ###摄像机鼠标模式
void MouseControl()
{
if (Input.GetMouseButton(2))
{
float _mouseX = Input.GetAxis("Mouse X");
float _mouseY = Input.GetAxis("Mouse Y");
//鼠标图标换成自定义小手
//RsCursorMgr.Instance.SetCursorDrag();
//相机位置的偏移量(Vector3类型,实现原理是:向量的加法)
Vector3 moveDir = (_mouseX * -transform.right + _mouseY * -transform.forward);
//限制y轴的偏移量
moveDir.y = 0;
transform.position += moveDir * mouseSpeed;
}
else
{
//鼠标恢复默认图标,置null即可
//RsCursorMgr.Instance.CursorReSet();
}
}
#endregion
#region ###摄像机聚焦功能
[Header("聚焦")]
public float distance = 150;//摄像机聚焦的距离
public Transform target
{
get
{
return GetComponent<RuntimeGizmos.TransformGizmo>().targetRootsOrdered[0];
}
}
public Vector2 angles;
Vector2 currentAngles;
Vector2 lastAngles;
Vector2 targetAngles;
Vector3 currentDirection, targetDirection, lastDirection;
float anglesSpeed, directionSpeed, distanceSpeed;
float currentDistance;
float targetDistance;
float anglesOffset, directionOffset, distanceOffset;
float lastDistance;
[Range(0, 5)]
public float alignDamper = 2.5f;
[Range(0, 1)]
public float threshold = 0.1f;
public bool isAligning;//表示摄像机是否处于聚焦过程中
bool linearAdsorbent;
/// <summary>
/// 聚焦的方法
/// </summary>
/// <param name="go"></param>
public void Focus(GameObject go)
{
currentAngles = Camera.main.transform.eulerAngles;
AlignVeiwToTarget(go.transform, new Vector2(angles.x, currentAngles.y), distance);
}
/// <summary>
/// 聚焦移动的方法
/// </summary>
/// <param name="center"></param>
/// <param name="angles"></param>
/// <param name="distance"></param>
public void AlignVeiwToTarget(Transform center, Vector2 angles, float distance)
{
target.position = center.position;
targetAngles = angles;
targetDistance = distance;
//Optimal angles.
while (targetAngles.y - currentAngles.y > 180)
targetAngles.y -= 360;
while (targetAngles.y - currentAngles.y < -180)
targetAngles.y += 360;
//Calculate lerp parameter.
currentDistance = Vector3.Distance(transform.position, target.position);
currentDirection = (transform.position - target.position).normalized;
targetDirection = (Quaternion.Euler(targetAngles) * Vector3.back).normalized;
//Calculate offset.
anglesOffset = (targetAngles - currentAngles).magnitude;
directionOffset = (targetDirection - currentDirection).magnitude;
distanceOffset = Mathf.Abs(targetDistance - currentDistance);
//Check zero value of offset.
anglesOffset = anglesOffset > Vector3.kEpsilon ? anglesOffset : 1;
directionOffset = directionOffset > Vector3.kEpsilon ? directionOffset : 1;
distanceOffset = distanceOffset > Vector3.kEpsilon ? distanceOffset : 1;
//Start align.
linearAdsorbent = false;
isAligning = true;
}
/// <summary>
/// 聚焦过程执行的方法
/// </summary>
private void AutoAlignView()
{
var currentAnglesOffset = (targetAngles - currentAngles).magnitude;
var currentDirectionOffset = (targetDirection - currentDirection).magnitude;
var currentDistanceOffset = Mathf.Abs(targetDistance - currentDistance);
if (currentAnglesOffset < 0.1f && currentDirectionOffset < 0.1f && currentDistanceOffset < 0.1f)
{
isAligning = false;
}
else
{
if (linearAdsorbent)
{
//MoveTowards to linear adsorbent align.
currentAngles = Vector2.MoveTowards(currentAngles, targetAngles, anglesSpeed * Time.deltaTime);
currentDirection = Vector3.MoveTowards(currentDirection, targetDirection, directionSpeed * Time.deltaTime);
currentDistance = Mathf.MoveTowards(currentDistance, targetDistance, distanceSpeed * Time.deltaTime);
}
else
{
//Record last.
lastAngles = currentAngles;
lastDirection = currentDirection;
lastDistance = currentDistance;
//Lerp to align.
currentAngles = Vector2.Lerp(currentAngles, targetAngles, alignDamper * Time.deltaTime);
currentDirection = Vector3.Lerp(currentDirection, targetDirection, alignDamper * Time.deltaTime);
currentDistance = Mathf.Lerp(currentDistance, targetDistance, alignDamper * Time.deltaTime);
//Check into linear adsorbent.
if (currentAnglesOffset / anglesOffset < threshold && currentDirectionOffset / directionOffset < threshold && currentDistanceOffset / distanceOffset < threshold)
{
anglesSpeed = (currentAngles - lastAngles).magnitude / Time.deltaTime;
directionSpeed = (currentDirection - lastDirection).magnitude / Time.deltaTime;
distanceSpeed = Mathf.Abs(currentDistance - lastDistance) / Time.deltaTime;
linearAdsorbent = true;
}
}
transform.position = target.position + currentDirection.normalized * currentDistance;
transform.rotation = Quaternion.Euler(currentAngles);
//解决摄像机死锁的问题
var angles = transform.eulerAngles;
x = angles.y;
y = angles.x;
}
}
#endregion
}
/// <summary>
/// 摄像机模式类型,可继续添加
/// </summary>
public enum CameraMode
{
无,
自由模式,
鼠标模式,
}
}