Как сделать Physics2D.OverlapBoxAll () активным в течение x раз и взаимодействовать только с новыми объектами, с которыми он сталкивается? - PullRequest
0 голосов
/ 19 сентября 2018

У меня очень простая 2D-игра, в которой игрок находится слева, а враги - справа и движутся к игроку.

Игрок будет атаковать врагов мечом,и у меня есть текущая функция для него:

[SerializeField] int damage = 1;
[SerializeField] Transform attackPos;
[SerializeField] LayerMask whatIsEnemy;
[SerializeField] float attackRangeX;
[SerializeField] float attackRangeY;

private void Update()
{
    if (Input.GetKeyDown(KeyCode.A))
    {
        DamageEnemies();
    }
}

private void DamageEnemies()
{
    Collider2D[] enemiesToDamage = Physics2D.OverlapBoxAll(attackPos.position, new Vector2(attackRangeX, attackRangeY), 0, whatIsEnemy);
    for (int i = 0; i < enemiesToDamage.Length; i++)
    {
        enemiesToDamage[i].GetComponent<EnemyController>().TakeDamage(damage);
    }
}

объект игры attackPos просто расположен перед игроком.AttackRangeX и Y напоминают квадрат перед игроком.

Проблема с этой настройкой заключается в том, что при нажатии клавиши атаки она будет взаимодействовать с врагами внутри только в этот момент времени, который является однимframe.

Как активировать столкновение в течение 5 секунд, но наносить урон только новым врагам один раз .Я бы не хотел, чтобы он продолжал наносить урон врагам, которых он уже повредил.

1 Ответ

0 голосов
/ 19 сентября 2018

Вы можете хранить уже поврежденных врагов в Списке и пропускать их, если вы уже повредили их.

Для более продолжительного активного урона некоторые люди предпочитают использовать сопрограммы (IEnumerator), но пока они просты.Я бы использовал простой таймер.

[SerializeField] int damage = 1;
[SerializeField] Transform attackPos;
[SerializeField] LayerMask whatIsEnemy;
[SerializeField] float attackRangeX;
[SerializeField] float attackRangeY;

// Adjust here how long the damage should take on (in seconds)
[SerializeField] float damageDuration = 5;

// This is the countdown timer for the damage
private float damageTimer;

// Flag that controls the damage mode
private bool isDamaging;

// Here you will store the already damaged enemies to skip them later
private List<Collider2D> alreadyDamagedEnemies = new List<Collider2D>();

private void Start()
{
    // Initialize the timer
    damageTimer = damageDuration;
}

private void Update()
{
    // only take keyboard input if not already damaging
    // to prevent a peanant press
    if(!isDamaging)
    {
        // Hint: If you want you could with a second timer at this point add
        // a cooldown so you can not directly atack again right after the damage duration
        // Just thought it might be interesting for you so I leave it as a homework ;) 

        if (Input.GetKeyDown(KeyCode.A))
        {
            // Only activate the damaging
            isDamaging = true;
        }
    }
    else // We are currently in damage mode
    {
        // If end of timer reset and leave damage mode
        if(damageTimer <= 0)
        {
            // Reset the timet
            damageTimer = damageDuration;

            // Switch off damage mode
            isDamaging = false;

            // Reset the list
            alreadyDamagedEnemies.Clear();
        }
        // else make damage and redue the timer
        else
        {
            DamageEnemies();

            // Reduce the timer by the time passed since last frame
            damageTimer-= Time.deltaTime;
        }
    }
}

private void DamageEnemies()
{
    Collider2D[] enemiesToDamage = Physics2D.OverlapBoxAll(attackPos.position, new Vector2(attackRangeX, attackRangeY), 0, whatIsEnemy);

    foreach (var currentEnemy in enemiesToDamage)
    {

        // Skip if you already damaged this enemy
        if(alreadyDamagedEnemies.Contains(currentEnemy) continue;

        currentEnemy.GetComponent<EnemyController>().TakeDamage(damage);

        // Add the damaged enemy to the list
        alreadyDamagedEnemies.Add(currentEnemy);
    }
}

В этом примере предполагается, что вы нажимаете A один раз, но наносите урон в течение полных 5 секунд, в том числе и при отпускании клавиши.

Если вы хотите, чтобы это происходило только во время нажатия клавиши и максимум 5 секунд вместо этого, я уверен, что вы сможете выяснить это самостоятельно, используя
if(Input.GetKey(KeyCode.A)){ ... }.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...