Некорректное создание кораблей

122
29 сентября 2019, 03:40

Всем привет.
Ситуация следующая:
Есть модуль создания волн вражеских кораблей.
Корабли состоят в отряде(ширенга, шахматный, клин и т.д.), отряды в формации(фаланга, шахматная, клин и т.д.), этакий Bridge. Формация содержится в классе EnemyWave, который является MonoBehaviour и отвечает за различные параметры(тип кораблей, количество кораблей, отрядов и прочее). Класс EnemyWaveController отвечает за волны кораблей(генерит их, меняет тип, например сразу только легкие корабли, потом средние и т.д.).
Корабли при уничтожении активируют событие EnemyDieEvent, Отряд же подписывается на него и при активации события смотрит есть ли еще живые корабли, если нет то генерит событие SquadDieEvent, аналогично формация по этому событию смотрит есть ли живые отряды и если их нет, то активирует событие FormationDieEvent, дальше EnemyWave при получении события создает новую формацию и активирует событие CanGenerateNewWaveEvent, генерация формации, отрядов и кораблей происходит в классе EnemyWaveController(при старте, а потом по событию CanGenerateNewWaveEvent)

Проблема в том, что при уничтожении первого же корабля происходит вся цепочка событий и спавнится куча новых кораблей(при уничтожении 3го корабля unity у меня зависает от спавна такого количества кораблей). Где косяк не пойму, прошу помогите пожалуйста).
Скрин до уничтожения первого корабля:

После:

Классы:

