zoukankan      html  css  js  c++  java
  • Unity 3D游戏-塔防类游戏源码:重要方法和功能的实现

    Unity-塔防游戏源码


    本文提供全流程,中文翻译。

    Chinar坚持将简单的生活方式,带给世人!

    (拥有更好的阅读体验 —— 高分辨率用户请根据需求调整网页缩放比例)

    1

    有耐心的朋友可以跳转到SiKi学院,观看视频:SiKi学院

    SiKi学院——是本人发现的网络教程做的很完善的网络课堂,推荐大家多学,多看

    using UnityEngine;
    using System.Collections;
    using UnityEngine.EventSystems;
    using UnityEngine.UI;
    
    /// <summary>
    /// 建筑物控制脚本
    /// </summary>
    public class BuildManager : MonoBehaviour
    {
        public  TurretData StandarTurretData;  //标准炮塔数据
        public  TurretData MissileTurretData;  //导弹炮塔数据
        public  TurretData LaserTurretData;    //激光炮塔数据
        private TurretData SelectedTurretData; //当前选择的炮塔(即将要建造的炮台)
        private MapCube    _selectedMapCube;   //当前选择的游戏炮台
        private int        Money = 1000;       //金币
        public  Text       MoneyText;          //金币文本框
        public  Animator   MoneyAnimator;
        public  GameObject UpgradeCanvas;
        public  Button     ButtonUpGrade;
        private Animator   UpgradeCanvasAnimator;
    
    
        void Start()
        {
            UpgradeCanvasAnimator = UpgradeCanvas.GetComponent<Animator>();
        }
    
    
        void Update()
        {
            //容错,炮台的建造,需要满足2个条件
            if (SelectedTurretData != null && Input.GetMouseButtonDown(0)) //如果鼠标右键按下;
            {
                if (EventSystem.current.IsPointerOverGameObject() == false) //检测鼠标在不在UI上。
                {
                    //射线
                    Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    
                    //被照射物体
                    RaycastHit hit;
    
                    //是否照射到物体                  (射线,被照射物体,射线长度,MapCuber层的物体)
                    bool isCollider = Physics.Raycast(ray, out hit, 1000, LayerMask.GetMask("MapCube"));
                    if (isCollider)
                    {
                        MapCube mapcube = hit.collider.GetComponent<MapCube>(); //得到点击的mapcube
    
                        //如果底板上 没有炮塔,则可以创建
                        if (mapcube.TurretGo == null)
                        {
                            //可以创建,然后判断钱够不够,
                            if (Money >= SelectedTurretData.Cost)
                            {
                                ChangeMoney(-SelectedTurretData.Cost);   //减少钱
                                mapcube.BuildTurret(SelectedTurretData); //创建炮塔
                            }
                            else
                            {
                                //提示钱不够
                                MoneyAnimator.SetTrigger("Flicker");
                            }
                        }
                        else if (mapcube.TurretGo != null)
                        {
                            //选择的是否是同一个炮台&&UI升级框是否显示
                            if (mapcube.TurretGo == _selectedMapCube && UpgradeCanvas.activeInHierarchy)
                            {
                                StartCoroutine(HideUpGradeUi());
                            }
                            else
                            {
                                Vector3 upgraded = new Vector3(mapcube.transform.position.x, mapcube.transform.position.y + 2.6f, mapcube.transform.position.z);
                                //升级
                                ShowUpGradeUI(upgraded, mapcube.IsUpgraded);
                            }
    
                            //选择的炮台,被赋值
                            _selectedMapCube = mapcube;
                        }
                    }
                }
            }
        }
    
    
        public void OnStandarSelected(bool isOn)
        {
            if (isOn)
            {
                SelectedTurretData = StandarTurretData;
            }
        }
    
    
        public void OnMissileSelected(bool isOn)
        {
            if (isOn)
            {
                SelectedTurretData = MissileTurretData;
            }
        }
    
    
        public void OnLaserSelected(bool isOn)
        {
            if (isOn)
            {
                SelectedTurretData = LaserTurretData;
            }
        }
    
    
        /// <summary>
        /// 金钱的变动
        /// </summary>
        /// <param name="change"></param>
        private void ChangeMoney(int change = 0)
        {
            Money          += change;      //金币的变动
            MoneyText.text =  "¥" + Money; //金币文本框赋值
        }
    
    
        /// <summary>
        /// 显示升级按钮
        /// </summary>
        /// <param name="pos"></param>
        /// <param name="isDisableUp"></param>
        private void ShowUpGradeUI(Vector3 pos, bool isDisableUp = false) //是否禁用升级按钮
        {
            StopCoroutine(HideUpGradeUi());
            UpgradeCanvas.SetActive(false); //显示按钮
            UpgradeCanvas.transform.position = pos;
            UpgradeCanvas.SetActive(true);             //显示按钮
            ButtonUpGrade.interactable = !isDisableUp; //是否可以交互/  false
        }
    
    
        /// <summary>
        /// 隐藏升级按钮
        /// </summary>
        IEnumerator HideUpGradeUi()
        {
            UpgradeCanvasAnimator.SetTrigger("Hide");
    
            yield return new WaitForSeconds(0.6f);
    
            UpgradeCanvas.SetActive(false);
        }
    
    
        /// <summary>
        /// 点击升级按钮,升级炮塔
        /// </summary>
        public void OnUpGradeButtonDown()
        {
            if (Money >= _selectedMapCube._turretData.Cost) //钱够不够
            {
                ChangeMoney(-_selectedMapCube._turretData.Cost);
                _selectedMapCube.UpGradeTurret();
            }
            else
            {
                MoneyAnimator.SetTrigger("Flicker");
            }
    
            StartCoroutine(HideUpGradeUi());
        }
    
    
        /// <summary>
        /// 点击拆按钮。拆炮塔
        /// </summary>
        public void OnDestroyButtonDown()
        {
            _selectedMapCube.DestroyTurret();
            StartCoroutine(HideUpGradeUi());
        }
    }

    2

    using UnityEngine;
    
    /// <summary>
    /// 子弹类脚本
    /// </summary>
    public class Bullet : MonoBehaviour
    {
        public  int       Damage = 50; //伤害
        public  float     Speed  = 20; //速度
        private Transform Target;      //目标
    
        public  GameObject ExplosionEffectPrefab;    //子弹特效
        private float      DistanceArriveTarget = 2; //子弹于目标物体,向量长度
    
    
        void Start()
        {
        }
    
    
        void Update()
        {
            if (Target == null)
            {
                Die();
                return;
            }
    
            transform.LookAt(Target.position); //面向目标位置
            transform.Translate(Vector3.forward * Speed * Time.deltaTime);
    
            Vector3 dir = Target.position - transform.position;
            if (dir.magnitude < DistanceArriveTarget) //向量的长度magnitude
            {
                //子弹打到敌人,掉血
                Target.GetComponent<Enemy>().TakeDamage(Damage);
    
                Die();
            }
        }
    
    
        private void Die()
        {
            //实例化特效
            GameObject effect = Instantiate(ExplosionEffectPrefab, transform.position, transform.rotation) as GameObject;
    
            //删除特效
            Destroy(effect, 1f);
    
            //销毁子弹
            Destroy(this.gameObject);
        }
    
    
        /// <summary>
        /// 设置目标
        /// 
        /// </summary>
        /// <param name="_target"></param>
        public void SetTarget(Transform _target)
        {
            this.Target = _target;
        }
    }

    3

    using UnityEngine;
    using System.Collections;
    using UnityEngine.UI;
    
    /// <summary>
    /// 敌人脚本
    /// </summary>
    public class Enemy : MonoBehaviour
    {
        //位置数组
        private Transform[] positions;
    
        //下标,从0开始
        private int index = 0;
    
        //速度
        public float Speed = 10;
    
        public float Hp = 150;
    
        private float TotalHp; //总HP
    
        public GameObject ExplosionEffect; //敌人爆炸特效
    
        private Slider HpSlider;
    
    
        void Start()
        {
            positions = WayPoints.positions;
    
            TotalHp = Hp;
    
            HpSlider = GetComponentInChildren<Slider>();
        }
    
    
        void Update()
        {
            Move();
        }
    
    
        void Move()
        {
            //下标越界,就跳出;
            if (index > positions.Length - 1) return;
    
            //找一个方向,(目标位置-当前位置).normalized 取得这个向量的单位向量 ;
            transform.Translate((positions[index].position - transform.position).normalized * Time.deltaTime * Speed);
    
            //判断 两点 之间的距离
            if (Vector3.Distance(positions[index].position, transform.position) < 0.5f)
            {
                index++;
            }
    
    
            if (index > positions.Length - 1)
            {
                ReachDestination();
            }
        }
    
    
        /// <summary>
        /// ReachDestination 到达 目的地 销毁
        /// </summary>
        void ReachDestination()
        {
            Destroy(this.gameObject);
            GameManager.instance.Failed();
        }
    
    
        /// <summary>
        /// 监听销毁敌人
        /// </summary>
        void OnDestroy()
        {
            EnemySpawner.CountEnemyAlive--;
        }
    
    
        /// <summary>
        /// 敌人受到伤害
        /// </summary>
        /// <param name="damage"></param>
        public void TakeDamage(float damage)
        {
            if (Hp <= 0) return;                    //死了不处理
            Hp             -= damage;               //减少血量
            HpSlider.value =  (float) Hp / TotalHp; //血条
            if (Hp <= 0)
            {
                Die();
            }
        }
    
    
        private void Die()
        {
            GameObject effect = Instantiate(ExplosionEffect, transform.position, transform.rotation) as GameObject;
    
            Destroy(effect, 1.5f);
    
            Destroy(this.gameObject);
        }
    }

    4

    using UnityEngine;
    using System.Collections;
    
    
    /// <summary>
    /// 敌人生成控制脚本
    /// </summary>
    public class EnemySpawner : MonoBehaviour
    {
        //属性面板
        public Wave[] Waves;
    
        //生成位置
        public Transform StartTran;
    
        //孵化间隔
        public float WaveRate = 0.2f;
    
        //存活敌人的数量
        public static int CountEnemyAlive = 0;
    
        private Coroutine coroutine;
    
    
        void Start()
        {
            coroutine = StartCoroutine(SpawnEnemy());
        }
    
    
        /// <summary>
        /// 敌人孵化器
        /// </summary>
        /// <returns></returns>
        IEnumerator SpawnEnemy()
        {
            //遍历所有Waves中的 数组
            foreach (Wave wave in Waves)
            {
                for (int i = 0; i < wave.Count; i++)
                {
                    //实例化预设物(每一波敌人的预设物,开始位置,无旋转的)旋转前的初始角
                    GameObject.Instantiate(wave.EnemyPrefab, StartTran.position, Quaternion.identity);
    
                    CountEnemyAlive++; //存活数量增加
    
                    if (i != wave.Count - 1) //检测生成是否完毕
                    {
                        //时间间隔
                        yield return new WaitForSeconds(wave.Rate);
                    }
                }
    
                //当存活数量大于0
                while (CountEnemyAlive > 0)
                {
                    yield return 0; //暂停0帧,不执行下边代码
                }
    
                //每一波暂停 WaveRate 秒
                yield return new WaitForSeconds(WaveRate);
            }
        }
    
    
        /// <summary>
        /// 停止生成
        /// </summary>
        public void Stop()
        {
            StopCoroutine(coroutine);
        }
    }

    5

    using UnityEngine;
    using UnityEngine.EventSystems;
    
    
    /// <summary>
    /// 地图版块控制脚本
    /// </summary>
    public class MapCube : MonoBehaviour
    {
        [HideInInspector]                             //不显示在 Inspector 面板
        public                   GameObject TurretGo; //保存当前Cube身上的炮台
        [HideInInspector] public TurretData _turretData;
        public                   GameObject BuildEffect;
    
        private Renderer CubeRenderer;
    
        [HideInInspector] public bool IsUpgraded; //MapCub上的炮塔是否升级过
    
    
        void Start()
        {
            CubeRenderer = GetComponent<Renderer>();
        }
    
    
        /// <summary>
        /// 点击创建炮塔
        /// </summary>
        /// <param name="turretPrefab"></param>
        public void BuildTurret(TurretData turretData)
        {
            this._turretData = turretData;
            IsUpgraded       = false;
            //创建炮塔,位置,旋转,强转
            TurretGo             = Instantiate(turretData.TurretPrefab, transform.position, Quaternion.identity) as GameObject;
            GameObject effectobj = Instantiate(BuildEffect, transform.position, Quaternion.identity) as GameObject;
            Destroy(effectobj, 1f);
        }
    
    
        /// <summary>
        /// 升级炮台
        /// </summary>
        /// <param name="turretgo"></param>
        public void UpGradeTurret()
        {
            if (IsUpgraded == true) return; //容错
            Destroy(TurretGo);              //删除低级炮塔
            IsUpgraded = true;              //升级状态变化
            //创建炮塔,位置,旋转,强转
            TurretGo             = Instantiate(_turretData.TurretUpGradedPrefab, transform.position, Quaternion.identity) as GameObject;
            GameObject effectobj = Instantiate(BuildEffect, transform.position, Quaternion.identity) as GameObject;
        }
    
    
        /// <summary>
        /// 拆除炮台
        /// </summary>
        public void DestroyTurret()
        {
            Destroy(TurretGo);
            GameObject effectobj = Instantiate(BuildEffect, transform.position, Quaternion.identity) as GameObject;
            IsUpgraded           = false; //升级状态变化
            TurretGo             = null;
            _turretData          = null;
        }
    
    
        /// <summary>
        /// 鼠标移入
        /// </summary>
        private void OnMouseEnter()
        {
            //Cube上没有炮台,且,鼠标没有放在UI上
            if (TurretGo == null && EventSystem.current.IsPointerOverGameObject() == false)
            {
                CubeRenderer.material.color = Color.red; //变红
            }
        }
    
    
        /// <summary>
        /// 鼠标移出
        /// </summary>
        private void OnMouseExit()
        {
            CubeRenderer.material.color = Color.white; //变红
        }
    }

    6

    using UnityEngine;
    
    
    /// <summary>
    /// 炮塔模型类
    /// </summary>
    [System.Serializable] //可序列化
    public class TurretData
    {
        //炮塔预设物
        public GameObject TurretPrefab;
    
        //花费
        public int Cost;
    
        //炮塔升级预设物
        public GameObject TurretUpGradedPrefab;
    
        //升级炮塔花费
        public int CostUpGraded;
    
        //默认枚举类型
        public TurretType Type;
    }
    
    
    /// <summary>
    /// 枚举一个炮塔类
    /// </summary>
    public enum TurretType
    {
        StandardTurret, //标准
        MissileTurret,  //导弹
        LaserTurret     //激光
    }

    7

    using UnityEngine;
    using System.Collections.Generic;
    
    
    /// <summary>
    /// 炮塔控制脚本类
    /// </summary>
    public class Turret : MonoBehaviour
    {
        private List<GameObject> Enemys         = new List<GameObject>(); //进入方位的敌人
        public  float            AttackRateTime = 1;                      //攻击间隔
        private float            Timer          = 0;                      //计时器
        public  GameObject       BulletPrefab;                            //子弹 预设物
        public  Transform        FirePos;
        public  Transform        Head;
        public  bool             UseLaser   = false; //默认攻击方式
        public  float            DamageRate = 70;    //激光炮塔,持续伤害 速率。每秒70点伤害
        public  LineRenderer     LaseRenderer;
        public  GameObject       LaserEffect; //激光特效
    
    
        void Start()
        {
            Timer = AttackRateTime;
        }
    
    
        void Update()
        {
            if (Enemys.Count > 0 && Enemys[0] != null)
            {
                Vector3 targetPosition = Enemys[0].transform.position;
                targetPosition.y       = Head.position.y;
                Head.LookAt(targetPosition);
            }
    
            if (UseLaser == false)
            {
                Timer += Time.deltaTime;
    
                //敌人数量大于0,且满足间隔时间
                if (Enemys.Count > 0 && Timer >= AttackRateTime)
                {
                    Timer = 0;
                    Attack();
                }
            }
    
            else if (Enemys.Count > 0)
            {
                if (LaseRenderer.enabled == false) LaseRenderer.enabled = true;
    
                if (Enemys[0] == null)
                {
                    UpDateEnemys();
                }
    
                if (Enemys.Count > 0)
                {
                    //激光炮塔朝向
                    LaseRenderer.SetPositions(new Vector3[] {FirePos.position, Enemys[0].transform.position});
    
                    //激光炮塔攻击
                    Enemys[0].GetComponent<Enemy>().TakeDamage(DamageRate * Time.deltaTime);
                    LaserEffect.SetActive(true);
                    LaserEffect.transform.position = Enemys[0].transform.position;
    
                    //激光特效,朝向炮塔
                    Vector3 pos = transform.position;
                    pos.y       = Enemys[0].transform.position.y;
                    LaserEffect.transform.LookAt(pos);
                }
            }
            else
            {
                LaserEffect.SetActive(false);
                LaseRenderer.enabled = false;
            }
        }
    
    
        /// <summary>
        /// 攻击方法
        /// </summary>
        private void Attack()
        {
            if (Enemys[0] == null)
            {
                UpDateEnemys();
            }
    
            if (Enemys.Count > 0)
            {
                //实例化子弹
                GameObject bullet = Instantiate(BulletPrefab, FirePos.position, FirePos.rotation) as GameObject;
    
                //子弹 指向目标
                bullet.GetComponent<Bullet>().SetTarget(Enemys[0].transform);
            }
            else
            {
                Timer = AttackRateTime; //下次来敌人,直接攻击
            }
        }
    
    
        /// <summary>
        /// 进入区域
        /// </summary>
        /// <param name="col"></param>
        private void OnTriggerEnter(Collider col)
        {
            if (col.tag == "Enemy")
            {
                Enemys.Add(col.gameObject);
            }
        }
    
    
        /// <summary>
        /// 离开区域
        /// </summary>
        /// <param name="col"></param>
        private void OnTriggerExit(Collider col)
        {
            if (col.tag == "Enemy")
            {
                Enemys.Remove(col.gameObject);
            }
        }
    
    
        /// <summary>
        /// 更新集合
        /// </summary>
        private void UpDateEnemys()
        {
            //用来存空元素下标  的数组
            List<int> EmptyIndex = new List<int>();
    
            //移除所有为空的元素,遍历进入范围的敌人数组长度。
            for (int i = 0; i < Enemys.Count; i++)
            {
                if (Enemys[i] == null)
                {
                    EmptyIndex.Add(i);
                }
            }
    
            //移除 所有空元素
            for (int i = 0; i < EmptyIndex.Count; i++)
            {
                //由于Enemys移除元素,下标会变动。所以减去,移除的个数;
                Enemys.RemoveAt(EmptyIndex[i] - i);
            }
        }
    }

    8

    using UnityEngine;
    using System.Collections;
    
    
    /// <summary>
    /// 玩家视角控制脚本
    /// </summary>
    public class ViewController : MonoBehaviour
    {
        public float Speed      = 1;   //速度
        public float MouseSpeed = 249; //速度
    
    
        void Start()
        {
        }
    
    
        void Update()
        {
            //获取水平和垂直参数
            float h     = Input.GetAxis("Horizontal");
            float v     = Input.GetAxis("Vertical");
            float mouse = Input.GetAxis("Mouse ScrollWheel") * MouseSpeed;
            //控制移动,并根据时间平滑移动,根据世界坐标移动
            transform.Translate(new Vector3(h * Speed, mouse, v * Speed) * Time.deltaTime, Space.World);
        }
    }

    9

    using UnityEngine;
    
    
    /// <summary>
    /// 保存每一波敌人生成所需要的属性
    /// </summary>
    [System.Serializable] //可以被序列化的属性
    public class Wave
    {
        public GameObject EnemyPrefab; //敌人
        public int        Count;       //数量
        public float      Rate;        //时间间隔
    }

    10

    有耐心的朋友可以跳转到SiKi学院,观看视频:SiKi学院

    using UnityEngine;
    
    
    /// <summary>
    /// 路径导航脚本
    /// </summary>
    public class WayPoints : MonoBehaviour
    {
        //拐点,数组
        public static Transform[] positions;
    
    
        void Awake()
        {
            //找到当前,挂载脚本物体下的,子物体数量
            positions = new Transform[transform.childCount];
    
            //依次遍历所有子物体,得到依次的位置
            for (int i = 0; i < positions.Length; i++)
            {
                positions[i] = transform.GetChild(i);
            }
        }
    }

    1 —— 云服务器超全购买流程 (新手必备!)

    2 —— 阿里ECS云服务器自定义配置 - 购买教程(新手必备!)

    3—— Windows 服务器配置、运行、建站一条龙 !

    4 —— Linux 服务器配置、运行、建站一条龙 !




    技术交流群:806091680 ! Chinar 欢迎你的加入


    END

    本博客为非营利性个人原创,除部分有明确署名的作品外,所刊登的所有作品的著作权均为本人所拥有,本人保留所有法定权利。违者必究

    对于需要复制、转载、链接和传播博客文章或内容的,请及时和本博主进行联系,留言,Email: ichinar@icloud.com

    对于经本博主明确授权和许可使用文章及内容的,使用时请注明文章或内容出处并注明网址
    >

  • 相关阅读:
    如何查看RabbitMQ日志,Rabbitmq Trace日志的使用
    windows激活 RabbitMQ's Management Plugin(必须)
    UNET
    边缘检测
    Huber Loss
    深度学习之自编码器AutoEncoder(一)
    PU learning简介
    机器学习-稀疏矩阵的处理
    R语言入门-安装R和Rstuido软件
    归一化 (Normalization)、标准化 (Standardization)和中心化/零均值化 (Zero-centered)
  • 原文地址:https://www.cnblogs.com/chinarbolg/p/9601458.html
Copyright © 2011-2022 走看看