Unity导航系统项目学习

https://www.bilibili.com/video/BV1Yq4y1S7zJ?p=1&vd_source=9728e0705d582ca9854cb5a50dd17fd8 莫新宇视频地址

usingSystem.Collections;
usingSystem.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
 
public class TowerBuyer : MonoBehaviour {
    //单例脚本,特点只挂一次
    public static TowerBuyer instance;
 
    [Header("炮塔预设体数组")]
    public GameObject[] towerPrefabs;
    [Header("游戏初始金钱")]
    public int currentMoney = 300;
    private int currentTowerIndex;
    //显示金钱文本
    private Text moneyText;
    //游戏速度Toggle
    private Toggle gameSpeedToggle;
    //射线碰撞检测器
    private RaycastHit hit;
    //射线
    private Ray ray;
 
    private void Awake()
    {
        instance = this;
        gameSpeedToggle =transform.GetChild(2).GetComponent<Toggle>();
        moneyText = transform.Find("Coinicon/CoinText").GetComponent<Text>();
    }
 
    private void Start()
    {
       gameSpeedToggle.onValueChanged.AddListener(OnGameSpeedToggleValueChange);
        UpdateMoney();
    }
 
    public void UpdateMoney() {
        moneyText.text =currentMoney.ToString();
    }
 
    public void OnGameSpeedToggleValueChange(bool val) {
        if (val)
        {
            Time.timeScale = 2;
        }
        else {
            Time.timeScale = 1;
        }
    }
 
 
    private void Update()
    {
        //将鼠标坐标转换成射线
        ray =Camera.main.ScreenPointToRay(Input.mousePosition);
 
        if (Input.GetMouseButtonDown(0) &&Physics.Raycast(ray, out hit)) {
            if (!hit.collider.name.Contains("TowerBase")) {
                return;
            }
 
            TowercrtTowerPrefab=towerPrefabs[currentTowerIndex].GetComponent<Tower>();
            //如果钱不够
            if (currentMoney < crtTowerPrefab.towerCost){
                Debug.Log("钱不够!!!");
                return;
            }
            //先交钱
            currentMoney -=crtTowerPrefab.towerCost;
            //更新
            UpdateMoney();
            //生成炮塔
            GameObjectcrtTower=Instantiate(towerPrefabs[currentTowerIndex]);
            //设置父对象
           crtTower.transform.SetParent(hit.collider.transform);
            //调整本地坐标
           crtTower.transform.localPosition=Vector3.up*1.2f;
        }
    }
    /// <summary>
    /// 炮塔按钮点击事件
    /// </summary>
    /// <param name="towerIndex"></param>
    public void OnTowerButtonClick(int towerIndex) {
        //设置当前点击的炮塔编号
        currentTowerIndex =towerIndex;
    }
 
 
}

usingSystem.Collections;
usingSystem.Collections.Generic;
using UnityEngine;
 
public class Tower : MonoBehaviour {
 
    [Header("炮塔价格")]
    public int towerCost = 200;
    [Header("炮塔主体")]
    public Transform turrent;
    [Header("转向速度")]
    public float turnSpeed = 5f;
    [Header("炮弹预设体")]
    public GameObject bulletPrefab;
    [Header("开炮时间间隔")]
    public float fireInterval=2;   
    [Header("炮弹生成点")]
    public Transform firePoint;
    [Header("炮塔炮弹伤害")]
    public float damage = 100;
 
    private float timer;
    //炮塔的攻击列表
    private List<Monster> monsterList;
 
 
 
    private void Awake()
    {
        monsterList = newList<Monster>();
    }
 
    private void Update()
    {
        if (monsterList.Count == 0)
            return;
        //炮塔指向怪物的方向向量
        Vector3 dir = monsterList[0].transform.position+ Vector3.up*monsterList[0].monsterHeight - turrent.position;
        //转换四元数
        Quaternion targetQua =Quaternion.LookRotation(dir);
 
        turrent.rotation =Quaternion.Lerp(turrent.rotation,targetQua,Time.deltaTime*turnSpeed);
 
        timer += Time.deltaTime;
        if (timer > fireInterval) {
            //生成炮弹
            GameObjectblt=Instantiate(bulletPrefab, firePoint.position, Quaternion.identity);
            //初始化炮弹
           blt.GetComponent<Bullet>().BulletInit(monsterList[0].transform,damage);
            //归零计时器
            timer = 0;
        }
 
    }
 
