Unity_FPS遊戲中設定子彈軌跡和紅外線瞄準
轉載自:2016-08-16 Unity官方
本教程適合Unity新手或對Raycast不甚瞭解的開發者,主要介紹Raycast的用途並繪製出射擊遊戲的射線軌跡。
本篇主要寫子彈射擊軌跡 紅外線瞄準可以參考相關的引數設定
最終效果
本課程包括滑鼠控制相機旋轉、射擊物體、顯示射線軌跡及準星三個部分,最終實現效果如下:
在講解實現步驟之前,先來了解Raycast的概念。Raycast可以簡單理解為遊戲場景中由某點發出的隱形射線,它能返回所有被射線射中的遊戲物件的詳細資訊及RaycastHit結構體,RaycastHit結構體包括該遊戲物件的Transform引用和射線與遊戲物件交點的座標等等。這裡需要注意的是,只有帶有碰撞體的遊戲物件才能被射線檢測到。
想了解更多關於Raycast及RaycastHit的資訊,請檢視Recast及RaycastHit。
另外要注意的是,在FPS遊戲中,射擊目標通常都是玩家眼睛朝向的位置,也就是相機正前方的中心點。所以這裡瞄準物體並進行碰撞檢測的射線並非我們需要繪製的射擊軌跡。
下面就來為大家講解實現步驟。
第一步 準備工作
首先下載本課程所需的工程資源並匯入Unity專案中:
找到Let’s Try Shooter > Scenes資料夾下的ShootingWithRaycasts場景並雙擊開啟。其中已經設定好了本課程所需的遊戲環境,FPSController來自Unity自帶的Standard Assets資源包,下面新增了Gun遊戲物件:
第二步 新增射擊指令碼
下面來新增射擊指令碼。在Scripts目錄下新建C#指令碼命名為RaycastShoot,將該指令碼拖拽至層級檢視的Gun遊戲物件上,然後雙擊指令碼進行編輯。RaycastShoot指令碼的主要作用是發出射線,射擊物體並造成傷害,播放射擊音效,顯示射擊軌跡並等待一段時間後消失。指令碼程式碼如下:
using UnityEngine;
using System.Collections;
public class RaycastShoot : MonoBehaviour {
// 設定槍擊帶來的傷害值
public int gunDamage = 1 ;
// 設定兩次槍擊的間隔時間
public float fireRate = 0.25f;
// 設定玩家可以射擊的Unity單位
public float weaponRange = 50f;
// 設定槍擊為物體帶來的衝擊力
public float hitForce = 100f;
// GunEnd遊戲物件
public Transform gunEnd;
// FPS相機
private Camera fpsCam;
// 設定射擊軌跡顯示的時間
private WaitForSeconds shotDuration = new WaitForSeconds(0.07f);
// 槍擊音效
private AudioSource gunAudio;
// 射擊軌跡
private LineRenderer laserLine;
// 玩家上次射擊後的間隔時間
private float nextFire;
void Start ()
{
// 獲取LineRenderer元件
laserLine = GetComponent<LineRenderer>();
// 獲取AudioSource元件
gunAudio = GetComponent<AudioSource>();
// 獲取Camera元件
fpsCam = GetComponentInParent<Camera>();
}
void Update ()
{
// 檢測是否按下射擊鍵以及射擊間隔時間是否足夠
if (Input.GetButtonDown("Fire1") && Time.time > nextFire)
{
// 射擊之後更新間隔時間
nextFire = Time.time + fireRate;
// 啟用ShotEffect攜程控制射線顯示及隱藏
StartCoroutine (ShotEffect());
// 在相機視口中心建立向量
Vector3 rayOrigin = fpsCam.ViewportToWorldPoint (new Vector3(0.5f, 0.5f, 0.0f));
// 宣告RaycastHit儲存射線射中的物件資訊
RaycastHit hit;
// 將射擊軌跡起點設定為GunEnd物件的位置
laserLine.SetPosition (0, gunEnd.position);
// 檢測射線是否碰撞到物件
if (Physics.Raycast (rayOrigin, fpsCam.transform.forward, out hit, weaponRange))
{
// 將射擊軌跡終點設定為碰撞發生的位置
laserLine.SetPosition (1, hit.point);
// 獲取被射中物件上的ShootableBox元件
ShootableBox health = hit.collider.GetComponent<ShootableBox>();
// 如果元件存在
if (health != null)
{
// 呼叫元件的Damage函式計算傷害
health.Damage (gunDamage);
}
// 檢測被射中的物件是否存在rigidbody元件
if (hit.rigidbody != null)
{
// 為被射中的物件新增作用力
hit.rigidbody.AddForce (-hit.normal * hitForce);
}
}
else{
// 如果未射中任何物件,則將射擊軌跡終點設為相機前方的武器射程最大距離處
laserLine.SetPosition (1, rayOrigin + (fpsCam.transform.forward * weaponRange));
}
}
}
private IEnumerator ShotEffect()
{
// 播放音效
gunAudio.Play ();
// 顯示射擊軌跡
laserLine.enabled = true;
// 等待0.07秒
yield return shotDuration;
// 等待結束後隱藏軌跡
laserLine.enabled = false;
}
}
注意,射線應該從玩家眼睛所處位置向眼鏡前方射出,玩家眼睛即相機所在位置。
上述程式碼涉及到還未新增的指令碼與遊戲物件,下面的步驟將一一說明。
第三步 新增LineRenderer元件
為Gun遊戲物件新增LineRenderer元件,用於在執行時的遊戲檢視中繪製出射擊軌跡,只有子彈發出時才會顯示軌跡,所以預設是隱藏的,取消勾選元件名左側的複選框隱藏元件。另外這裡並未指定材質,所以繪製出來的射線會是粉紅色的,你也可以自行新增材質。
第四步 建立GunEnd
這裡需要一個空的遊戲物件作為槍頭處的位置標記,在層級檢視中選中Gun遊戲物件,右鍵單擊在彈出選單中選擇Create Empty新建遊戲物件,重新命名為GunEnd。為GunEnd新增標籤以便在場景中顯示更明顯,然後調整GunEnd的座標至槍頭處,這裡設定為(0.36, -0.18, 1):
將建立好的GunEnd遊戲物件拖拽至Gun物件的RaycastShoot指令碼的GunEnd欄位。
第五步 新增RayViewer指令碼
上面提到了,瞄準物體並進行碰撞檢測的射線並非我們需要繪製的射擊軌跡。需要繪製的射擊軌跡已經在RaycastShoot指令碼中完成了,接下來新增RayViewer指令碼,使用Debug功能在場景中繪製用於瞄準的射線,也就是從相機位置發出的射線。
新建C#指令碼重新命名為RayViewer,將指令碼拖拽至Gun遊戲物件上,雙擊指令碼進行編輯。RayViewer指令碼程式碼如下:
using UnityEngine;
using System.Collections;
public class RayViewer : MonoBehaviour {
// Debug.DrawRay繪製的Unity單位
public float weaponRange = 50f;
// FPS相機
private Camera fpsCam;
void Start ()
{
// 獲取Camera元件
fpsCam = GetComponentInParent<Camera>();
}
void Update ()
{
// 建立相機位置至視口中心點的向量
Vector3 lineOrigin = fpsCam.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, 0.0f));
// 在場景檢視中繪製lineOrigin到相機前方武器射程處的射線
Debug.DrawRay(lineOrigin, fpsCam.transform.forward * weaponRange, Color.green);
}
}
到此射線的處理與繪製就差不多了,執行場景會看到場景檢視出現了兩條射線:
找到層級檢視中Environment > Targets下,有兩個TargetBox物件,選中物件會發現上面已經綁定了ShootableBox指令碼。ShootableBox指令碼的功能非常簡單,CurrentHealth表示物件當前血量,初始總血量為3,指令碼程式碼如下:
using UnityEngine;
using System.Collections;
public class ShootableBox : MonoBehaviour {
// 總血量
public int currentHealth = 3;
public void Damage(int damageAmount)
{
// 呼叫Damage時總血量要減去傷害值
currentHealth -= damageAmount;
// 檢測總血量是否小於等於0
if (currentHealth <= 0)
{
// 隱藏物件
gameObject.SetActive (false);
}
}
}
在上方的RaycastShoot指令碼中已經添加了射擊處理的邏輯,當射中立方體時,此時執行場景,已經可以進行射擊了,但還是比較難進行瞄準。下面來新增準星。
第六步 新增UI
在層級檢視右鍵單擊,彈出選單中依次選擇UI > Image新建Image,點選Color右邊的顏色選取按鈕,將Image的顏色設定為紅色:
然後點選Rect Transform的錨點設定按鈕,按下Alt/Option鍵同時選擇中心點,讓準星永遠出現在螢幕中心位置:
設定好後再次點選執行,大功告成啦!