閒雜:
想玩遊戲的時候就來寫博客,其實我個人的感覺寫博客就跟寫書是一樣的嗎,寫書是將內心的故事呈現給讀者,而寫博客就是將技術呈現給讀者,一方面我們可以將自己的技術分享出來供大家學習,第二個是希望大家可以給我的技術做一些指點,互相學習互相交流,希望能在評論區多多留言,我也可以解決疑難雜症。
故事開始:
在FPS的遊戲開發當中設計到槍械的方面,手雷的方面,近戰武器,以及一些特殊的道具,所以這些模塊值得去深挖和細品,古人云:彩虹風雨後,成功細節中(我也不知道是哪個古人說的)
我的思路,搭建場景,然後給box添加上Rigibody組件(不要給地面也添加該組件,會出現很奇怪的情況,如果想試一試的小夥伴,可以玩一下)
接下來就是Granade,吐槽一下,我的第一版手雷和上面的箱子一樣大,由於太過搞笑所以我就弄了手雷2.0,看起來就舒服多了
接下來就是腳本方面了,我的思路是這樣的,首先是Granade.cs的腳本
- 手雷延時爆炸delay
- 手雷的爆炸半徑
- 手雷的爆炸力度
這三方面考慮好後就可以開始寫腳本了,代碼如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Granade : MonoBehaviour
{
public float delay = 3f;
public float radius = 5f;
public float force = 700f;
public GameObject ExplosionEffect;
public GameObject ExplosionAudio;
float countDown;
bool hasExploaded = false;
void Start()
{
countDown = delay;
}
void Update()
{
countDown -= Time.deltaTime;
if (countDown <= 0f && !hasExploaded)
{
Explode();
hasExploaded = true;
}
}
void Explode()
{
Instantiate(ExplosionEffect, transform.position, transform.rotation);
Instantiate(ExplosionAudio, transform.position, transform.rotation);
//add force to move
//該半徑內的所有碰撞器,返回一個數組
Collider[] collidersToMove = Physics.OverlapSphere(transform.position,radius);
//遍歷球體內的所有Collider
foreach (Collider nearbyObject in collidersToMove)
{
//獲取球體半徑範圍內的rigibody
Rigidbody rb = nearbyObject.GetComponent<Rigidbody>();
if (rb != null)
{
//向模擬爆炸效果的剛體施加力
rb.AddExplosionForce(force,transform.position, radius);
}
}
Destroy(gameObject);
}
//Granade Demage
}
代碼分析:
我在此腳本中用了一個特殊的方法,我們知道,當物體被銷燬的時候,身上的腳本以及組件都被銷燬了,所以不能夠將聲音和爆炸的特效掛載到手雷上面,而是應該單獨做成兩個預製體,接下來在手雷爆炸的時候將這兩個預製體加載出來,這樣就解決了這個辦法。
Instantiate(ExplosionEffect, transform.position, transform.rotation);
Instantiate(ExplosionAudio, transform.position, transform.rotation);
然後給Granade添加爆炸力和爆炸範圍
Collider[] collidersToMove = Physics.OverlapSphere(transform.position,radius);
在官方文檔中,講到了參數和使用方法。我解釋一下返回Collider數組的作用,這裏是將球形範圍內的所有包含Collder組件的物體都存起來,接下來遍歷球體內物體上的Rigibody組件,然後可以給含有該組件的物體添加爆炸力度,爆炸力是手雷來提供的,這樣就實現了手雷爆炸擊飛箱子。
rb.AddExplosionForce(force,transform.position, radius);
Granade的部分就完成了,接下來就是手雷爆炸特效和手雷音效銷燬,回收的階段,我遇到的問題是特效如果不銷燬就會一直常駐內存,而且特效也會重複播放,所以,我就另外寫了一個腳本來專門管理它,DestroyGameObject(名字起的不是很恰當,後期優化)
代碼如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DestroyGameObject : MonoBehaviour
{
public float effectTime = 6f;
public GameObject BigExplosionEffect;
public GameObject GranadeAudio;
float currentDown;
bool hasPerfab = true;
void Start()
{
currentDown = effectTime;
}
void Update()
{
currentDown -= Time.deltaTime;
if (currentDown <= 0 && hasPerfab)
{
if (BigExplosionEffect != null && GranadeAudio != null)
{
currentDown = effectTime;
DestoryExplosinEffect();
DestoryExlosinAudio();
hasPerfab = true;
}
else
{
hasPerfab = false;
}
}
}
void DestoryExplosinEffect()
{
GameObject obj = GameObject.Find("BigExplosionEffect(Clone)");
if (obj != null)
{
Destroy(obj);
}
}
void DestoryExlosinAudio()
{
GameObject obj = GameObject.Find("GranadeAudio(Clone)");
if (obj != null)
{
Destroy(obj);
}
}
}
代碼解釋:
我先定義了一個計時器,由於我的特效和聲音大概是3秒,加上之前的手雷延時爆炸3秒,所以是6秒之後銷燬,這樣寫是比較簡單的,分開控制,方法也是分開寫的,方便後期的管理。
添加了一個控制條件hasPerfab ,控制它只銷毀一次,之前想一次扔好幾個手雷,但是出現了一些小問題(其實問題蠻大的),我下來解決一下,在下回書中我們在講解。然後將其掛載到場景CheckDestory上,如圖
最後是控制手雷的扔出,ThrowerGranade,代碼如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GranadeThrower : MonoBehaviour
{
public float throwerForce = 15f;
public GameObject GranadePrefab;
private AudioSource audioSource;
bool isFirst = true;
void Start()
{
audioSource = GetComponent<AudioSource>();
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
//播放手雷扔出的音效
audioSource.Play();
if (isFirst)
{
ThrowGranade();
isFirst = false;
}
}
}
void ThrowGranade()
{
GameObject granade = Instantiate(GranadePrefab,transform.position, transform.rotation);
Rigidbody rb = granade.GetComponent<Rigidbody>();
rb.AddForce(transform.forward * throwerForce,ForceMode.VelocityChange);
}
}
代碼解釋:
掛載到相機上,按下鼠標左鍵時,添加一個向前的力,這樣手雷就扔出去了,我後期想加上拋物線,後面在改進,這樣就可以實現真正的手雷模擬器(無情)
完整的演示圖: