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

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

  • 相关阅读:
    使用 libevent 和 libev 提高网络应用性能
    An existing connection was forcibly closed by the remote host
    各种浏览器的兼容css
    vs输出窗口,显示build的时间
    sass
    网站设置404错误页
    List of content management systems
    css footer not displaying at the bottom of the page
    强制刷新css
    sp_executesql invalid object name
  • 原文地址:https://www.cnblogs.com/chinarbolg/p/9601458.html
Copyright © 2011-2022 走看看