    public void RemoveMonsterFromList(Monster monster) {
        if (monsterList.Contains(monster)) {
            //从列表中移除
           monsterList.Remove(monster);
        }
    }
 
    private void OnTriggerEnter(Collider other)
    {
        if (other.tag == "Monster") {
            //当前怪物
            Monster currentMonster =other.GetComponent<Monster>();
            //加入攻击列表
           monsterList.Add(other.GetComponent<Monster>());
            //给怪物绑定死亡事件
            currentMonster.deathEvent+= RemoveMonsterFromList;
        }
    }
 
    private void OnTriggerExit(Collider other)
    {
        if (other.tag == "Monster")
        {
            //当前怪物
            Monster currentMonster =other.GetComponent<Monster>();
            //从攻击列表移除
           monsterList.Remove(other.GetComponent<Monster>());
            //给怪物解除绑定死亡事件
           currentMonster.deathEvent -= RemoveMonsterFromList;
        }
    }
}

usingSystem.Collections;
usingSystem.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using System;
 
public class Monster : MonoBehaviour {
    [Header("怪物血量")]
    public float monsterHP;
    [Header("怪物身高")]
    public float monsterHeight = 0.5f;
    [HideInInspector]
    //击杀怪物的价值
    private int monsterValue;
 
    /// <summary>
    /// 死亡事件
    /// </summary>
    public Action<Monster> deathEvent;
 
    private NavMeshAgent nav;
 
    private Animator ani;
 
    private CapsuleCollider col;
 
    private void Awake()
    {
        nav =GetComponent<NavMeshAgent>();
        ani =GetComponent<Animator>();
        col =GetComponent<CapsuleCollider>();
    }
    /// <summary>
    /// 怪物初始化
    /// </summary>
    /// <param name="moveSpeed"></param>
    /// <param name="hp"></param>
    /// <param name="target"></param>
    public void MonsterInit(float moveSpeed, float hp, int monsterValue ,Vector3 target) {
        nav.speed = moveSpeed;
        monsterHP = hp;
        this.monsterValue = monsterValue;
        nav.SetDestination(target);
    }
 
    public void TakeDamage(float damage) {
        //扣血
        monsterHP -= damage;
        if (monsterHP > 0)
        {
            //活着,播放受伤动画
            ani.SetTrigger("Damage");
            //停止导航
            nav.isStopped = true;
            //延时恢复导航
            Invoke("ResumeNavigation",0.25f);
        }
        else {
            //获取怪物的价值
           TowerBuyer.instance.currentMoney += monsterValue;
           TowerBuyer.instance.UpdateMoney();
            //播放死亡动画
            ani.SetTrigger("Dead");
            //停止导航
            nav.isStopped = true;
 
            if (deathEvent != null)
            {
                //执行死亡事件
                deathEvent(this);
            }
            //关闭碰撞体
            col.enabled = false;
 
            Destroy(gameObject,0.9f);
        }
    }
    /// <summary>
    /// 恢复导航
    /// </summary>
    private void ResumeNavigation() {
        nav.isStopped = false;
    }
}

usingSystem.Collections;
usingSystem.Collections.Generic;
using UnityEngine;
 
public class GameHealth : MonoBehaviour {
    [Header("游戏血量")]
    public int gameHealth = 10;
    private void OnTriggerEnter(Collider other)
    {
        //销毁游戏对象
        Destroy(other.gameObject);
        if (other.tag == "Monster") {
            if (--gameHealth == 0) {
                Debug.Log("GameOver");
            }
        }
    }
}

usingSystem.Collections;
usingSystem.Collections.Generic;
using UnityEngine;
 
public class CameraController : MonoBehaviour {
    //虚拟轴
    private float hor, ver;
    [Header("起结界始")]
    Vector2 startLimit = new Vector2(20,0);
    [Header("终点界始")]
    Vector2 endLimit = new Vector2(40, 60);
    [Header("移动速度")]
    public float moveSpeed = 3f;
 
 
 
         // Use this for initialization
         void Start () {
                  
         }
         
