欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Unity3D开发塔防游戏案例个人总结

程序员文章站 2024-01-25 08:32:59
...

什么是塔防游戏?

  • 塔防游戏(Tower Defense game,简称TD),即指一类通过在地图上建造炮塔或类似建筑物,以阻止游戏中敌人进攻的策略型游戏.
    Unity3D开发塔防游戏案例个人总结
  • 比如:植物大战僵尸 保卫萝卜 防御觉醒等

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);
    }
}