第二部分——敌人生成器

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

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

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

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值