| 项目 Project | 视图 View | 
| 游戏对象 GameObject | 刚体 Rigidbody | 
| 组件 Component | 碰撞 Collide | 
| 预制件 Prefab | 材质 Material | 
| 脚本 Script | 资源商店 Asset Store | 
| 调试 Debug | 音频 Audio | 
| 包 Package | 发布 Publish | 
| 导航 Navigation | 用户界面 Toggle | 
| 物理 Physical | 线渲染 Line Renderer | 
| 协程 Coroutine | 数据脚本 Data | 
        
        
        
        
      



using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;//引入事件系统
public class Base : MonoBehaviour
{
    MeshRenderer m_Renderer;
    Color init_Color;
    public Color hover_Color;
    void Start()
    {
        m_Renderer = GetComponent<MeshRenderer>();
        init_Color = m_Renderer.material.color;
    }
    private void OnMouseEnter()
    {
        if (!EventSystem.current.IsPointerOverGameObject())//增加判断:不在UI上
        {
            m_Renderer.material.color = hover_Color;
        }
    }
    private void OnMouseExit()
    {
        m_Renderer.material.color = init_Color;
    }
}
      





using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.UI;
public class Mon : MonoBehaviour
{
    public GameObject explosion;
    public float Hp;
    public Image HpBar;
    NavMeshAgent agent;
    Transform tar;
    float curHealth;
    float oriSpeed;
    void Start()
    {
        curHealth = Hp;
        agent = GetComponent<NavMeshAgent>();
        tar = GameObject.FindGameObjectWithTag("target").transform;
        oriSpeed = agent.speed;
    }
    void Update()
    {
        agent.SetDestination(tar.position);
        //请根据实际情况判断距离
        if (Vector3.Distance(agent.destination, agent.nextPosition) <= 0.5f)
        {
            Destroy(gameObject);//1
            //每成功达到终点1个怪物,玩家生命减1;来自脚本GameManager.cs
            GameManager.lives--;
        }
    }
    //供子弹脚本的碰撞处理使用
    public void GetDam(float dam)
    {
        curHealth -= dam;
        HpBar.fillAmount = curHealth / Hp;
        if (curHealth <= 0)
        {
            Destroy(gameObject);//2
            //播放死亡时的粒子特效,参见后面[提高]部分
            GameObject exp = Instantiate(explosion);
            Destroy(exp, 1);
        }
    }
    //后期预留减速功能
    public void getSlow(float factor)
    {
        agent.speed = oriSpeed * (1 - factor);
        StartCoroutine(clearSlow());
    }
    public void resetSlow()
    {
        agent.speed = oriSpeed;
    }
    IEnumerator clearSlow()
    {
        yield return new WaitForSeconds(2);
        resetSlow();
    }
    //业务整合或单独写在对象销毁所在的函数内1、2
    private void OnDestroy()
    {
        Spawn.alive--;
    }
}
      
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Data
{
    public GameObject monPrefab;
    public int monNum;
    public int monInter;
}
      
