Пытаясь заставить врага наносить урон каждые несколько секунд (Единство) - PullRequest
0 голосов
/ 03 мая 2020

Я создаю 3D-шутер и пытаюсь нанести противнику урон игроку каждые заданные секунды. Я заставил врага наносить урон с помощью радиопередачи, но он наносит урон слишком быстро.

Я думал, что при использовании yield return новый WaitForSeconds (2) будет получать 1 урон от игрока каждые 2 секунды, но он наносит урон игроку намного быстрее.

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

public class EnemyMove : MonoBehaviour
{
    public Transform target;
    public Transform player;
    public float enemySpeed;
    public int moveTrigger = 1;
    public int isAttacking;

    public float distanceFromPlayer;

    void Update()
    {
        distanceFromPlayer = Vector3.Distance(target.transform.position, player.transform.position);

        if (distanceFromPlayer <= 10 && moveTrigger == 1)
        {
            transform.LookAt(target);
            StartCoroutine(EnemyDamage());
        }
        if (distanceFromPlayer <10 && moveTrigger == 1 && distanceFromPlayer >3)
        {
            transform.Translate(Vector3.forward * enemySpeed * Time.deltaTime);
        }
    }

    IEnumerator EnemyDamage()
    {
        RaycastHit PlayerHit;
        if (Physics.Raycast(target.transform.position, target.transform.forward, out PlayerHit))
        {
            Debug.Log(PlayerHit.transform.name);
            Target target = PlayerHit.transform.GetComponent<Target>();
            if (target != null)
            {
                yield return new WaitForSeconds(2);
                GlobalHealth.playerHealth -= 1;
                yield return null;
            }
        }
    }
}

Ответы [ 4 ]

1 голос
/ 03 мая 2020

Вы запускаете сопрограмму в каждом обновлении l oop, поэтому каждый кадр вызывается вашей подпрограммой урона и применяет ваш 1 урон через 2 секунды. Если вы хотите, чтобы эффект наносил урон с течением времени, предложение использовать таймер игрового времени является правильным, но если вы хотите, чтобы ваш враг мог атаковать только каждые x секунд, вам нужно реализовать какое-то время восстановления вашей функции урона. Например, добавляйте Time.deltaTime до тех пор, пока не истечет время, которое вы хотите, и только тогда враг сможет снова нанести урон. Вы можете сделать это с логическим значением.

0 голосов
/ 03 мая 2020

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

// in update
if (distanceFromPlayer <= 10 && moveTrigger == 1){
        transform.LookAt(target);
        if(!isAttacking)
            StartCoroutine(EnemyDamage());
}

IEnumerator EnemyDamage()
{
    isAttacking = true;
    while(distanceFromPlayer <= 10){ // in range
        RaycastHit PlayerHit;
        if (Physics.Raycast(target.transform.position, target.transform.forward, out PlayerHit)){
            Target target = PlayerHit.transform.GetComponent<Target>();
            if (target != null){
                GlobalHealth.playerHealth -= 1;
                yield return new WaitForSeconds(2);      
            }
        }
    }
    isAttacking = false; // out of range
    yield return null;
}
0 голосов
/ 03 мая 2020

в обновлении l oop, проверьте, когда прошло две секунды, когда игрок находится в диапазоне

float timeInRange = 0.0f;
bool inRange = false;

if (distanceFromPlayer <= 10 && moveTrigger == 1)
{
    inRange = true;
} 
else 
{
    inRange = false;
    timeInRange = 0;
}

if (inRange) 
{
    timeInRange += Time.DeltaTime;
}

if (timeInRange > 2.0f) 
{
    GlobalHealth.playerHealth -= 1;
    timeInRange = 0.0f;
}
0 голосов
/ 03 мая 2020

Вы можете использовать FixedUpdate → установить локальную переменную bool alreadyShoot = false.

  • В вашем EnemyDamage() добавить if(!alreadyShoot) перед повреждением приложения и установить alreadyShoot в true после нанесения ущерба.

  • В FixedUpdate вы можете установить alreadyShoot на false.

Вы можете выбрать другой решение установить alreadyShoot в false вместо FixedUpdate (например, сопрограмму, которая срабатывает каждую секунду, ...)

...