現(xiàn)在呢我們來搞一下防御塔對(duì)怪物的檢測邏輯。
首先呢胀茵,我想到了觸發(fā)器檢測琼娘,并配以一條列表儲(chǔ)存在該防御塔射程內(nèi)的所有敵人附鸽。
那么我們來建一個(gè)CheckEnemy腳本,用來監(jiān)測敵人熄浓,跟隨注視并攻擊省撑。
話不多說竟秫,貼上代碼先:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CheckEnemy : MonoBehaviour {
/// <summary>
/// 炮塔價(jià)格
/// </summary>
public float value = 100;
/// <summary>
/// 開火頻率
/// </summary>
public int firewaittime = 2;
/// <summary>
/// 臨時(shí)ID肥败,測試
/// </summary>
public int idi = 0;
/// <summary>
/// 炮塔轉(zhuǎn)動(dòng)速度
/// </summary>
public float turnSpeed = 2;
/// <summary>
/// 最遠(yuǎn)攻擊距離
/// </summary>
public float disFire = 12;
/// <summary>
/// 是否有正在攻擊的目標(biāo)
/// </summary>
private bool isAlarm;
/// <summary>
/// 子彈
/// </summary>
public GameObject ziDan;
/// <summary>
/// 子彈生成位置
/// </summary>
public Transform firePos;
/// <summary>
/// 攻擊目標(biāo)
/// </summary>
private Transform targetEnemy;
/// <summary>
/// 存儲(chǔ)所有檢測到的敵人
/// </summary>
private List<Transform> enemyList;
/// <summary>
/// 開火的協(xié)程是否開啟
/// </summary>
private bool isFire = false;
private Input_Key ik;
void Start ()
{
enemyList = new List<Transform>();
}
void Update () {
//攻擊隊(duì)列里有敵人
if (enemyList.Count != 0)
{
if (enemyList[0] == null)
{
enemyList[0] = enemyList[1];
enemyList.Remove(enemyList[1]);
}
else
{
if (!isFire)
{
isFire = true;
StartCoroutine("Fire");
}
//瞄準(zhǔn)敵人
//transform.LookAt(enemyList[0]);
Vector3 direction = enemyList[0].position - transform.position;
Quaternion qua = Quaternion.LookRotation(direction);
transform.rotation = Quaternion.Lerp(transform.rotation, qua, Time.deltaTime * turnSpeed);
////如果敵人脫離攻擊范圍,或者死亡
if (Vector3.Distance(transform.position, enemyList[0].position) > disFire || enemyList[0].GetComponent<EnemyContrl>().Blood <= 0)
{
enemyList.Remove(enemyList[0]);
}
}
}
else
{
if (isFire)
{
StopCoroutine("Fire");
isFire = false;
}
}
}
/// <summary>
/// 檢測觸發(fā)物是否為敵人,是的話放入攻擊列表
/// </summary>
void OnTriggerEnter(Collider other)
{
//可以改成檢測空中和地上
if (other.transform.tag == "Enemy"||other.transform.tag == "FlyEnemy")
{
if (!enemyList.Contains(other.transform)) {
enemyList.Add(other.transform);
}
}
}
/// <summary>
/// 炮塔射擊敵人
/// </summary>
IEnumerator Fire() {
while (true) {
if (enemyList.Count != 0 && enemyList[0] != null)
{
//生成子彈并指定發(fā)射的目標(biāo)
GameObject go = Instantiate<GameObject>(ziDan, firePos.transform.position, firePos.transform.rotation);
go.GetComponent<ZhaDan>().target = enemyList[0];
}
else if (enemyList[0] == null) {
enemyList.Remove(enemyList[0]);
}
yield return new WaitForSeconds(firewaittime);
}
}
}
這里有一小點(diǎn):如果不寫下面的這個(gè)就會(huì)出現(xiàn)n座塔同時(shí)攻擊有一個(gè)目標(biāo),怪物被其中一座塔收走人頭往史,其他以該怪物為目標(biāo)的塔就會(huì)丟失目標(biāo)而啞火。
if (enemyList[0] == null)
{
enemyList[0] = enemyList[1];
enemyList.Remove(enemyList[1]);
}
為了改正這個(gè)bug挨决,我一開始是想直接在enemyList[0] = null時(shí)enemyList.Remove(enemyList[0])脖祈,但是不知道為什么還是會(huì)出錯(cuò)刷晋,所以我就改成把enemyList[1]提前一個(gè)單位,并enemyList.Remove(enemyList[1])喻奥,這樣就好使了捏悬,坑爹啊,各位大神如果知道原因請(qǐng)?jiān)谠u(píng)論區(qū)賜教貪狼感激不盡甥厦。
然后我們迎來了本游戲的重頭戲“防御塔”攻擊方式——彈藥寇钉。我分成了三大類:1.單體攻擊類,2.范圍攻擊類。而這兩類又可以分別派生出對(duì)地類谦秧,對(duì)空類甚至減速buff這種buff類
首先油够,我們來看看單體攻擊類:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour {
public float damageValue = 25f;
/// <summary>
/// 攻擊目標(biāo)
/// </summary>
public Transform target;
/// <summary>
/// 子彈發(fā)射速度
/// </summary>
public float speed = 10f;
void Update ()
{
if (target&&target!=null)
{
transform.position = Vector3.MoveTowards(transform.position, target.transform.position+new Vector3(0,1.5f,0), speed * Time.deltaTime);
}
//丟失目標(biāo)
else {
Destroy(transform.gameObject);
}
}
//此處為對(duì)地對(duì)空雙功能征懈,你可以改成單一功能
void OnTriggerEnter(Collider other) {
if (other.transform.tag == "Enemy"|| other.transform.tag == "FlyEnemy") {
other.GetComponent<EnemyContrl>().EnemyHurt(damageValue);
Destroy(this.gameObject);
}
}
}
然后是范圍傷害類:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ZhaDan : MonoBehaviour {
public float DamageOffeset;
public float damageValue;
/// <summary>
/// 攻擊目標(biāo)
/// </summary>
public Transform target;
/// <summary>
/// 子彈發(fā)射速度
/// </summary>
public float speed = 10f;
// Use this for initialization
/// <summary>
/// AOE半徑
/// </summary>
public float r = 1f;
void Start()
{
}
void Update()
{
if (target.GetComponent<CapsuleCollider>() !=null)
{
if (transform.tag != "Ice")
{
transform.position = Vector3.MoveTowards(transform.position, target.transform.position + new Vector3(0, 2.5f, 0), speed * Time.deltaTime);
}
else {
transform.position = Vector3.MoveTowards(transform.position, target.transform.position + new Vector3(0, 0.1f, 0), speed * Time.deltaTime);
}
}
else
{
Destroy(transform.gameObject);
}
}
void OnTriggerEnter(Collider other)
{
if (other.transform.tag == "Enemy")
{
Grenade_AOE_Damage(transform, r, damageValue);
}
}
void Grenade_AOE_Damage(Transform _grenade, float _AOE_radius, float _damage)
{
//獲取手雷_AOE_radius范圍內(nèi)所有的碰撞體(敵人)
Collider[] colliders = Physics.OverlapSphere(_grenade.position, _AOE_radius);
//遍歷范圍內(nèi)所有敵人并給予傷害
for (int i = 0; i < colliders.Length; i++)
{
bool isCap = colliders[i].GetType() == (typeof(CapsuleCollider));
if (isCap && (colliders[i].gameObject.tag=="Enemy"))
{
//判斷距離中心爆炸點(diǎn)距離鬼悠,并實(shí)現(xiàn)傷害衰減
float dis = Vector3.Distance(colliders[i].transform.position, _grenade.position);
float dam = _damage - dis * DamageOffeset;
//加上特效
//獲取生命腳本組件,調(diào)用傷害函數(shù)
colliders[i].gameObject.GetComponent<EnemyContrl>().EnemyHurt(dam);
}
}
StartCoroutine(Boom());
}
IEnumerator Boom() {
transform.GetComponent<MeshRenderer>().enabled = false;
GameObject go;
if (transform.tag == "Bomb")
{
go = Instantiate<GameObject>((GameObject)Resources.Load("fireball/Boom/Prefabs/Bomb"), transform.position, transform.rotation);
} else if (transform.tag == "Ice") {
go = Instantiate<GameObject>((GameObject)Resources.Load("fireball/IceEffect/Prefabs/Fx/IceGo"), transform.position, transform.rotation);
}
else {
go = null;
}
yield return new WaitForSeconds(0.8f);
Destroy(this.gameObject);
if (go != null) {
Destroy(go);
}
}
}
然后我們上網(wǎng)下載一個(gè)冰霜特效和爆炸特效蹬挺,可以增加真實(shí)感它掂,并在冰霜特效上掛載腳本控制減速協(xié)程:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class IceBullet : MonoBehaviour {
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter(Collider other) {
if (other.transform.tag == "Enemy" && other.transform.GetComponent<NavMeshAgent>())
{
other.transform.GetComponent<EnemyContrl>().DealSpeed();
}
}
}
這時(shí)虐秋,我們需要在EnemyContrl腳本及加些“零件”:
private bool isLowSpeed = false;
public void DealSpeed() {
if (isLowSpeed)
{
return;
}
else {
isLowSpeed = true;
StartCoroutine(LowSpeed());
}
}
IEnumerator LowSpeed() {
transform.GetComponent<NavMeshAgent>().speed /= 2;
yield return new WaitForSeconds(2.5f);
if(transform.GetComponent<NavMeshAgent>())
transform.GetComponent<NavMeshAgent>().speed *= 2;
![Uploading IS}]3IW`}1{XXX_(8YB{98F_078727.png . . .]
isLowSpeed = false;
}
其中isLowSpeed是為了防止同一怪物被反復(fù)減速客给,然后可以將減速幅度設(shè)為public類型,以便想要防御塔升級(jí)時(shí)加大減速幅度的朋友控制蜻拨。
另外還有激光槍桩引,噴火筒兩種,這里我將粒子特效掛在槍口休涤,并為粒子特效增加碰撞器笛辟,使其只檢測Enemy層敵人序苏。
然后有兩種思路忱详,第一種是在CheckEnemy時(shí),判斷自己是否是激光槍监透,噴火筒(tag=“strong”)
然后監(jiān)測到敵人就向目標(biāo)放“特效”(用ParticleSystem my_PS航唆;my_PS.Stop();my_PS.Play();)控制。然后通過粒子碰撞器粪狼,將碰到的敵人扣除血量(可以用OnParticleCollisionStay判斷)。
第二種思路是我們偷懶想出的辦法再榄,特效照開不誤,但是用“隱形的”子彈和炮彈(激光單體嗅蔬,噴火群體)以很快的速度攻擊怪物(哈哈這樣就可以用舊代碼實(shí)現(xiàn)新功能了疾就,我好懶)。