第二部分——敌人生成器

        使用工厂方法模式来生成敌人。

        一:创建工厂的接口 + 工厂抽象类

        (1)在工厂中配有创建敌人的方法,在具体的工厂中会保存有敌人的预制体引用。在创建的函数实现中,还会调用敌人类中的初始化方法。

        (2)创建工厂的接口:让具体的敌人来创建,更加方便(可以利用多态):通过此接口我们可以实现提供一系列的敌人Prefab,然后全部自动创建工厂。

public interface ICreateFactory
{
    public EnemyFactory CreateFactory(EnemyController enemyPrefab);
}

public abstract class EnemyFactory
{
    public abstract EnemyController CreateEnemy();

}

public class MetalonFactory : EnemyFactory
{
    private readonly MetalonController metalonPrefab;

    public MetalonFactory(MetalonController metalonPrefab) 
    {
        this.metalonPrefab = metalonPrefab;
    }
    public override EnemyController CreateEnemy()
    {
        var metalon = Object.Instantiate(metalonPrefab);
        metalon.InitAfterGenerate();
        return metalon;
    }
}


public class GolemFactory : EnemyFactory
{
    private readonly GolemController golemPrefab;
    
    public GolemFactory(GolemController golemPrefab)
    {
        this.golemPrefab = golemPrefab;
    }

    public override EnemyController CreateEnemy()
    {
        var golem = Object.Instantiate(golemPrefab);
        golem.InitAfterGenerate();
        return golem;
    }
}

        二:敌人生成器

       (1)在编译器窗口中,我们只需要把所有的敌人预制体放入即可自动创建所有的工厂。

       (2)为所有敌人增加了阶级属性(普通敌人,精英敌人,BOSS敌人),并且分别创建了对应的工厂列表,这样可以方便地随机生成想要的阶级的敌人。同时建立了一个<敌人名称,敌人工厂>的字典,可以供我们生成具体想要的敌人类型(在每个Enemy中有静态字段表示名称)。

        (3)设置一个简单的基于波数的战斗规则(规则可自行定义)。分为普通波和BOSS波,每一波后有短暂的间隔,BOSS战后有较长的休息时间,同时回家的传送门会打开,无限循环即可。


public class EnemyGenerator : MonoBehaviour
{
    [Header("敌人预制体")] 
    [SerializeField] private List<EnemyController> enemyPrefabs;

    [Header("敌人生成设置")] 
    
    [SerializeField] private float generateTime;   // 每波的冷却时间(杀死所有敌人后)
    
    [SerializeField] private int generateMinEnemyCount; // 每波生成的最少敌人

    [SerializeField] private int generateMaxEnemyCount; // 每波生成的最大敌人

    [SerializeField] private float generateEliteProbability; // 生成精英敌人的概率

    [SerializeField] private float restTimeAfterBossFight;   // boss战后的调整时间

    [Header("引用")] 
    [SerializeField] private GameObject transitionPatrol; // 战斗场景的传送门:规则打完boss之后会打开一段时间
    
    private int generateTimes;          // 当前的波数:每10波生成一个boss

    private bool isBossFightOver;       // 是否是在Boss波结束后

    private bool isFightOver;           // 是否是在一波战斗结束后

    // 不同阶级敌人的生成工厂:用于在某个阶级上随机生成不同种类敌人
    private readonly List<EnemyFactory> normalEnemyFactories = new();
    private readonly List<EnemyFactory> eliteEnemyFactories = new();
    private readonly List<EnemyFactory> bossEnemyFactories = new();

    // 字典工厂:可以指定生成某种类的敌人
    private readonly Dictionary<string, EnemyFactory> enemyNameToFactories = new();
    
    private float generateTimeCounter; // 生成冷却时间的计时器
    public float GenerateTimeCounter
    {
        get => generateTimeCounter;
        set
        {
            generateTimeCounter = value;
            if (value <= 0)
            {
                StartCoroutine(GenerateEnemy());
            }
        }
    }


    private void Awake()
    {
        foreach (var enemyPrefab in enemyPrefabs)
        {
            var factory = enemyPrefab.CreateFactory(enemyPrefab);
            switch (enemyPrefab.EnemyLevel)
            {
                case EnemyLevelType.Normal:
                    normalEnemyFactories.Add(factory);
                    break;
                case EnemyLevelType.Elite:
                    eliteEnemyFactories.Add(factory);
                    break;
                case EnemyLevelType.Boss:
                    bossEnemyFactories.Add(factory);
                    break;
            }
            enemyNameToFactories.Add(enemyPrefab.EnemyName, factory);
        }
    }

    private void Start()
    {
        generateTimes = 0;
        GenerateTimeCounter = generateTime;
    }

    private void OnEnable()
    {
        GlobalEvent.enemyDeathEvent += CheckFightOver;
    }

    private void OnDisable()
    {
        GlobalEvent.enemyDeathEvent -= CheckFightOver;
    }

