文章來源
https://gamedevacademy.org/learn-and-understand-raycasting-in-unity3d/
在Unity3D中學習和理解Raycasting
您可以從以下位置下載本教程中使用的資源:
使用 Autodesk角色生成器 創建3D角色模型
2D精靈是從Kennynl Kenney•Tanks 免費提供給我的
教程源文件位於此處。
今天,我們將討論Raycasting。對於那些不熟悉術語Raycasting的人,讓我們在開始之前給出一些解釋。
什麼是Raycasting?
“Raycasting是從一個點射出不可見光線的過程,在指定的方向上檢測是否有任何碰撞器位於光線的路徑上。”
這對於側滾動射擊遊戲,FPS,第三人稱射擊遊戲,子彈地獄和冒險遊戲。能夠追踪子彈或激光從開始到結束的位置,意味著我們確切地知道它應該如何表現。我們可以在遊戲世界中進行物理觀察並操縱它。
Unity3D中的Raycasting分為兩個不同的部分,2D和3D。兩者都是物理對象。他們有自己的方法文件; 然而,3D和2D分別對2D和3D遊戲使用相同的遊戲對象(線條渲染器)。
入門
在開始之前,讓我們創建一個空的3D項目。由於該項目將同時使用2D和3D,因此稍後將其轉換為2D以用於場景非常簡單。
在Assets文件夾中創建總共5個文件夾。模型,場景和腳本。在Models文件夾中,創建2個名為2D Art和3D Art的文件夾。
將Art導入各自的文件夾。
現在,創建並保存2個場景。分別將它們命名為2D和3D。
加載2D場景,讓我們開始在Unity3D中為2D遊戲進行Raycasting課程。
2DRaycasting
首先,移除定向燈。我們點擊2D現場查看和相機改變角度至正交。
tank spritesheet的紋理類型應設置為Sprite(2D和UI),Sprite Mode設置為Multiple。現在選擇申請。
單擊Sprite Editor,現在我們可以開始將spritesheet切片為單獨的sprite對象。
單擊切片。它將提示一個提示,我們將切片類型保持為Automatic,然後單擊菜單中的Slice。最後一步是單擊Apply。
靜態圖像示例:
我們回到Unity3D的標準UI。tank_spritesheetRetina下的subsprite中有許多單獨的sprite 。我們將使用tanks_spritesheetRetina_0。
將我們想要使用的精靈拖到場景視圖上。x位置應為-7.91,y位置應為0.75。
單擊添加組件,我們要添加的組件是Line Renderer。該行渲染器位於效應。
創建一個名為TwoDRayCasting的腳本並將其附加到tank對象。確保“ 線條渲染器”的寬度為0.25
現在,我們可以編寫代碼了。
using System.Collections;
using UnityEngine;
public class TwoDRayCasting : MonoBehaviour
{
LineRenderer line;
private void Start()
{
line = gameObject.GetComponent<LineRenderer>();
line.enabled = false;
}
private void Update()
{
if (Input.GetButtonDown("Fire1"))
{
StopCoroutine("fireLazer");
StartCoroutine("fireLazer");
}
}
private IEnumerator fireLazer()
{
line.enabled = true;
while (Input.GetButton("Fire1"))
{
line.SetPosition(0, new Vector3(transform.position.x + .92f, transform.position.y + 0.41f));
line.SetPosition(1, new Vector3(transform.position.x + 10f, transform.position.y + 0.41f));
yield return null;
}
line.enabled = false;
}
}
讓我們剖析代碼,使其更容易理解。
// This allows us to access the Line Renderer component
LineRenderer line;
private void Start()
{
// Since the Line Renderer is a private object, we should make //sure we can access the component later on. So get the //component to be safe.
line = gameObject.GetComponent<LineRenderer>();
// We want the LineRenderer to be false to manually manipulate //when it is turned on and off.
line.enabled = false;
}
private IEnumerator fireLazer()
{
// set the line to be enabled at the start of the method.
line.enabled = true;
// we want this code to only work while the condition is true.
// In this case it is the built in Mouse 0 click event.
while (Input.GetButton("Fire1"))
{
// Set position for the line. It takes an index and Vector3 position.
// We set the index to be 0 since it is the first one in the array.
// We set the vector 3 to be the tank's x and y position + an offset.
// Since we are working in 2D, we don't need a value for Z so it is assumed
// to be 0.
line.SetPosition(0, new Vector3(transform.position.x + .92f, transform.position.y + 0.41f));
line.SetPosition(1, new Vector3(transform.position.x + 10f, transform.position.y + 0.41f));
// next we yield return. Why? Because it works differently from the standard way in C#.
// The yield statement is a special kind of return, that ensures that the function will continue from the line after the yield statement next time it is called.
yield return null;
}
// next we disable the line again.
line.enabled = false;
}
private void Update()
{
// We only want the line to render when the fire button is pressed.
if (Input.GetButtonDown("Fire1"))
{
// check to be sure the line is not on and turn if off if it is
StopCoroutine("fireLazer");
// turn on the line.
StartCoroutine("fireLazer");
}
}
按播放按鈕並試用。要控制激光,請按鼠標左鍵。
2D動畫示例:
接下來,我們將創建一個可怕的動畫並用它進行Raycasting。多次點擊圖像編號0,1,5和6; 將其拖到畫布上。它將打開一個保存提示。我將名稱保留為New Animation並將其保存到2D Art文件夾中。
新槽的位置應為-7.91,-0.3,0。添加Line Renderer組件並將線渲染器的寬度更改為0.25。
像之前一樣將腳本附加到坦克。
運行它,準備動畫中的癲癇發作。
3D渲染
現在我們可以進入我知道你們一直在耐心等待3D Raycasting的部分。這個有點複雜,但不是那麼複雜。我將繼續進行Raycasting,就好像你正在建造一個帶有射擊技巧的側面滾動平台遊戲和一個第一人稱射擊遊戲,你在那裡拍攝爆炸,就像你建造的漫畫書/動漫英雄遊戲一樣。
首先在斬波塊上我們將為側滾動和第一人稱模式編寫腳本。我知道這是我正常工作方式的變化,它將使顯示附加空遊戲對象和適當實例化渲染器的平凡任務變得更加容易。
腳本:
側滾動腳本
側滾動腳本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ThreeDRayCastingSideScrollMode : MonoBehaviour
{
LineRenderer line;
private void Start()
{
line = gameObject.GetComponent<LineRenderer>();
line.enabled = false;
}
private IEnumerator fireShot()
{
line.enabled = true;
while (Input.GetButton("Fire1"))
{
Ray ray = new Ray(transform.position, transform.right);
line.SetPosition(0, ray.origin);
line.SetPosition(1, ray.GetPoint(-10) * .24f);
yield return null;
}
line.enabled = false;
}
private void Update()
{
if (Input.GetButtonDown("Fire1"))
{
StopCoroutine("fireShot");
StartCoroutine("fireShot");
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ThreeDRayCastingSideScrollMode : MonoBehaviour
{
LineRenderer line;
private void Start()
{
line = gameObject.GetComponent<LineRenderer>();
line.enabled = false;
}
private IEnumerator fireShot()
{
line.enabled = true;
while (Input.GetButton("Fire1"))
{
Ray ray = new Ray(transform.position, transform.right);
line.SetPosition(0, ray.origin);
line.SetPosition(1, ray.GetPoint(-10) * .24f);
yield return null;
}
line.enabled = false;
}
private void Update()
{
if (Input.GetButtonDown("Fire1"))
{
StopCoroutine("fireShot");
StartCoroutine("fireShot");
}
}
}
請注意,此腳本與2D腳本之間的唯一區別是我們在與2D版本不同的上下文中使用SetPosition。讓我們仔細看看我們正在做什麼。
Ray ray = new Ray(transform.position, transform.right);
Ray ray = new Ray(transform.position, transform.right);
line.SetPosition(0, ray.origin);
line.SetPosition(1, ray.GetPoint(-10) * .24f);
ray.origin是射線起源的點。
ray.GetPoint沿途返回一個距離單位的點。
我們將Ray設置為基於我們附加到的對象的變換位置,並且方向是附加對像變換的右側。我們將數組的第一個元素設置為光線的原點。我們將光線的第二個元素設置為特定點乘以任意數,以便根據模型和位置的位置處理曲線。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ThreeDRayCastingFirstPersonMode : MonoBehaviour
{
LineRenderer line;
private void Start()
{
line = gameObject.GetComponent<LineRenderer>();
line.enabled = false;
}
private IEnumerator fireShot()
{
line.enabled = true;
while (Input.GetButton("Fire1"))
{
Ray ray = new Ray(transform.position, Vector3.forward);
line.SetPosition(0, ray.origin);
line.SetPosition(1, ray.GetPoint(100));
yield return null;
}
line.enabled = false;
}
private void Update()
{
if (Input.GetButtonDown("Fire1"))
{
StopCoroutine("fireShot");
StartCoroutine("fireShot");
}
}
}
接下來我們有fps腳本,它適用於第1 /第3 /自上而下的視圖。
Ray ray = new Ray(transform.position, Vector3.forward);
line.SetPosition(1, ray.GetPoint(100));
我們還將光線設置為基於它所附著的對象的變換的位置,並且我們還將方向設置為向前。我們只需要將該點設置為距離原點100個距離單位。
哇,既然所有這一切都已經完成,我們就可以開始構建場景了。
側滾動場景
免責聲明:我已經創建了一個預製件,它已經將模型從T-pose修改為我們想要用於本課程這一部分的姿勢。接下來的另一課將更深入地討論Unity中的3D模型動畫以及如何構建它們。
首先,創建一個名為3DSideScroll的新場景。
對於此示例,主攝像機應處於透視模式,位置為0,0.33,-3.38。雖然你可以而且應該做正交模式。
現在我們將為課程的這一部分導入的預製件導入到場景中。
她的位置應該是-3.26,-1.15,0。她的輪換應該是0,75,0。
將ThreeDRayCastingSideScrollMode腳本添加到角色。我導航到角色的層次結構,一直到右手。
這是有趣的部分,為角色添加了一個線條渲染器。確保未選中行渲染器的框。正好在腳本所附的位置是我將附加渲染器的位置。確保線條渲染器的寬度為0.05(儘管您可以使用寬度,直到找到您更喜歡的寬度)。
我將Line Renderer和Script放在預製件的右側,因為這是我希望線渲染器遵循的軌跡。您可以非常輕鬆地將線條渲染器放在您選擇的位置的空遊戲對像中,並完成相同的專長。我這樣做的方式允許引擎找到線條渲染器的起點位於角色位置的位置,而無需額外的代碼。
您現在可以自己運行場景並進行測試。
3D場景
在這個例子中,我將在肩部視圖中做第一人稱和第三人。
肩膀上的第三人稱
讓我們從肩膀上的第三人開始。這樣做的原因是因為我們真正需要做的就是將這一個修改為第一個人,這實際上是改變角色模型的位置。
同樣,我已經創建了模型的預製件,因為我使用Unity中的關節將其從T Pose更改為我想要的姿勢。
加載3D場景以開始使用。
將預製件添加到場景中並將模型的位置設置為-0.22,-1.36,0。
再次,我將Line Renderer的寬度為0.15,將ThreeDRayCasting腳本添加到Model的層次結構中的右手索引1。
您現在可以自己運行場景並進行測試。對於3D第三人而言,肩膀上的觀點並不是太難了嗎?現在,讓我們轉到第一人稱視角。
第一人稱視角
真的,第三人在肩膀視圖和第一人稱視角之間的唯一區別實際上是角色的位置和相機本身的一個非常小的變化。
要開始使用,請導航到主攝像頭。將剪切平面更改為0.12。
接下來,我們改變模型的位置。你可以玩它直到你找到你喜歡的東西,我去了一個簡單的0,-0.28,-3.44。它有舊學校的FPS感覺它的外觀,沒有UI的東西或在這個例子中沒有槍的事實。
您現在可以自己運行場景並進行測試。
最後的想法
如您所見,創建Line Renderers是一項非常簡單的任務,可以相當快速有效地完成。這些可以取代粒子效應並充當激光束,激光步槍等等。它們在物理和其他效果方面非常有效。
總而言之,我認為向你展示一些你可以用Line Renderers做的非常小的事情是非常值得的,因為你永遠不知道,你可能在將來的某個時候需要它們。
我希望本教程能幫助你學習新東西,下次我會再見到你。願你的代碼乾淨無bug。我會在下一個教程中找到你。