Unity 實現(xiàn)框選游戲戰(zhàn)斗單位的思路詳解
?? Preface
本文簡單介紹如何實現(xiàn)即時戰(zhàn)略游戲中框選戰(zhàn)斗單位的功能,如圖所示:
?? 實現(xiàn)思路:
本文將該功能的實現(xiàn)拆分為以下部分:
- 在屏幕坐標系中繪制框選范圍;
- 根據(jù)框選范圍定位其在世界坐標系中對應的區(qū)域;
- 在該區(qū)域內進行物理檢測。
? 如何在屏幕坐標系內繪制框選框
使用Line Renderer
光線渲染器組件來進行范圍繪制,當鼠標按下時,可以獲得框選范圍的起始點
,鼠標持續(xù)按下時,鼠標位置則是框選范圍的結束點
,根據(jù)這兩個點的坐標可以求得另外兩個頂點的坐標,如圖所示:
首先設置Line Renderer
光線渲染器的屬性:
Enable
:默認設為false,當鼠標按下時將其設為true;Loop
:設為true,為了讓第三個頂點與起始點相連形成閉環(huán);Size
:設為4,框選范圍有4個頂點;Width
:設為0.001即可,線框不需要很粗,可適當調整;
代碼部分:
using UnityEngine; using SK.Framework; using System.Collections.Generic; public class Example : MonoBehaviour { //光線渲染器組件 private LineRenderer lineRenderer; //屏幕坐標系起始點 private Vector3 screenStartPoint; //屏幕坐標系結束點 private Vector3 screenEndPoint; private void Start() { //獲取光線渲染器組件 lineRenderer = GetComponent<LineRenderer>(); } private void Update() { //鼠標按下 if (Input.GetMouseButtonDown(0)) { //激活光線渲染器 lineRenderer.enabled = true; //屏幕坐標系起始點 screenStartPoint = Input.mousePosition; screenStartPoint.z = 1; } //鼠標持續(xù)按下 if (Input.GetMouseButton(0)) { //屏幕坐標系結束點 screenEndPoint = Input.mousePosition; screenEndPoint.z = 1; //求得框選框的另外兩個頂點的位置 Vector3 point1 = new Vector3(screenEndPoint.x, screenStartPoint.y, 1); Vector3 point2 = new Vector3(screenStartPoint.x, screenEndPoint.y, 1); //接下來使用光線渲染器畫出框選范圍 lineRenderer.SetPosition(0, Camera.main.ScreenToWorldPoint(screenStartPoint)); lineRenderer.SetPosition(1, Camera.main.ScreenToWorldPoint(point1)); lineRenderer.SetPosition(2, Camera.main.ScreenToWorldPoint(screenEndPoint)); lineRenderer.SetPosition(3, Camera.main.ScreenToWorldPoint(point2)); } //鼠標抬起 if (Input.GetMouseButtonUp(0)) { //取消光線渲染器 lineRenderer.enabled = false; } } }
如圖所示,已經(jīng)實現(xiàn)框選范圍的繪制:
?? 根據(jù)框選范圍定位其在世界坐標系中對應的區(qū)域
該部分的實現(xiàn)主要依靠物理射線檢測,在鼠標位置發(fā)出射線,檢測與地面的碰撞點,首先為Plane地面設置Layer
層級:
在鼠標按下時根據(jù)射線檢測信息確定世界坐標系中的起始點:
//鼠標按下 if (Input.GetMouseButtonDown(0)) { //激活光線渲染器 lineRenderer.enabled = true; //屏幕坐標系起始點 screenStartPoint = Input.mousePosition; screenStartPoint.z = 1; //射線檢測 if (Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition), out hit, 1 << LayerMask.NameToLayer("Ground"))) { //世界坐標系起始點 worldStartPoint = hit.point; } }
在鼠標抬起時根據(jù)射線檢測信息確定世界坐標系中的結束點:
//鼠標抬起 if (Input.GetMouseButtonUp(0)) { //取消光線渲染器 lineRenderer.enabled = false; //射線檢測 if (Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition), out hit, 1 << LayerMask.NameToLayer("Ground"))) { //世界坐標系結束點 worldEndPoint = hit.point; } }
?? 在該區(qū)域內進行物理檢測
該部分用的的核心API:
可以理解為創(chuàng)建一個碰撞盒來檢測該范圍內的碰撞體,首先計算出該API需要傳入的參數(shù):
center
:該盒子的中心點;halfExtents
:該盒子長寬高的一半。
//盒子中心點 Vector3 center = new Vector3((worldEndPoint.x + worldStartPoint.x) * .5f, 1f, (worldEndPoint.z + worldStartPoint.z) * .5f); //盒子長寬高的一半 Vector3 halfExtents = new Vector3(Mathf.Abs(worldEndPoint.x - worldStartPoint.x) * .5f, 1f, Mathf.Abs(worldEndPoint.z - worldStartPoint.z) * .5f);
有了這兩個參數(shù),調用該API可以獲得該區(qū)域內的所有碰撞體,遍歷判斷碰撞體身上如果包含指定的組件,則將其選中,這里使用Outline
高亮組件來表示:
//盒子中心點 Vector3 center = new Vector3((worldEndPoint.x + worldStartPoint.x) * .5f, 1f, (worldEndPoint.z + worldStartPoint.z) * .5f); //盒子長寬高的一半 Vector3 halfExtents = new Vector3(Mathf.Abs(worldEndPoint.x - worldStartPoint.x) * .5f, 1f, Mathf.Abs(worldEndPoint.z - worldStartPoint.z) * .5f); //檢測到盒子內的碰撞器 Collider[] colliders = Physics.OverlapBox(center, halfExtents); for (int i = 0; i < colliders.Length; i++) { var collider = colliders[i]; var outline = collider.GetComponent<Outline>(); if (outline != null) { outline.enabled = true; } }
如圖所示,我們已經(jīng)實現(xiàn)了基本的框選功能:
在框選時,還需要清除上一次框選的內容,因此我們使用一個List
列表來記錄當前框選的戰(zhàn)斗單位,框選前遍歷該列表來清除框選記錄,完整代碼如下:
public class Example : MonoBehaviour { //光線渲染器組件 private LineRenderer lineRenderer; //屏幕坐標系起始點 private Vector3 screenStartPoint; //屏幕坐標系結束點 private Vector3 screenEndPoint; //主相機 private Camera mainCamera; //碰撞信息 private RaycastHit hit; //世界坐標系起始點 private Vector3 worldStartPoint; //世界坐標系結束點 private Vector3 worldEndPoint; //框選記錄列表 private List<Outline> list = new List<Outline>(); private void Start() { //獲取光線渲染器組件 lineRenderer = GetComponent<LineRenderer>(); //獲取主相機 mainCamera = Camera.main != null ? Camera.main : FindObjectOfType<Camera>(); } private void Update() { //鼠標按下 if (Input.GetMouseButtonDown(0)) { //激活光線渲染器 lineRenderer.enabled = true; //屏幕坐標系起始點 screenStartPoint = Input.mousePosition; screenStartPoint.z = 1; //射線檢測 if (Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition), out hit, 1 << LayerMask.NameToLayer("Ground"))) { //世界坐標系起始點 worldStartPoint = hit.point; } } //鼠標持續(xù)按下 if (Input.GetMouseButton(0)) { //屏幕坐標系結束點 screenEndPoint = Input.mousePosition; screenEndPoint.z = 1; //求得框選框的另外兩個頂點的位置 Vector3 point1 = new Vector3(screenEndPoint.x, screenStartPoint.y, 1); Vector3 point2 = new Vector3(screenStartPoint.x, screenEndPoint.y, 1); //接下來使用光線渲染器畫出框選范圍 lineRenderer.SetPosition(0, Camera.main.ScreenToWorldPoint(screenStartPoint)); lineRenderer.SetPosition(1, Camera.main.ScreenToWorldPoint(point1)); lineRenderer.SetPosition(2, Camera.main.ScreenToWorldPoint(screenEndPoint)); lineRenderer.SetPosition(3, Camera.main.ScreenToWorldPoint(point2)); } //鼠標抬起 if (Input.GetMouseButtonUp(0)) { //取消光線渲染器 lineRenderer.enabled = false; //首先清除上一次的框選記錄 for (int i = 0; i < list.Count; i++) { list[i].enabled = false; } list.Clear(); //射線檢測 if (Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition), out hit, 1 << LayerMask.NameToLayer("Ground"))) { //世界坐標系結束點 worldEndPoint = hit.point; //盒子中心點 Vector3 center = new Vector3((worldEndPoint.x + worldStartPoint.x) * .5f, 1f, (worldEndPoint.z + worldStartPoint.z) * .5f); //盒子長寬高的一半 Vector3 halfExtents = new Vector3(Mathf.Abs(worldEndPoint.x - worldStartPoint.x) * .5f, 1f, Mathf.Abs(worldEndPoint.z - worldStartPoint.z) * .5f); //檢測到盒子內的碰撞器 Collider[] colliders = Physics.OverlapBox(center, halfExtents); for (int i = 0; i < colliders.Length; i++) { var collider = colliders[i]; var outline = collider.GetComponent<Outline>(); if (outline != null) { list.Add(outline); outline.enabled = true; } } } } } }
到此這篇關于Unity 如何實現(xiàn)框選游戲戰(zhàn)斗單位的文章就介紹到這了,更多相關Unity框選游戲戰(zhàn)斗單位內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C#利用Task實現(xiàn)任務超時多任務一起執(zhí)行的方法
這篇文章主要給大家介紹了關于C#利用Task實現(xiàn)任務超時,多任務一起執(zhí)行的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友下面來一起看看吧。2017-12-12