    private void CheckFightOver(EnemyController enemyController)
    {
        isFightOver = GameManager.Instance.enemies.Count == 0;
        isBossFightOver = isFightOver & (generateTimes % 10 == 0);
        if (isBossFightOver)
        {
            //激活传送门
            transitionPatrol.gameObject.SetActive(true);
            generateTimeCounter = restTimeAfterBossFight;
        }
    }

    private void Update()
    {
        // 计时器计时的规则:1:当前是战斗场景 2:敌人数量为0 3:当前不是正在加载场景
        if (SceneLoader.Instance.GetCurrentSceneType == SceneType.FightScene && GameManager.Instance.enemies.Count == 0&& !SceneLoader.Instance.IsLoading)
            GenerateTimeCounter -= Time.deltaTime;

        // 如果在boss波结束后按下E键 则立刻进入下一波
        if (isBossFightOver&&Input.GetKeyDown(KeyCode.E))
        {
            GenerateTimeCounter = 0;
        }
        
    }


    public IEnumerator GenerateEnemy()
    {
        ++generateTimes;
        transitionPatrol.gameObject.SetActive(false);
        // 生成boss类敌人
        if (generateTimes % 10 == 0)
        {
            CreateRandomBossEnemy();
            yield break;
        }
        // 生成普通/精英敌人
        int generateEnemyCount = Random.Range(generateMinEnemyCount, generateMaxEnemyCount);
        for (int i = 0; i < generateEnemyCount; i++)
        {
            float random = Random.value;
            if (random < generateEliteProbability)
            {
                CreateRandomEliteEnemy();
            }
            else
            {
                CreateRandomNormalEnemy();
            }

            yield return new WaitForSeconds(1f);
        }
    }


    private void CreateRandomNormalEnemy()
    {
        var enemy = normalEnemyFactories[Random.Range(0, normalEnemyFactories.Count)].CreateEnemy();
    }

    private void CreateRandomEliteEnemy()
    {
        var enemy = eliteEnemyFactories[Random.Range(0, eliteEnemyFactories.Count)].CreateEnemy();
    }

    private void CreateRandomBossEnemy()
    {
        // TODO:暂时没有设计boss 
        var enemy = eliteEnemyFactories[Random.Range(0, eliteEnemyFactories.Count)].CreateEnemy();
        // var enemy = bossEnemyFactories[Random.Range(0, bossEnemyFactories.Count)].CreateEnemy();
    }

        private void CreateEnemyByName(string enemyName)
    {
        if (enemyNameToFactories.TryGetValue(enemyName, out var factory))
        {
            var enemy = factory.CreateEnemy();
        }
    }

}

### 创建塔防游戏敌人生成机制 在Unity中实现塔防游戏中的敌人生成主要涉及几个方面:创建管理器对象、编写生成逻辑以及定义路径节点。 #### 游戏管理器与生成器设定 为了更好地控制整个游戏流程,在场景内添加一个名为`GameManager`的空GameObject作为全局控制器[^3]。随后在此基础上建立专门负责怪物出场安排的对象——即“Enemy Spawner”,并为其挂载相应的C#脚本来描述具体的召唤行为模式。 ```csharp using UnityEngine; public class EnemySpawner : MonoBehaviour { // 需要填充的具体参数... } ``` #### 编写敌人生成逻辑 接下来就是具体实现敌人群体按照一定规律刷新的功能了。这通常会涉及到定时触发事件来决定何时何地投放新的单位实例。下面给出了一种简单的做法: - 设定波次间隔时间和每波数量; - 使用协程(Coroutine)配合WaitForSeconds等待指定秒数后再继续执行后续操作; ```csharp // 波次数目 private int waveIndex = 0; // 当前正在生成的一批敌人计数器 private int currentWaveCountdown; // 单位之间的最小间距时间 [SerializeField] private float spawnInterval = 1f; // 各阶段配置详情表(可根据实际需求调整) [SerializeField] private Wave[] waves; void Start(){ StartCoroutine(SpawnWaves()); } IEnumerator SpawnWaves(){ while (waveIndex<waves.Length){ yield return new WaitForSeconds(2); var wave = waves[waveIndex++]; PrepareNextWave(wave); for(currentWaveCountdown=wave.count;currentWaveCountdown>0;--currentWaveCountdown){ InstantiateEnemy(); yield return new WaitForSeconds(spawnInterval); } } } void PrepareNextWave(Wave wave){ Debug.Log($"即将开始第{waveIndex}波攻击!"); } void InstantiateEnemy(){ GameObject enemyInstance = Instantiate(enemyPrefab,spawnPoint.position,Quaternion.identity); enemyInstance.GetComponent<Enemy>().pathPositions = pathTransforms; } ``` 此处假设已经存在预设好的敌人模型(`enemyPrefab`)和路径点数组(`pathTransforms`)供调用,同时也假定了每个敌人组件里含有属性用于接收导航信息以便于之后沿轨迹前进[^4]。 通过上述方式可以在Unity环境中较为轻松地搭建起一套基础版的塔防类项目框架下的敌人生成体系。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值