Unity3D开发塔防游戏案例个人总结
程序员文章站
2024-01-25 08:32:59
...
什么是塔防游戏?
- 塔防游戏(Tower Defense game,简称TD),即指一类通过在地图上建造炮塔或类似建筑物,以阻止游戏中敌人进攻的策略型游戏.
- 比如:植物大战僵尸 保卫萝卜 防御觉醒等
Unity3d开发塔防游戏的步骤
- 创建游戏地图 ,使用Cube代替炮塔可放置的位置
- MapCube.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class MapCube : MonoBehaviour
{
//保存当前cube身上的炮台
[HideInInspector]
public GameObject turretGo;
//炮台数据
[HideInInspector]
public TurretData turretData;
//是否升级了
[HideInInspector]
public bool isUpgraded = false;
//建造特效
public GameObject buildEffect;
//渲染组件
private Renderer renderer;
void Start()
{
renderer = GetComponent<Renderer>();
}
public void BuildTurret(TurretData turretData)
{
this.turretData = turretData;
isUpgraded = false;
turretGo = GameObject.Instantiate(turretData.turretPrefab, transform.position, Quaternion.identity);
GameObject effect = GameObject.Instantiate(buildEffect, transform.position, Quaternion.identity);
//延时1.5秒销毁特效
Destroy(effect, 1.5f);
}
public void UpgradeTurret()
{
if (isUpgraded == true) return;
Destroy(turretGo);
isUpgraded = true;
turretGo = GameObject.Instantiate(turretData.turretUpGradedPrefab, transform.position, Quaternion.identity);
GameObject effect = GameObject.Instantiate(buildEffect, transform.position, Quaternion.identity);
Destroy(effect, 1.5f);
}
public void DestroyTurret()
{
Destroy(turretGo);
isUpgraded = false;
turretGo = null;
turretData = null;
GameObject effect = GameObject.Instantiate(buildEffect, transform.position, Quaternion.identity);
Destroy(effect, 1.5f);
}
void OnMouseEnter()
{
//当前位置无炮台,且当前鼠标不在UI上
if (turretGo == null && EventSystem.current.IsPointerOverGameObject() == false)
{
renderer.material.color = Color.red;
}
}
void OnMouseExit()
{
renderer.material.color = Color.white;
}
}
- 创建敌人行走的路径,拐弯处使用空物体代替WayPoints
- 创建敌人生成点和终点
- 创建敌人生成代码
- EnemySpawner.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemySpawner : MonoBehaviour {
//敌人存活的数量
public static int CountEnemyAlive = 0;
//敌人每一波的数据数组
public Wave[] waves;
//起始点
public Transform START;
//每一波的间隔时间
public float waveRate = 3F;
void Start () {
//开启一个协程
StartCoroutine(SpawnEnemy());
}
//生成敌人的协程
IEnumerator SpawnEnemy()
{
foreach (Wave wave in waves)
{
for (int i = 0; i < wave.count; i++)
{
//在开始点生成敌人
GameObject.Instantiate(wave.enemyPrefab, START.position, Quaternion.identity);
//敌人的数量当然要增加了
CountEnemyAlive++;
//控制每一个敌人的生成间隔时间
if(i != wave.count - 1)
yield return new WaitForSeconds(wave.rate);
}
//这里我还没弄明白
while(CountEnemyAlive > 0)
{
yield return 0;
}
//控制每一波敌人的生成间隔时间
yield return new WaitForSeconds(waveRate);
}
}
}
上面的代码中使用了协程,如果不懂可以看看这篇文章
- 创建炮塔Turret
炮塔类有的属性:
1.攻击速率(每秒攻击几次,或者多少秒攻击1次)
2.子弹
3.在范围内的敌人列表(为什么需要这个呢?因为炮塔最先攻击先进入范围内的敌人,当敌人不在范围内的时候,需要把敌人移除)
4.攻击的时间(记录攻击速率,每一个攻击间隔执行一次攻击)
Turret.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 炮塔类
/// </summary>
public class Turret : MonoBehaviour {
//所有在攻击范围的敌人
private List<GameObject> enemys = new List<GameObject>();
void OnTriggerEnter(Collider col)
{
if (col.tag == "Enemy")
{
enemys.Add(col.gameObject);
}
}
void OnTriggerExit(Collider col)
{
if (col.tag == "Enemy")
{
enemys.Remove(col.gameObject);
}
}
//多少秒攻击一次
public float attackRateTime = 1;
private float timer = 0;
//子弹
public GameObject bulletPrefab;
//开火位置
public Transform firePosition;
//头部
public Transform head;
//是否使用激光攻击
public bool useLaser = false;
//攻击的每秒伤害
public float damageRate = 70;
//激光
public LineRenderer laserRenderer;
//激光特效
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;
if (enemys.Count > 0 && timer >= attackRateTime)
{
timer = 0;
Attack();
}
}
else if (enemys.Count > 0)
{
if (laserRenderer.enabled == false)
laserRenderer.enabled = true;
laserEffect.SetActive(true);
if (enemys[0] == null)
{
//当敌人不再范围内时,需要把敌人从数组中移除
UpdateEnemys();
}
if (enemys.Count > 0)
{
laserRenderer.SetPositions(new Vector3[] { firePosition.position, enemys[0].transform.position });
enemys[0].GetComponent<Enemy>().TakeDamage(damageRate * Time.deltaTime);
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);
laserRenderer.enabled = false;
}
}
void Attack()
{
if (enemys[0] == null)
{
UpdateEnemys();
}
if (enemys.Count > 0)
{
GameObject bullet = GameObject.Instantiate(bulletPrefab, firePosition.position, firePosition.rotation);
bullet.GetComponent<Bullet>().SetTarget(enemys[0].transform);
}
else
{
timer = attackRateTime;
}
}
void UpdateEnemys()
{
List<int> emptyIndex = new List<int>();
for (int index = 0; index < enemys.Count; index++)
{
if (enemys[index] == null)
{
emptyIndex.Add(index);
}
}
for (int i = 0; i < emptyIndex.Count; i++)
{
//移除索引后,索引会发生变化,所以要减i
enemys.RemoveAt(emptyIndex[i] - i);
}
}
}
接下来分析一下子弹有的属性
1.伤害 damage
2.速度 speed
3.目标点 target
Bullet.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour {
public int damage = 50;
public float speed = 20;
public GameObject explosionEffectPrefab;
private float distanceArriveTarget = 1.2f;
private Transform target;
public void SetTarget(Transform _target)
{
this.target = _target;
}
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)
{
target.GetComponent<Enemy>().TakeDamage(damage);
Die();
}
}
void Die()
{
GameObject effect = GameObject.Instantiate(explosionEffectPrefab, transform.position, transform.rotation);
Destroy(effect, 1);
Destroy(this.gameObject);
}
}