筆記29 導航系統項目聯繫:塔防遊戲
場景(起始點、終點)、敵人+代碼
代碼:終點EndControl
//如果進入觸發區域
private void OnTriggerEnter(Collider other)
{
//如果是敵人
if(other.tag == "Enemy")
{
//TODO:減血
UIControl.Instance.AddHp(-1);
//銷燬敵人
Destroy(other.gameObject);
}
}
代碼:敵人EnemyControl
using UnityEngine.AI;
public class EnemyControl : MonoBehaviour
{
// 血量
public int Hp = 100;
//死亡後,獎勵10元。
public int Money = 10;
//拿到導航組件,因爲這個組件是在AI名稱空間裏的,所以需要添加using UnityEngine.AI;
private NavMeshAgent agent;
//拿到終點的位置。因爲導航最終是導向那裏
private Transform End;
void Start()
{
//在這裏得到
//由於這裏物體比較少,所以直接尋找
End = GameObject.Find("End").transform;
//獲取導航
agent = GetComponent<NavMeshAgent>();
//導航到終點的位置
agent.SetDestination(End.position);
}
//受到攻擊。attack是傷害值,後期會傳進來。
public void GetHit(int attack)
{
//掉血。
Hp -= attack;
if(Hp<= 0)
{
//錢數增加10元
UIControl.Instance.AddMoney(Money);
//銷燬自己
Destroy(gameObject);
}
}
起始點+代碼StartControl
//拿到怪物的預設體,因爲怪物不止一種,所以用數組
public GameObject[] Enemy;
//出怪的間隔時間
public float EnemySpawnCD = 1f;
//一波怪的數量
public int EnemyCount = 10;
//每波怪之間的間隔時間
public float EnemyTimer = 5f;
//以下這些不用開放給外界
//當前怪的個數
private int count = 0;
//當前的第幾波怪
private int index = 0;
//計時器
private float timer = 0;
void Start()
{
//起初當前怪的數量等於一波怪的數量
count = EnemyCount;
}
void Update()
{
//如果當前怪物波數超出索引,退出
if(index >= Enemy.Length)
{
return;
}
//計時器計時
timer += Time.deltaTime;
//如果計時器到時,產生怪物
if(timer > EnemySpawnCD)
{
if(count > 0)
{
//產生當前的怪物。實例化(索引,位置,旋轉)
Instantiate(Enemy[index], transform.position, transform.rotation);
//待實例化的怪的數量在實例化後,減少
count--;
//計時器重置
timer = 0;
}
else
{
//該下一波怪了
//首先數量恢復
count = EnemyCount;
//波數增加
index++;
//EnemyTimer每波怪之間的間隔時間,默認是5秒。
//此處計時器直接等於 -5,那就直接再去計時timer += Time.deltaTime;
timer = -EnemyTimer;
}
}
}
代碼:子彈BulletControl
創建子彈,添加腳本。子彈設置爲觸發,關聯子彈的“目標敵人”。
// 目標敵人(會盯住敵人攻擊)
public EnemyControl TargetEnemy;
//威力。
public int Attack = 40;
//速度
public float Speed = 5f;
void Start()
{
}
void Update()
{
//像這種有目標的( 此處,有目標敵人),上來要做“非空判斷”。
if(TargetEnemy == null)
{
//銷燬。就是說,比如左右兩發子彈同時都攻擊一個目標,當第一顆子彈已經把目標炸燬了,那麼第二顆,就自己銷燬。
Destroy(gameObject);
return;
}
//朝向敵人的向量:目標點的位置-我的位置
Vector3 dir = TargetEnemy.transform.position - transform.position;
//朝目標走過去(方向*速度*單位轉換成每秒)
transform.Translate(dir * Speed * Time.deltaTime);
//擊中敵人。(判斷子彈和目標的距離,如果小於0.5米,就算擊中敵人了)
if (Vector3.Distance(TargetEnemy.transform.position, transform.position) < 0.5f)
{
//調用敵人腳本里受到傷害的方法。把傷害值40傳回去
TargetEnemy.GetHit(Attack);
//銷燬
Destroy(gameObject);
}
}
防禦塔+代碼BatteryControl
//子彈預設體
public GameObject BulletPre;
//攻擊間隔,此處,半秒打一發子彈
public float FireCD = 0.5f;
//攻擊力
public int Attack = 40;
//價格。默認50元
public static int Money = 50;
//計時器
private float timer = 0;
//原理:每個炮臺將能打到的敵人保存在一個列表,然後就盯着第一個敵人目標打。
//攻擊列表。因爲能打到的目標敵人是在會變化的,所以使用動態列表List
private List<EnemyControl> Enemys;
void Start()
{
//實例化
Enemys = new List<EnemyControl>();
}
void Update()
{
//計時器
timer += Time.deltaTime;
//遍歷,如果有敵人死亡了,就將其從攻擊列表中移除
for (int i = 0; i<Enemys.Count; i++)
{
EnemyControl enemy = Enemys[i];
if (enemy == null)
{
Enemys.Remove(enemy);
}
}
//如果敵人屬於攻擊列表,並且到達攻擊間隔
if (Enemys.Count > 0 && timer>FireCD)
{
//攻擊
//需要實例化子彈,並得到子彈的腳本。返回值(子彈的腳本) = 實例化(什麼東西,位置,旋轉).得到子彈的腳本
BulletControl bc = Instantiate(BulletPre, transform.position + Vector3.up, Quaternion.identity).GetComponent<BulletControl>();
//給子彈設定攻擊目標:數組裏的第一個
bc.TargetEnemy = Enemys[0];
//攻擊力。子彈的攻擊力等於防禦塔的攻擊力。此處,子彈的默認攻擊力就無效了。
bc.Attack = Attack;
//重置時間(如果沒有重置時間,只會發射一顆子彈)
timer = 0;
}
}
//如果有敵人進入到攻擊區域
private void OnTriggerEnter(Collider other)
{
if(other.tag == "Enemy")
{
//往列表裏添加敵人,得到它身上EnemyControl這個腳本
Enemys.Add(other.GetComponent<EnemyControl>());
}
}
//如果有敵人離開攻擊區域
private void OnTriggerExit(Collider other)
{
if (other.tag == "Enemy")
{
//移除
Enemys.Remove(other.GetComponent<EnemyControl>());
}
}
臺階+代碼CubeControl
//防禦塔(炮臺)預設體
public GameObject BatteryPre;
void Start()
{
}
//鼠標進入
private void OnMouseEnter()
{
//給Cube改顏色。拿到渲染組件.修改它裏面材質.顏色 = 新顏色
GetComponent<MeshRenderer>().material.color = Color.green;
}
//鼠標離開
private void OnMouseExit()
{
//改回原色。即新顏色爲白色
GetComponent<MeshRenderer>().material.color = Color.white;
}
//注意:鼠標操作,第一種用回調;第二種用射線(鼠標點的位置,想屏幕裏打一條射線,打在哪個Cube上,就在哪個上創建。
//第一種:當鼠標在它上面按下的時候
private void OnMouseDown()
{
//如果我身上的子節點爲零,說明身上沒有防禦塔。
//並且,能夠花費購買該防禦塔所需的費用。如果能花,返回值爲true;否則爲false。
if (transform.childCount == 0 && UIControl.Instance.GetMoney(BatteryControl.Money))
{
//實例化(創建防禦塔)。+ Vector3.up是將其位置向上提了一點
Instantiate(BatteryPre, transform.position + Vector3.up, Quaternion.identity);
}
}
金錢、生命值+代碼UIControl
//寫成單例
public static UIControl Instance;
//錢數。添加名稱空間using UnityEngine.UI;
public Text MoneyText;
//生命值???
public Text HpText;
//金錢,默認60
private int money = 60;
//生命值
private int Hp = 10;
void Awake()
{
//單例……
Instance = this;
}
// 添加金錢(消滅敵人得金錢,敵人代碼)
public void AddMoney(int money)
{
this.money += money;
//刷新文本
MoneyText.text = this.money + "";
}
//消耗金錢。返回的不是void,而是布爾值。(添加防禦塔,消耗金錢。防禦塔代碼)
public bool GetMoney(int money)
{
//如果擁有的錢大於等於防禦塔的價格
if (this.money >= money)
{
this.money -= money;
//刷新文本
MoneyText.text = this.money + "";
//返回true
return true;
}
//否則就返回false,說明消耗失敗了
return false;
}
//添加生命值
public void AddHp(int hp)
{
Hp += hp;
//刷新文本
HpText.text = this.Hp + "";
}
完善