UnityRTS實(shí)現(xiàn)相機(jī)移動(dòng)縮放功能
所謂RTS就是即時(shí)戰(zhàn)略游戲(Real-Time Strategy Game)。
話不多說(shuō)直接看一下demo:
相機(jī)的層級(jí)關(guān)系(移動(dòng)的操作是對(duì)父物體進(jìn)行操作,而縮放是對(duì)子物體主相機(jī)的操作):
以此場(chǎng)景為例,自己設(shè)置的一些參數(shù),主要是移動(dòng)速度,邊界、縮放限制等。
代碼如下(掛載到相機(jī)的父物體上)。有兩種鼠標(biāo)的控制方式,一種是邊界檢測(cè),一種是鼠標(biāo)拖動(dòng)。這個(gè)代碼是完整版的,也就是鍵盤(pán)也可以控制相機(jī)移動(dòng)縮放的,如果只需要鼠標(biāo)控制的,請(qǐng)往下看:
using UnityEngine; /// <summary> /// /// * Writer:June /// * /// * Data:2021.3.9 /// * /// * Function:RTS模式的相機(jī)移動(dòng) /// * /// * Remarks: /// /// </summary> public class CameraMoveControl : MonoBehaviour { #region 移動(dòng) /// <summary> /// 移動(dòng)速度 /// </summary> private float panSpeed; /// <summary> /// 正常速度 /// </summary> [SerializeField] private float normalSpeed; /// <summary> /// 按shift加速 /// </summary> [SerializeField] private float speedUp; /// <summary> /// 緩沖時(shí)間 /// </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)拖動(dòng)操作相關(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軸限制后的縮放比值要一致,不然會(huì)出現(xiàn)縮放不平滑的現(xiàn)象 * */ /// <summary> /// 縮放最大最小值 /// </summary> [SerializeField] private Vector3 zoomMin, zoomMax; private Vector3 newMainCamreaPos; /// <summary> /// 縮放時(shí)間 /// </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; //移動(dòng) 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ī)移動(dòng) /// </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á)邊緣,檢測(cè)后操作相機(jī)移動(dòng)) //Vector2 mousePos = Input.mousePosition; //鼠標(biāo)在四個(gè)邊緣檢測(cè) //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)右鍵拖動(dòng)控制相機(jī)移動(dòng)) //首先判斷相機(jī)是否為空 if (mainCamrea) { //鼠標(biāo)右鍵按下時(shí)記錄起始位置 if (Input.GetMouseButtonDown(1)) { //新建的世界坐標(biāo)系下的平面,用于檢測(cè)射線 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)右鍵一直按下時(shí)記錄當(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); } }
這個(gè)代碼是后來(lái)我覺(jué)得其實(shí)沒(méi)必要用鍵盤(pán)來(lái)操控相機(jī),根據(jù)我玩過(guò)的一些類似游戲,比較多都是鼠標(biāo)操作的,所以刪了鍵盤(pán)操作的部分:
using UnityEngine; /// <summary> /// /// * Writer:June /// * /// * Data:2021.3.9 /// * /// * Function:RTS模式的相機(jī)移動(dòng) /// * /// * Remarks: /// /// </summary> public class CameraMoveControl : MonoBehaviour { #region 移動(dòng) /// <summary> /// 移動(dòng)速度 /// </summary> private float panSpeed; /// <summary> /// 正常速度 /// </summary> [SerializeField] private float normalSpeed; /// <summary> /// 按shift加速 /// </summary> [SerializeField] private float speedUp; /// <summary> /// 緩沖時(shí)間 /// </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)拖動(dòng)操作相關(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軸限制后的縮放比值要一致,不然會(huì)出現(xiàn)縮放不平滑的現(xiàn)象 * */ /// <summary> /// 縮放最大最小值 /// </summary> [SerializeField] private Vector3 zoomMin, zoomMax; private Vector3 newMainCamreaPos; /// <summary> /// 縮放時(shí)間 /// </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; //移動(dòng) 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ī)移動(dòng) /// </summary> private void ControlCamreaMove() { Vector3 movePos = transform.position; newPos = Vector3.zero; #region 鼠標(biāo)操作 #region 方式1(鼠標(biāo)到達(dá)邊緣,檢測(cè)后操作相機(jī)移動(dòng)) Vector2 mousePos = Input.mousePosition; //鼠標(biāo)在四個(gè)邊緣檢測(cè) 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)右鍵拖動(dòng)控制相機(jī)移動(dòng)) //首先判斷相機(jī)是否為空 if (mainCamrea) { //鼠標(biāo)右鍵按下時(shí)記錄起始位置 if (Input.GetMouseButtonDown(1)) { //新建的世界坐標(biāo)系下的平面,用于檢測(cè)射線 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)右鍵一直按下時(shí)記錄當(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); } }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C#實(shí)現(xiàn)協(xié)同過(guò)濾算法的實(shí)例代碼
這篇文章介紹了C#實(shí)現(xiàn)協(xié)同過(guò)濾算法的實(shí)例代碼,有需要的朋友可以參考一下2013-07-07Untiy Shader實(shí)現(xiàn)紋理貼圖滾動(dòng)
這篇文章主要為大家詳細(xì)介紹了Untiy Shader實(shí)現(xiàn)紋理貼圖滾動(dòng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-03-03VSCode調(diào)試C#程序及附缺失.dll文件的解決辦法
這篇文章主要介紹了VSCode調(diào)試C#程序及附缺失.dll文件的解決辦法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09深入分析C#鍵盤(pán)勾子(Hook),屏蔽鍵盤(pán)活動(dòng)的詳解
本篇文章是對(duì)C#鍵盤(pán)勾子(Hook),屏蔽鍵盤(pán)活動(dòng)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05DevExpress實(shí)現(xiàn)GridControl單元格編輯驗(yàn)證的方法
這篇文章主要介紹了DevExpress實(shí)現(xiàn)GridControl單元格編輯驗(yàn)證的方法,很實(shí)用的功能,需要的朋友可以參考下2014-08-08