namespace Core.EnemyWaves
{
    public class EnemyWavesController : MonoBehaviour
    {
        [SerializeField]
        private EnemyWave[] enemyWaves; 
        [SerializeField]
        private float delay;
        private EnemyWave _currentWave;
        private int _enemyWaveIndex;
        private void Awake()
        {
            _enemyWaveIndex = 0;
            enemyWaves[_enemyWaveIndex].gameObject.SetActive(true);
            for (int i = 1; i < enemyWaves.Length; i++)
            {
                enemyWaves[i].gameObject.SetActive(false);
            }
            _currentWave = enemyWaves[_enemyWaveIndex];
            ManagerProvider.EventManager.CanGenerateNewWaveEvent.Subscribe(OnWaveDestroyed);
        }
        private void Start()
        {
            _currentWave.GenerateWave();
        }
        private void OnDestroy()
        {
            ManagerProvider.EventManager.CanGenerateNewWaveEvent.Unsubscribe(OnWaveDestroyed);
        }
        private void OnWaveChanged()
        {
            _enemyWaveIndex++;
            if (_enemyWaveIndex < enemyWaves.Length - 1)
            {
                enemyWaves[_enemyWaveIndex - 1].gameObject.SetActive(false);
                enemyWaves[_enemyWaveIndex].gameObject.SetActive(true);
                _currentWave = enemyWaves[_enemyWaveIndex];
            }
        }
        private void OnWaveDestroyed()
        {
            StartCoroutine(GenerateNewWave());
        }
        private IEnumerator GenerateNewWave()
        {
            yield return new WaitForSeconds(delay);
            _currentWave.GenerateWave();
        }
    }
}
namespace Core.EnemyWaves
{
    public class EnemyWave : MonoBehaviour
    {
        [SerializeField]
        private GameObject[] enemyShipPrefabs;
        [SerializeField]
        private Vector2 startPosition;
        [SerializeField]
        private float squadOffset;
        [SerializeField]
        private float shipOffset;
        [SerializeField]
        private int countShipsInSquad;
        [SerializeField]
        private int countSqudsInFormation;
        [SerializeField]
        private int _countKindsOfFormation = 4;
        private BaseFormation _formation;
        public void GenerateWave()
        {
            _formation.GenerateFormation();
        }
        private void Awake()
        {
            _formation = CreateRandomFormation();
        }
        private void OnEnable()
        {
            ManagerProvider.EventManager.FormationDieEvent.Subscribe(OnFormationDie);
        }
        private void OnDisable()
        {
            ManagerProvider.EventManager.FormationDieEvent.Unsubscribe(OnFormationDie);
        }
        private void OnFormationDie()
        {
            _formation.Dispose();
            _formation = CreateRandomFormation();
            ManagerProvider.EventManager.CanGenerateNewWaveEvent.OnEvent();
        }
        private BaseFormation CreateRandomFormation()
        {
            int rand = Random.Range(0, _countKindsOfFormation);
            switch (rand)
            {
                case 0:
                    return new FalangeFormation(this.startPosition, this.squadOffset, this.shipOffset, 
                        this.countShipsInSquad, this.countSqudsInFormation, this.enemyShipPrefabs);
                case 1:
                    return new WedgeFormation(this.startPosition, this.squadOffset, this.shipOffset,
                        this.countShipsInSquad, this.countSqudsInFormation, this.enemyShipPrefabs);
                case 2:
                    return new TriangleFormation(this.startPosition, this.squadOffset, this.shipOffset,
                        this.countShipsInSquad, this.countSqudsInFormation, this.enemyShipPrefabs);
                case 3:
                    return new ChessFormation(this.startPosition, this.squadOffset, this.shipOffset,
                        this.countShipsInSquad, this.countSqudsInFormation, this.enemyShipPrefabs);
                default:
                    goto case 0;
            }
        }
    }
}
namespace Core.EnemyWaves.Formations
{
    public abstract class BaseFormation
    {
        private List<BaseSquad> _squads;
        protected Vector2 startPosition;
        protected float shipOffset;
        protected int countShipsInSquad;
        protected GameObject[] enemyShipPrefabs;
        protected float SquadOffset { get; set; }
        protected int CountSquads { get; private set; }
        public BaseFormation
            (Vector2 startPosition, float squadOffest, float shipOffset, 
            int countShipsInSquad, int countSquads, GameObject[] enemyShipPrefabs)
        {
            _squads = new List<BaseSquad>();
            this.startPosition = startPosition;
            this.shipOffset = shipOffset;
            this.countShipsInSquad = countShipsInSquad;
            SquadOffset = squadOffest;
            CountSquads = countSquads;
            if (enemyShipPrefabs == null || enemyShipPrefabs.Length == 0)
            {
                Debug.LogError("Enemy ship prefabs must be not null or length more then 0");
            }
            this.enemyShipPrefabs = enemyShipPrefabs;
            ManagerProvider.EventManager.SquadDieEvent.Subscribe(OnSquadDie);
            _squads.AddRange(CreateSquads());
        }
        public void GenerateFormation()
        {
            foreach (BaseSquad squad in _squads)
            {
                squad.GenerateSquad();
            }
            Debug.Log("Count squads in formation=" + _squads.Count);
        }
        public void Dispose()
        {
            ManagerProvider.EventManager.SquadDieEvent.Unsubscribe(OnSquadDie);
        }
        protected abstract BaseSquad[] CreateSquads();
        private void OnSquadDie(BaseSquad squad)
        {
            _squads.Remove(squad);
            squad.Dispose();
            Debug.Log("Left Squads in formation=" + _squads.Count);
            if (_squads.Count == 0)
            {
                ManagerProvider.EventManager.FormationDieEvent.OnEvent();
            }
        }
    }
}
namespace Core.EnemyWaves.Formations
{
    public class FalangeFormation : BaseFormation
    {
        public FalangeFormation(Vector2 startPosition, float squadOffest, float shipOffset,
            int countShipsInSquad, int countSquads, GameObject[] enemyShipPrefabs) 
            : base(startPosition, squadOffest, shipOffset, 
                  countShipsInSquad, countSquads, enemyShipPrefabs)
        {
        }
        protected override BaseSquad[] CreateSquads()
        {
            BaseSquad[] result = new BaseSquad[CountSquads];
            for (int i = 0; i < CountSquads; i++)
            {
                int rand = Random.Range(0, base.enemyShipPrefabs.Length);
                result[i] = new SquadLine
                    (base.enemyShipPrefabs[rand], base.startPosition, base.shipOffset, base.countShipsInSquad);
                base.startPosition.y -= base.SquadOffset;
            }
            return result;
        }
    }
}
namespace Core.EnemyWaves.Squads
{
    public abstract class BaseSquad
    {
        protected List<GameObject> enemyShips;
        protected GameObject enemyShipPrefab;
        protected Vector2 startPosition;
        protected float shipOffset;
        protected int countShips;
        public BaseSquad
            (GameObject enemyShipPrefab, Vector2 startPosition, float shipOffset, int countShips)
        {
            enemyShips = new List<GameObject>();
            this.enemyShipPrefab = enemyShipPrefab;
            this.startPosition = new Vector2(startPosition.x, startPosition.y);
            this.shipOffset = shipOffset;
            this.countShips = countShips;
            ManagerProvider.EventManager.EnemyDieEvent.Subscribe(OnEnemyShipDie);
        }
        public abstract void GenerateSquad();
        public void Dispose()
        {
            ManagerProvider.EventManager.EnemyDieEvent.Unsubscribe(OnEnemyShipDie);
        }
        private void OnEnemyShipDie(GameObject enemyShip)
        {
            this.enemyShips.Remove(enemyShip);
            Debug.Log("Left ships in squad=" + this.enemyShips.Count);
            if (this.enemyShips.Count == 0)
            {
                ManagerProvider.EventManager.SquadDieEvent.OnEvent(this);
            }
        }
    }
} 
namespace Core.EnemyWaves.Squads
{
    public class SquadLine : BaseSquad
    {
        public SquadLine
            (GameObject enemyShipPrefab, Vector2 startPosition, float shipOffset, int countShips)
            : base(enemyShipPrefab, startPosition, shipOffset, countShips)
        {
        }
        public override void GenerateSquad()
        {
            for (int i = 0; i < base.countShips; i++)
            {
                GameObject enemyShipInstance = LeanPool.Spawn
                    (base.enemyShipPrefab, base.startPosition, base.enemyShipPrefab.transform.rotation);
                base.enemyShips.Add(enemyShipInstance);
                base.startPosition.x += base.shipOffset;
            }
            Debug.Log("Count ships in squad=" + base.enemyShips.Count);
        }
    }
}
namespace Core.Events
{
    public interface IEvent
    {
        void OnEvent();
        void Subscribe(Action handler);
        void Unsubscribe(Action handler);
    }
    public interface IEvent<T>
    {
        void OnEvent(T type);
        void Subscribe(Action<T> handler);
        void Unsubscribe(Action<T> handler);
    }
}
namespace Core.Events
{
    public class SquadDieEvent : IEvent<BaseSquad>
    {
        private event Action<BaseSquad> _squadDie;
        public void OnEvent(BaseSquad squad)
        {
            _squadDie?.Invoke(squad);
        }
        public void Subscribe(Action<BaseSquad> handler)
        {
            _squadDie += handler;
        }
        public void Unsubscribe(Action<BaseSquad> handler)
        {
            _squadDie -= handler;
        }
    }
}
namespace Core.Managers
{
    [RequireComponent(typeof(EventManager))]
    [RequireComponent(typeof(PlayerManager))]
    [RequireComponent(typeof(ScoreManager))]
    [RequireComponent(typeof(AudioManager))]
    [RequireComponent(typeof(AnimationManager))]
    [RequireComponent(typeof(LevelManager))]
    public class ManagerProvider : MonoBehaviour
    {
        private List<AbstractManager> _managers;
        public static EventManager EventManager { get; private set; }
        public static PlayerManager PlayerManager { get; private set; }
        public static ScoreManager ScoreManager { get; private set; }
        public static AudioManager AudioManager { get; private set; }
        public static AnimationManager AnimationManager { get; private set; }
        public static LevelManager LevelManager { get; private set; }
        private void Awake()
        {
            Initialize();
            DontDestroyOnLoad(this.gameObject);
            LevelManager.LoadLevel(Levels.MainMenu);
        }
        private void OnDestroy()
        {
            foreach (AbstractManager manager in _managers)
            {
                manager.Finalization();
            }
        }
        private void Initialize()
        {
            EventManager = GetComponent<EventManager>();
            ScoreManager = GetComponent<ScoreManager>();
            AudioManager = GetComponent<AudioManager>();
            AnimationManager = GetComponent<AnimationManager>();
            PlayerManager = GetComponent<PlayerManager>();
            LevelManager = GetComponent<LevelManager>();
            _managers = new List<AbstractManager>
            {
                EventManager,
                ScoreManager,
                AudioManager,
                AnimationManager,
                PlayerManager,
                LevelManager
            };
            foreach (AbstractManager manager in _managers)
            {
                manager.Initialization();
            }
        }
    }
}
namespace Core.Managers
{
    public abstract class AbstractManager : MonoBehaviour
    {
        public abstract void Initialization();
        public abstract void Finalization();
    }
}
namespace Core.Managers
{
    public class EventManager : AbstractManager
    {
        public EnemyDieEvent EnemyDieEvent { get; private set; }
        public SquadDieEvent SquadDieEvent { get; private set; }
        public FormationDieEvent FormationDieEvent { get; private set; }
        public CanGenerateNewWaveEvent CanGenerateNewWaveEvent { get; private set; }
        public PlayerDieEvent PlayerDieEvent { get; private set; }
        public HeavyScoreEvent HeavyScoreEvent { get; private set; }
        public override void Initialization()
        {
            EnemyDieEvent = new EnemyDieEvent();
            SquadDieEvent = new SquadDieEvent();
            FormationDieEvent = new FormationDieEvent();
            CanGenerateNewWaveEvent = new CanGenerateNewWaveEvent();
            PlayerDieEvent = new PlayerDieEvent();
            HeavyScoreEvent = new HeavyScoreEvent();
        }
        public override void Finalization()
        {
        }
    }
}
namespace Core
{
    public abstract class BaseDie : MonoBehaviour
    {
        [SerializeField]
        private int health;
        [SerializeField]
        protected GameObject explosionPrefab;
        [SerializeField]
        protected AudioClip explosionAudio;
        protected int CurrentHealth { get; set; }
        public virtual void TakeDamage(int damage)
        {
            CurrentHealth -= damage;
        }
        public void OnSpawn()
        {
            CurrentHealth = health;
        }
    }
}
namespace Core
{
    [RequireComponent(typeof(ItemsDroper))]
    public class EnemyDie : BaseDie
    {
        [SerializeField]
        private long scoreCost;
        private ItemsDroper _itemDropper;
        private void Awake()
        {
            _itemDropper = GetComponent<ItemsDroper>();
        }
        public override void TakeDamage(int damage)
        {
            base.TakeDamage(damage);
            if (CurrentHealth <= 0)
            {
                Transform selfTransform = this.transform;
                ManagerProvider.AnimationManager.PlayAnimatedObject
                    (base.explosionPrefab, selfTransform.position, selfTransform.rotation);
                ManagerProvider.AudioManager.PlayClip(base.explosionAudio);
                _itemDropper.DropRandomItem(selfTransform.position, selfTransform.rotation);
                ManagerProvider.ScoreManager.Score += this.scoreCost;
                ManagerProvider.EventManager.EnemyDieEvent.OnEvent(this.gameObject);
                LeanPool.Despawn(this.gameObject);
            }
        }
    }
}