//Spawn.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Spawn : MonoBehaviour
{
    public Data[] mons;
    public float waveInter;
    public static int alive = 0;
    public static bool isDone=false;
    void Start()
    {
        isDone = false;
        StartCoroutine(MonSpawn());
    }
    IEnumerator MonSpawn()
    {
        for (int i = 0; i < mons.Length; i++)
        {
            for (int j = 0; j < mons[i].monNum; j++)
            {
                alive++;
                GameObject mon = Instantiate(mons[i].monPrefab, transform.position, Quaternion.identity);
                yield return new WaitForSeconds(mons[i].monInter);
            }
            while (alive > 0)
            {
                yield return null;
            }
            yield return new WaitForSeconds(waveInter);
        }
        isDone=true;
    }
}
      
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;//引入UI事件系统
public class Build : MonoBehaviour
{
    public GameObject standard, missile, laser;
    GameObject selected;
    void Start()
    {
        selected = standard;
    }
    void Update()
    {
        //按下鼠标且不在UI上
        if (Input.GetMouseButtonDown(0) && !EventSystem.current.IsPointerOverGameObject())
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            //和指定层发射碰撞
            //如果不指定距离,会放到路面上!!!
            if (Physics.Raycast(ray, out hit, 1000, LayerMask.GetMask("base")))
            {
                GameObject obj = hit.collider.gameObject;
                //如果当前对象没有炮塔/子对象;且金钱足够[功能预留]
                if (obj.transform.childCount == 0)
                {
                    //动态生成并放置炮塔,成为基座base的子对象
                    GameObject tower = Instantiate(selected, obj.transform.position, Quaternion.identity);
                    tower.transform.parent = obj.transform;
                }
            }
        }
    }
    public void selTowerStandard(bool isON)//选中第1种炮:标准炮
    {
        if (isON)
        {
            selected = standard;
        }
    }
    public void selTowerMissile(bool isON)//选中第2种炮:火箭炮
    {
        if (isON)
        {
            selected = missile;
        }
    }
    public void selTowerLaser(bool isON)//选中第3种炮:激光炮
    {
        if (isON)
        {
            selected = laser;
        }
    }
}
      
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
    GameObject obj = hit.collider.gameObject;
    if (obj.tag == "base" && obj.transform.childCount == 0)
    {
        GameObject tar = Instantiate(curTower, obj.transform.position, Quaternion.identity);
        tar.transform.parent = obj.transform;
    }
}
      
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class Base : MonoBehaviour
{
    public GameObject towerFab;
    private void OnMouseDown()
    {
        if (transform.childCount == 0 && !EventSystem.current.IsPointerOverGameObject())
        {
            GameObject obj = Instantiate(towerFab, transform.position, Quaternion.identity);
            obj.transform.parent = transform;
        }
    }
}
      
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
    public float damage = 10;
    public float speed = 20;
    Transform target = null;
    void Update()
    {
        if (target == null)
        {
            Destroy(gameObject);
            return;
        }
        transform.Translate(Vector3.forward * speed * Time.deltaTime);
        transform.LookAt(target.position);
    }
    public void SetTarget(Transform tar)
    {
        target = tar;
    }
    private void OnTriggerEnter(Collider other)
    {
        if (other.tag == "mon")
        {
            Destroy(gameObject);
            target.GetComponent<Mon>().GetDam(damage);
            //预留:粒子击中特效
        }
    }
}
      
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Standard : MonoBehaviour
{
    public List<GameObject> list = new List<GameObject>();
    public GameObject bullet;
    public Transform firePos;
    public Transform headRot;
    Transform target;//也可以声明为GameObj,但是我们仅仅需要的是一个位置
    public float attackInter = 1f;
    float timer = 0;
    private void Start()
    {
        InvokeRepeating("GetTarget", 0, 0.5f);
    }
    void Update()
    {
        if (target == null)
        {
            return;
        }
        //创建新的位置信息,主要是控制高度一致,避免后仰前俯;且让炮台始终朝向目标
        Vector3 tarPos = target.position;
        tarPos.y = headRot.position.y;
        headRot.LookAt(tarPos);
        timer += Time.deltaTime;
        if (timer >= attackInter && list.Count > 0)
        {
            GameObject bulletObj = Instantiate(bullet, firePos.position, firePos.rotation);
            bulletObj.GetComponent<Bullet>().SetTarget(target);
            Destroy(bulletObj.gameObject, 5);
            timer = 0;
        }
    }
    void GetTarget()
    {
        float minDis = Mathf.Infinity;
        //起始必须赋空值
        Transform nearMon = null;
        //MUST:每次获取前先把可能的空对象移出
        list.RemoveAll(item => item == null);
        foreach (GameObject item in list)
        {
            float dis = Vector3.Distance(transform.position, item.transform.position);
            if (dis < minDis)
            {
                minDis = dis;
                nearMon = item.transform;
            }
        }
        target = nearMon;
    }
    private void OnTriggerEnter(Collider other)
    {
        if (other.tag == "mon")
        {
            list.Add(other.gameObject);
        }
    }
    private void OnTriggerExit(Collider other)
    {
        if (other.tag == "mon")
        {
            list.Remove(other.gameObject);
        }
    }
}
      
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Laser : MonoBehaviour
{
    public List<GameObject> list = new List<GameObject>();
    public Transform firePos;
    public Transform headRot;
    Transform target;
    public LineRenderer line;
    public float damOverTime = 20f;
    public float slowFactor = 0.6f;
    private void Start()
    {
        InvokeRepeating("GetTarget", 0, 0.5f);
    }
    void Update()
    {
        if (target == null)
        {
            line.enabled = false;
            return;
        }
        Vector3 tarPos = target.position;
        tarPos.y = headRot.position.y;
            line.enabled = true;
        headRot.LookAt(tarPos);
        line.SetPositions(new Vector3[] { firePos.position,target.position});
        target.GetComponent<Mon>().GetDam(damOverTime*Time.deltaTime);
        target.GetComponent<Mon>().getSlow(slowFactor);
        //发射音效
    }
    void GetTarget()
    {
        float minDis = Mathf.Infinity;
        Transform nearMon = null;
        //MUST:每次获取前先把可能的空对象移出
        list.RemoveAll(item => item == null);
        foreach (GameObject item in list)
        {
            float dis = Vector3.Distance(transform.position, item.transform.position);
            if (dis < minDis)
            {
                minDis = dis;
                nearMon = item.transform;
            }
        }
        target = nearMon;
    }
    private void OnTriggerEnter(Collider other)
    {
        if (other.tag == "mon")
        {
            list.Add(other.gameObject);
        }
    }
    private void OnTriggerExit(Collider other)
    {
        if (other.tag == "mon")
        {
            list.Remove(other.gameObject);
        }
    }
}
      
