塔防游戏 Day2
1. 创建炮塔选择的 UI
使用 UI -> Toggle 。注意指定同一 group。
2. 创建炮台的数据类
1 [System.Serializable] // 序列化 2 public class TurretData{ 3 public GameObject turretPrefab; // 炮塔模型 4 public int cost; // 建造炮塔花费 5 public GameObject turretUpgradedPrefab; // 升级炮塔模型 6 public int costUpgraded; // 升级花费 7 public TurretType type; // 炮台类型 8 } 9 10 public enum TurretType // 炮塔类型 11 { 12 LaserTurret, 13 MissileTurret, 14 StandardTurret 15 }
3. 监听炮塔选择的事件
在 Inspector 中指定 On Value Changed 触发函数。
1 public void onLaserSelected(bool isOn) // 当监听变量发生变化时触发 2 { 3 if (isOn) 4 { 5 selectedTurretData = laserTurretData; 6 } 7 } 8 9 public void onMissileSelected(bool isOn) 10 { 11 if (isOn) 12 { 13 selectedTurretData = missileTurretData; 14 } 15 } 16 17 public void onStandardSelected(bool isOn) 18 { 19 if (isOn) 20 { 21 selectedTurretData = standardTurretData; 22 } 23 }
4. 鼠标点击创建炮塔
1 void Update() 2 { 3 if (Input.GetMouseButtonDown(0)) // 监测鼠标左键点击 4 { 5 if (!EventSystem.current.IsPointerOverGameObject()) // 鼠标没有点击 UI 图标 6 { 7 // 有鼠标所在位置发射射线 8 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); 9 RaycastHit hit; // 存储射线碰撞物 10 bool isCollider = Physics.Raycast(ray, out hit, 1000, LayerMask.GetMask("MapCube")); 11 if (isCollider) 12 { 13 MapCube mapCube = hit.collider.GetComponent<MapCube>(); // 获取点击方块 14 // 当前已选择炮台且方块上没有放置炮台 15 if (selectedTurretData != null && mapCube.turretGo == null) 16 { 17 if (money > selectedTurretData.cost) // 钱够用 18 { 19 ChangeMoney(-selectedTurretData.cost); 20 mapCube.BuildTurret(selectedTurretData.turretPrefab); 21 } 22 else 23 { 24 // 钱不够,则触发动画 25 moneyAnimator.SetTrigger("Flicker"); 26 } 27 } 28 else if (mapCube.turretGo != null) 29 { 30 // TODO 升级处理 31 } 32 } 33 } 34 } 35 }
1 // 建造炮塔 2 public void BuildTurret(GameObject turretPrefab) 3 { 4 // 实例化炮塔模型 5 turretGo = GameObject.Instantiate(turretPrefab, transform.position, Quaternion.identity); 6 // 产生建造特效 7 GameObject effect = GameObject.Instantiate(buildEffect, transform.position, Quaternion.identity); 8 Destroy(effect, 1); // 一秒后销毁特效 9 }
5. 检测炮塔附近的敌人
1 public class Turret : MonoBehaviour { 2 // 存储炮塔攻击范围内的敌人 3 public List<GameObject> enemys = new List<GameObject>(); 4 5 void OnTriggerEnter(Collider col) 6 { 7 if (col.tag == "Enemy") // 敌人进入 8 { 9 enemys.Add(col.gameObject); 10 } 11 } 12 13 void OnTriggerExit(Collider col) 14 { 15 if (col.tag == "Enemy") // 敌人离开 16 { 17 enemys.Remove(col.gameObject); 18 } 19 } 20 21 public float attackRateTime = 1; // 攻击频率 22 private float timer = 0; // 记录时间 23 24 public GameObject bulletPrefab; // 子弹模型 25 public Transform firePosition; // 子弹生成位置 26 public Transform head; // 炮塔头部位置 27 28 void Start() 29 { 30 timer = attackRateTime; // 有敌人立刻攻击 31 } 32 33 void Update() 34 { 35 if (enemys.Count > 0) 36 { 37 if (enemys[0] != null) 38 { 39 // 炮塔头部转向敌人位置 40 Vector3 targetPosition = enemys[0].transform.position; 41 targetPosition.y = head.position.y; // 要注意高度相同 42 head.LookAt(targetPosition); 43 } 44 timer += Time.deltaTime; 45 if (timer >= attackRateTime) // 攻击 46 { 47 timer -= attackRateTime; 48 Attack(); 49 } 50 } 51 } 52 53 void Attack() 54 { 55 if (enemys[0] == null) // 若第一个敌人为空 56 { 57 updateEnemys(); // 更新攻击范围内敌人 58 } 59 if (enemys.Count > 0) 60 { 61 // 实例化子弹 62 GameObject bullet = GameObject.Instantiate(bulletPrefab, firePosition.position, firePosition.rotation); 63 bullet.GetComponent<Bullet>().setTarget(enemys[0].transform); 64 } 65 else 66 { 67 timer = attackRateTime; 68 } 69 } 70 71 // 去除已经死亡的敌人 72 void updateEnemys() 73 { 74 List<int> emptyIndex = new List<int>(); 75 for (int i = 0; i < enemys.Count; ++i) 76 { 77 if (enemys[i] == null) 78 { 79 emptyIndex.Add(i); 80 } 81 } 82 for (int i = 0; i < emptyIndex.Count; ++i) 83 { 84 enemys.RemoveAt(emptyIndex[i] - i); 85 } 86 } 87 }
6. 敌人添加血条设计
使用 UI -> Slider
hpSlider.value = (float)hp / totalHp; // 更新血条
7.