Если что-то упустил, пишите добавлю.
Пример

Answer 1

Проблема решена.
Дело было в том, что объектов волн было несколько(с разными параметрами). Они все подписывались на событие и так как на момент его срабатывания, у волн были пустые списки с кораблями(по тому, что генерация была отдельно от создания объектов(формации, отрядов)), из-за этого они спавнили новые корабли, хоть и сами объекты волн были деактивированы.
Решил таким способом:
генерацию сделал в момент создания формации, ответственным за генерацию сделал EnemyWave(раньше был EnemyWaveController), и в событиях добавил проверку на активность объекта.

READ ALSO
Получить generic аргументы с помощью Mono.Cecil

Получить generic аргументы с помощью Mono.Cecil

У меня есть иерархия типов произвольной глубины, которая в конце реализует IPlugin<T> или IPlugin<T1, T2> интерфейс, который находится в другойdll

138
Laravel Авторизация с ролями многие ко многим

Laravel Авторизация с ролями многие ко многим

пытаюсь сделать авторизацию на ларавел с двумя ролямиНе понимаю как проверить права пользователя

109
Ошибка в .htaccess

Ошибка в .htaccess

Выдает 500 ошибкуВ чем ошибка? Сам тут полный 0

140
Как на php и mysql избрранное вещей сделать? [закрыт]

Как на php и mysql избрранное вещей сделать? [закрыт]

я создал таблицы users, post и psusers - пользователь, post - почты, ps - хранятся id users и post

120