//Menu.cs
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Menu : MonoBehaviour
{
    public Animation ani;
    private void Start()
    {
        Time.timeScale = 1;
    }
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Escape))
        {
            Application.Quit();
        }
    }
    public void LoadScene(string str)
    {
        SceneManager.LoadScene(str);
    }
    public void Quit()
    {
        Application.Quit();
    }
    public void LoadAnim()
    {
        ani.Play();
    }
}
      
//GameManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour
{
    public static int lives = 3;
    public GameObject failEnding;
    public GameObject winEnding;
    public GameObject pauseEnding;
    bool isPause=false;
    private void Start()
    {
        lives = 3;
        Time.timeScale = 1;
        failEnding.SetActive(false);
        winEnding.SetActive(false);
        pauseEnding.SetActive(false);
    }
    private void Update()
    {
        //失败
        if (lives <= 0)
        {
            failEnding.SetActive(true);
            Time.timeScale = 0;
        }
        //胜利
        if (lives > 0 && Spawn.isDone)
        {
            StartCoroutine(dis());
        }
        //按下Escape
        if (Input.GetKeyDown(KeyCode.Escape))
        {
            if (isPause)
            {
                isPause = false;
                Time.timeScale = 1;
                pauseEnding.SetActive(false);
            }
            else
            {
                isPause = true;
                Time.timeScale = 0;
                pauseEnding.SetActive(true);
            }
        }
    }
    public void backToGame()
    {
        Time.timeScale = 1;
        pauseEnding.SetActive(false);        
        isPause = false;
    }
    public void LoadScene(string str)
    {
        SceneManager.LoadScene(str);
    }
    public void Quit()
    {
        Application.Quit();
    }
    //暂停1秒后显示winEnding
    IEnumerator dis()
    {
        yield return new WaitForSeconds(1);
        winEnding.SetActive(true);
    }
}
      public AudioSource player; public AudioClip clip; // player.PlayOneShot(clip);
public AudioSource player;
public AudioClip clip;                    
//如果没有播放就播放,否则什么也不做
if (player.isPlaying)
{
}
else
{
    player.PlayOneShot(clip);
}
      
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AudioCtrl : MonoBehaviour
{
    public static AudioCtrl instance;
    AudioSource player;
    private void Awake()
    {
        if (instance == null)
        {
            instance = this;
        }
        else if (instance != this)
        {
            Destroy(gameObject);
        }
        DontDestroyOnLoad(gameObject);
    }
    void Start()
    {
        player = GetComponent<AudioSource>();
    }
    public void playAudio(AudioClip clip)
    {
        player.PlayOneShot(clip);
    }
}
      
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class xxx : MonoBehaviour
{
    public AudioClip clip;
    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.tag == "mon")
        {
            //其它业务略
            AudioCtrl.instance.playAudio(clip);
        }
    }
}
      
















