UnityRTS實(shí)現(xiàn)相機(jī)移動縮放功能
所謂RTS就是即時戰(zhàn)略游戲(Real-Time Strategy Game)。
話不多說直接看一下demo:

相機(jī)的層級關(guān)系(移動的操作是對父物體進(jìn)行操作,而縮放是對子物體主相機(jī)的操作):

以此場景為例,自己設(shè)置的一些參數(shù),主要是移動速度,邊界、縮放限制等。

代碼如下(掛載到相機(jī)的父物體上)。有兩種鼠標(biāo)的控制方式,一種是邊界檢測,一種是鼠標(biāo)拖動。這個代碼是完整版的,也就是鍵盤也可以控制相機(jī)移動縮放的,如果只需要鼠標(biāo)控制的,請往下看:
using UnityEngine;
/// <summary>
///
/// * Writer:June
/// *
/// * Data:2021.3.9
/// *
/// * Function:RTS模式的相機(jī)移動
/// *
/// * Remarks:
///
/// </summary>
public class CameraMoveControl : MonoBehaviour
{
#region 移動
/// <summary>
/// 移動速度
/// </summary>
private float panSpeed;
/// <summary>
/// 正常速度
/// </summary>
[SerializeField] private float normalSpeed;
/// <summary>
/// 按shift加速
/// </summary>
[SerializeField] private float speedUp;
/// <summary>
/// 緩沖時間
/// </summary>
[SerializeField] private float moveTime;
private Vector3 newPos;
/// <summary>
/// 邊界限制
/// </summary>
[SerializeField] private float xLimMin, xLimMax;
/// <summary>
/// 這里的Y是指屏幕上下平移的限制
/// </summary>
[SerializeField] private float yLimMin, yLimMax;
//-----------------------------------------------鼠標(biāo)拖動操作相關(guān)字段----------------------------------------------------
private Camera mainCamrea;
private Vector3 startPoint, currentPoint;
#endregion
#region 縮放
/// <summary>
/// 主攝像機(jī)的位置組件
/// </summary>
private Transform mainCamreaTF;
/// <summary>
/// 縮放向量
/// tips:相機(jī)的放大縮小改變的是相機(jī)自身坐標(biāo)的yz值
/// </summary>
[SerializeField] private Vector3 zoomV3;
/*
* 需要注意的是縮放限制:
* x軸與y軸限制后的縮放比值要一致,不然會出現(xiàn)縮放不平滑的現(xiàn)象
*
*/
/// <summary>
/// 縮放最大最小值
/// </summary>
[SerializeField] private Vector3 zoomMin, zoomMax;
private Vector3 newMainCamreaPos;
/// <summary>
/// 縮放時間
/// </summary>
[SerializeField] private float zoomTime;
#endregion
private void Start()
{
//判斷是否有子物體
mainCamreaTF = transform.childCount > 0 ? transform.GetChild(0) : null;
if (mainCamreaTF) newMainCamreaPos = mainCamreaTF.localPosition;
mainCamrea = Camera.main;
}
private void Update()
{
//按左shift加速
panSpeed = Input.GetKey(KeyCode.LeftShift) ? speedUp : normalSpeed;
//移動
ControlCamreaMove();
//縮放
ControlCamreaZoom();
}
/// <summary>
/// 控制相機(jī)縮放
/// </summary>
private void ControlCamreaZoom()
{
if (mainCamreaTF)
{
if (Input.GetKey(KeyCode.R)) newMainCamreaPos += zoomV3 * Time.deltaTime;//放大
if (Input.GetKey(KeyCode.F)) newMainCamreaPos -= zoomV3 * Time.deltaTime;//縮小
newMainCamreaPos += Input.GetAxis("Mouse ScrollWheel") * zoomV3;
ZoomLimit(ref newMainCamreaPos);
//刷新最終位置
mainCamreaTF.localPosition = Vector3.Lerp(mainCamreaTF.localPosition, newMainCamreaPos, zoomTime * Time.deltaTime);
}
}
/// <summary>
/// 控制相機(jī)移動
/// </summary>
private void ControlCamreaMove()
{
Vector3 movePos = transform.position;
newPos.Set(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
#region 鼠標(biāo)操作
#region 方式1(鼠標(biāo)到達(dá)邊緣,檢測后操作相機(jī)移動)
//Vector2 mousePos = Input.mousePosition;
//鼠標(biāo)在四個邊緣檢測
//if (mousePos.x > Screen.width * 0.9f && mousePos.x < Screen.width) newPos.x = 1;
//if (mousePos.x < Screen.width * 0.1f && mousePos.x > 0) newPos.x = -1;
//if (mousePos.y > Screen.height * 0.9f && mousePos.y < Screen.height) newPos.z = 1;
//if (mousePos.y < Screen.height * 0.1f && mousePos.y > 0) newPos.z = -1;
movePos += newPos.normalized * panSpeed * Time.deltaTime;
#endregion
#region 方式2(鼠標(biāo)右鍵拖動控制相機(jī)移動)
//首先判斷相機(jī)是否為空
if (mainCamrea)
{
//鼠標(biāo)右鍵按下時記錄起始位置
if (Input.GetMouseButtonDown(1))
{
//新建的世界坐標(biāo)系下的平面,用于檢測射線
Plane plane = new Plane(Vector3.up, Vector3.zero);
Ray ray = mainCamrea.ScreenPointToRay(Input.mousePosition);
float distance;
if (plane.Raycast(ray, out distance))
{
//獲取碰撞位置
startPoint = ray.GetPoint(distance);
}
}
//鼠標(biāo)右鍵一直按下時記錄當(dāng)前點(diǎn)位置
if (Input.GetMouseButton(1))
{
Plane plane = new Plane(Vector3.up, Vector3.zero);
Ray ray = mainCamrea.ScreenPointToRay(Input.mousePosition);
float distance;
if (plane.Raycast(ray, out distance))
{
currentPoint = ray.GetPoint(distance);
}
movePos += (startPoint - currentPoint);
}
}
#endregion
#endregion
BoundaryLimit(ref movePos);
transform.position = Vector3.Lerp(transform.position, movePos, moveTime);
}
/// <summary>
/// 邊界限制
/// </summary>
/// <param name="_pos">要限制的目標(biāo)向量</param>
private void BoundaryLimit(ref Vector3 _pos)
{
_pos.x = Mathf.Clamp(_pos.x, xLimMin, xLimMax);
_pos.z = Mathf.Clamp(_pos.z, yLimMin, yLimMax);
}
/// <summary>
/// 縮放限制
/// </summary>
/// <param name="_v3">要限制的目標(biāo)向量</param>
private void ZoomLimit(ref Vector3 _v3)
{
_v3.y = Mathf.Clamp(_v3.y, zoomMin.y, zoomMax.y);
_v3.z = Mathf.Clamp(_v3.z, zoomMin.z, zoomMax.z);
}
}
這個代碼是后來我覺得其實(shí)沒必要用鍵盤來操控相機(jī),根據(jù)我玩過的一些類似游戲,比較多都是鼠標(biāo)操作的,所以刪了鍵盤操作的部分:
using UnityEngine;
/// <summary>
///
/// * Writer:June
/// *
/// * Data:2021.3.9
/// *
/// * Function:RTS模式的相機(jī)移動
/// *
/// * Remarks:
///
/// </summary>
public class CameraMoveControl : MonoBehaviour
{
#region 移動
/// <summary>
/// 移動速度
/// </summary>
private float panSpeed;
/// <summary>
/// 正常速度
/// </summary>
[SerializeField] private float normalSpeed;
/// <summary>
/// 按shift加速
/// </summary>
[SerializeField] private float speedUp;
/// <summary>
/// 緩沖時間
/// </summary>
[SerializeField] private float moveTime;
private Vector3 newPos;
/// <summary>
/// 邊界限制
/// </summary>
[SerializeField] private float xLimMin, xLimMax;
/// <summary>
/// 這里的Y是指屏幕上下平移的限制
/// </summary>
[SerializeField] private float yLimMin, yLimMax;
//-----------------------------------------------鼠標(biāo)拖動操作相關(guān)字段----------------------------------------------------
private Camera mainCamrea;
private Vector3 startPoint, currentPoint;
#endregion
#region 縮放
/// <summary>
/// 主攝像機(jī)的位置組件
/// </summary>
private Transform mainCamreaTF;
/// <summary>
/// 縮放向量
/// tips:相機(jī)的放大縮小改變的是相機(jī)自身坐標(biāo)的yz值
/// </summary>
[SerializeField] private Vector3 zoomV3;
/*
* 需要注意的是縮放限制:
* x軸與y軸限制后的縮放比值要一致,不然會出現(xiàn)縮放不平滑的現(xiàn)象
*
*/
/// <summary>
/// 縮放最大最小值
/// </summary>
[SerializeField] private Vector3 zoomMin, zoomMax;
private Vector3 newMainCamreaPos;
/// <summary>
/// 縮放時間
/// </summary>
[SerializeField] private float zoomTime;
#endregion
private void Start()
{
//判斷是否有子物體
mainCamreaTF = transform.childCount > 0 ? transform.GetChild(0) : null;
if (mainCamreaTF) newMainCamreaPos = mainCamreaTF.localPosition;
mainCamrea = Camera.main;
}
private void Update()
{
//按左shift加速
panSpeed = Input.GetKey(KeyCode.LeftShift) ? speedUp : normalSpeed;
//移動
ControlCamreaMove();
//縮放
ControlCamreaZoom();
}
/// <summary>
/// 控制相機(jī)縮放
/// </summary>
private void ControlCamreaZoom()
{
if (mainCamreaTF)
{
newMainCamreaPos += Input.GetAxis("Mouse ScrollWheel") * zoomV3;
ZoomLimit(ref newMainCamreaPos);
//刷新最終位置
mainCamreaTF.localPosition = Vector3.Lerp(mainCamreaTF.localPosition, newMainCamreaPos, zoomTime * Time.deltaTime);
}
}
/// <summary>
/// 控制相機(jī)移動
/// </summary>
private void ControlCamreaMove()
{
Vector3 movePos = transform.position;
newPos = Vector3.zero;
#region 鼠標(biāo)操作
#region 方式1(鼠標(biāo)到達(dá)邊緣,檢測后操作相機(jī)移動)
Vector2 mousePos = Input.mousePosition;
//鼠標(biāo)在四個邊緣檢測
if (mousePos.x > Screen.width * 0.9f && mousePos.x < Screen.width) newPos.x = 1;
if (mousePos.x < Screen.width * 0.1f && mousePos.x > 0) newPos.x = -1;
if (mousePos.y > Screen.height * 0.9f && mousePos.y < Screen.height) newPos.z = 1;
if (mousePos.y < Screen.height * 0.1f && mousePos.y > 0) newPos.z = -1;
movePos += newPos.normalized * panSpeed * Time.deltaTime;
#endregion
#region 方式2(鼠標(biāo)右鍵拖動控制相機(jī)移動)
//首先判斷相機(jī)是否為空
if (mainCamrea)
{
//鼠標(biāo)右鍵按下時記錄起始位置
if (Input.GetMouseButtonDown(1))
{
//新建的世界坐標(biāo)系下的平面,用于檢測射線
Plane plane = new Plane(Vector3.up, Vector3.zero);
Ray ray = mainCamrea.ScreenPointToRay(Input.mousePosition);
float distance;
if (plane.Raycast(ray, out distance))
{
//獲取碰撞位置
startPoint = ray.GetPoint(distance);
}
}
//鼠標(biāo)右鍵一直按下時記錄當(dāng)前點(diǎn)位置
if (Input.GetMouseButton(1))
{
Plane plane = new Plane(Vector3.up, Vector3.zero);
Ray ray = mainCamrea.ScreenPointToRay(Input.mousePosition);
float distance;
if (plane.Raycast(ray, out distance))
{
currentPoint = ray.GetPoint(distance);
}
movePos += (startPoint - currentPoint);
}
}
#endregion
#endregion
BoundaryLimit(ref movePos);
transform.position = Vector3.Lerp(transform.position, movePos, moveTime);
}
/// <summary>
/// 邊界限制
/// </summary>
/// <param name="_pos">要限制的目標(biāo)向量</param>
private void BoundaryLimit(ref Vector3 _pos)
{
_pos.x = Mathf.Clamp(_pos.x, xLimMin, xLimMax);
_pos.z = Mathf.Clamp(_pos.z, yLimMin, yLimMax);
}
/// <summary>
/// 縮放限制
/// </summary>
/// <param name="_v3">要限制的目標(biāo)向量</param>
private void ZoomLimit(ref Vector3 _v3)
{
_v3.y = Mathf.Clamp(_v3.y, zoomMin.y, zoomMax.y);
_v3.z = Mathf.Clamp(_v3.z, zoomMin.z, zoomMax.z);
}
}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C#實(shí)現(xiàn)協(xié)同過濾算法的實(shí)例代碼
這篇文章介紹了C#實(shí)現(xiàn)協(xié)同過濾算法的實(shí)例代碼,有需要的朋友可以參考一下2013-07-07
Untiy Shader實(shí)現(xiàn)紋理貼圖滾動
這篇文章主要為大家詳細(xì)介紹了Untiy Shader實(shí)現(xiàn)紋理貼圖滾動,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-03-03
VSCode調(diào)試C#程序及附缺失.dll文件的解決辦法
這篇文章主要介紹了VSCode調(diào)試C#程序及附缺失.dll文件的解決辦法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
DevExpress實(shí)現(xiàn)GridControl單元格編輯驗(yàn)證的方法
這篇文章主要介紹了DevExpress實(shí)現(xiàn)GridControl單元格編輯驗(yàn)證的方法,很實(shí)用的功能,需要的朋友可以參考下2014-08-08