         // Update is called once per frame
         void Update () {
        hor = Input.GetAxis("Horizontal");
        ver = Input.GetAxis("Vertical");
        //获取当前摄像机可能的位置
        Vector3crtPos=transform.position + new Vector3(hor, 0, ver) * Time.deltaTime * moveSpeed;
 
        float x = Mathf.Clamp(crtPos.x, startLimit.x,endLimit.x);
        float z = Mathf.Clamp(crtPos.z, startLimit.y,endLimit.y);
 
        transform.position = new Vector3(x,crtPos.y, z);
    }
}

usingSystem.Collections;
usingSystem.Collections.Generic;
using UnityEngine;
 
public class Bullet : MonoBehaviour {
    //追踪目标   
    private Transform target;
    [Header("追踪速度")]
    public float speed = 5f;
    //炮塔的伤害    
    private float damage = 100;
 
/// <summary>
/// 炮弹信息初始化
/// </summary>
/// <paramname="target"></param>
/// <paramname="damage"></param>
    public void BulletInit(Transform target,float damage) {
        this.target = target;
        this.damage = damage;
    }
 
    private void Update()
    {
        if (target == null)
        {
            //销毁自己
            Destroy(gameObject);
            return;
        }                   
           
        transform.position =Vector3.Lerp(transform.position, target.position, Time.deltaTime * speed);
    }
 
    private void OnTriggerEnter(Collider other)
    {
        if (other.tag == "Monster") {
            //扣血
           other.GetComponent<Monster>().TakeDamage(100);
            //销毁自己
            Destroy(gameObject);
        }
    }
}

usingSystem.Collections;
usingSystem.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
 
/// <summary>
/// 怪物波次信息
/// </summary>
[System.Serializable]//序列化
public class MonsterWave {
    [Header("波次之间的时间间隔")]
    public float waveInterval;
    [Header("怪物之间的时间间隔")]
    public float monsterInterval;
    [Header("怪物个数")]
    public int monsterCount;
    [Header("怪物预设体")]
    public GameObject monsterPrefab;
    [Header("怪物血量")]
    public float monsterHP;
    [Header("怪物移动速度")]
    public float monsterNavSpeed;
    [Header("击杀怪物的价值")]
    public int monsterValue;
 
}
 
 
public class MonsterCreater : MonoBehaviour {
    [Header("波次信息")]
    public MonsterWave[] waves;
    //波次计数器
    private float wavetimer=0;
    //怪物生成计时器
    private float monsterTimer = 0;
    //怪物生成计数器
    private int counter=0;
    //当前生成的波次编号
    private int waveIndex=0;
    //起点
    private Transform startTra;
    //终点
    private Transform endTra;
 
    private void Awake()
    {
        startTra = GameObject.FindWithTag("Start").transform;
        endTra =GameObject.FindWithTag("End").transform;
    }
 
    private void Update()
    {
        //波次计时器计时
        wavetimer += Time.deltaTime;
        //如果所有波次怪物都已经生成完毕
        if (waveIndex >= waves.Length) {
            return;
        }
        
        //计时达到该生成这波怪的时候
        if (wavetimer >waves[waveIndex].waveInterval) {
            for (int i = 0; i<waves[waveIndex].monsterCount; i++) {
                //怪物计时器计时
                monsterTimer +=Time.deltaTime;
 
                //当前波次的怪物是否生成完毕
                if (counter <waves[waveIndex].monsterCount)
                {
                    //计时达到生产怪物的时间间隔
                    if (monsterTimer> waves[waveIndex].monsterInterval)
                    {
                        //生成怪物
                        GameObjectcurrentMonster = Instantiate(waves[waveIndex].monsterPrefab, startTra.position,Quaternion.identity);
 
                        //设置当前怪物的导航速度
                       currentMonster.GetComponent<NavMeshAgent>().speed =waves[waveIndex].monsterNavSpeed;
 
                        //初始化怪物信息
                       currentMonster.GetComponent<Monster>().MonsterInit(waves[waveIndex].monsterNavSpeed,waves[waveIndex].monsterHP, waves[waveIndex].monsterValue, endTra.position);
                        //计数器递增
                        counter++;
                        //计时器归零
                        monsterTimer = 0;
                    }
                }
                //当前波次怪物都已经生成完毕
                else {
 
                    //波次编号递增
                    waveIndex++;
 
                    //计数器归零
                    counter = 0;
                    //波次计数器归零
                    wavetimer = 0;
                }
            }
            
        }        
    }
}

猜你喜欢

转载自blog.csdn.net/renwen1579/article/details/128985302