deeda
@deeda

Не останавливается корутина. Что нужно дописать чтобы ее остановить?

Суть такая, хотел написать код для получения урона от ловушки, но без использования Time.deltaTime, ибо тот медленный, решил окунуться в мир корутин, так что открыл для себя его недавно, буквально вчера утром.

Все думал как написать код, но все без толку, либо персонаж получает урон один раз в триггере, а потом не получает вовсе потому что цикл я останавливал через "break;", либо персонаж получал урон даже выйдя из триггера, как будто при отравлении, пока хп не кончится, либо при входе в триггер Юнити эдитор зависал напрочь.

Отчаялся так, что попросил помощь в дискорде Russian Gamedev, но там не дали дельного совета, один ответчик посоветовал использовать Time.deltaTime, а второй вовсе не понимал почему мое хп уходит в минус, так что теперь прошу помощи здесь, пожалуйста, помогите с решением данной проблемы, заранее спасибо огромное за ваши ответы, я очень вам благодарен!

Вот данный код:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TakeDamage : MonoBehaviour
{


    public HealthSystem Hsys;
    public PlayerController PCont;


    private Collider2D collision;


    private bool Trigger;


    public int DamageFromTraps;



    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.tag.Equals("Trap"))
        {
            Trigger = true;
            DamageCondition();
        }
    }

    private void OnTriggerExit2D(Collider2D collision)
    {
        if (collision.gameObject.tag.Equals("Trap"))
        {
            Trigger = false;
            DamageCondition();
        }
    }


    private void DamageCondition()
    {
        if (Trigger == true)
        {
            StartCoroutine(Spikes());
        }

        else if (Trigger == false)
        {
            StopCoroutine(Spikes());

            Debug.Log("Корутина остановлена");
        }


   
    }

   IEnumerator Spikes()
    {
        while (Hsys.health > 0)
        {
            Hsys.health -= DamageFromTraps;
            yield return new WaitForSeconds(2f);
        }
    }


}
  • Вопрос задан
  • 160 просмотров
Решения вопроса 1
K0TlK
@K0TlK
Буллю людей.
Hsys

PCont

Много времени сохранил себе, сократив названия?

TakeDamage

Что это вообще такое и зачем оно нужно?

DamageCondition

Метод назван так, будто он должен что-то возвращать, но возвращает он ничего.

Почему вообще урон от пик персонаж наносит сам себе, а не пики ему?

Ты хочешь сделать миллион компонентов и потом навешивать их по-одному на персонажа? Не надо так делать. В итоге у тебя будет миллион компонентов, которые зависят друг от друга и, чтобы потом собрать другого персонажа, тебе придется искать всё, из чего он состоит. Делай все через интерфейсы.

Отдельно здоровье

namespace Coroutines
{
    public interface IHealth
    {
        bool IsOver { get; }
        void Lose(float amount);
        void Restore(float amount);
    }
}


using System;
using UnityEngine;

namespace Coroutines
{
    public class Health : IHealth
    {
        private readonly float _max;
        private readonly float _min;
        private float _current;

        public Health(float max, float min = 0)
        {
            _max = max;
            _min = min;
            _current = _max;
        }

        public bool IsOver => _current <= _min;
        
        public void Lose(float amount)
        {
            if (amount <= 0) throw new ArgumentException();
            
            SetCurrent(_current - amount);
        }

        public void Restore(float amount)
        {
            if (amount <= 0) throw new ArgumentException();

            SetCurrent(_current + amount);
        }

        private void SetCurrent(float amount)
        {
            _current = Mathf.Clamp(amount, _min, _max);
        }
    }
}



Отдельно персонаж

namespace Coroutines
{
    public interface IDamageable
    {
        bool IsDead { get; }
        void ApplyDamage(float amount);
    }
}


using UnityEngine;

namespace Coroutines
{
    public class Character : MonoBehaviour, IDamageable
    {
        [SerializeField] private float _maxHp = 100f;

        private IHealth _health;

        public bool IsDead => _health.IsOver;

        private void Awake()
        {
            _health = new Health(_maxHp);
        }

        public void ApplyDamage(float amount) => _health.Lose(amount);
    }
}



И отдельно ловушка

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Coroutines
{
    public class Trap : MonoBehaviour
    {
        [SerializeField] private float _damage = 10f;
        [SerializeField] private float _delay = 2f;
        
        private readonly Dictionary<IDamageable, Coroutine> _targets = new();

        private void OnTriggerEnter2D(Collider2D other)
        {
            if (other.TryGetComponent(out IDamageable damageable))
            {
                var coroutine = StartCoroutine(Damaging(damageable));
                _targets.Add(damageable, coroutine);
            }
        }

        private void OnTriggerExit2D(Collider2D other)
        {
            if (other.TryGetComponent(out IDamageable damageable))
            {
                var coroutine = _targets[damageable];
                StopCoroutine(coroutine);
                _targets.Remove(damageable);
            }
        }

        private IEnumerator Damaging(IDamageable target)
        {
            while (target.IsDead == false)
            {
                target.ApplyDamage(_damage);
                yield return new WaitForSeconds(_delay);
            }
        }

    }
}



Как именно должен дамаг наноситься ты не сказал, поэтому у меня каждому персонажу, что зашел в триггер, урон наносится отдельно. На входе в триггер персонаж добавляется в список и стартуется корутина, на выходе корутина завершается и персонаж из списка удаляется. Чтобы завершить определенную корутину, ее нужно кэшировать куда-то.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы