试图让敌人在设定的秒数内造成伤害(Unity)

Trying to get enemy to deal damage every set seconds (Unity)

我正在创建一个 3D 射击游戏,我试图让敌人每隔设定的秒数对玩家造成伤害。我已经让敌人用光线投射造成伤害,但它造成伤害的速度太快了。

我认为使用 yield return new WaitForSeconds(2) 会每 2 秒从玩家身上带走 1 点伤害,但它对玩家造成伤害的速度要快得多。

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

可以使用FixedUpdate → 设置局部变量bool alreadyShoot = false.

  • 在你的 EnemyDamage() 中添加一个 if(!alreadyShoot) 在损害赔偿申请之前并在损害赔偿申请之后将 alreadyShoot 设置为 true

  • FixedUpdate中您可以将alreadyShoot设置为false

您可以选择其他解决方案将 alreadyShoot 设置为 false 而不是 FixedUpdate(例如每秒触发的协程,...)

你在每个更新循环中启动一个协程,所以每一帧你的伤害协程都会被调用并在 2 秒后应用你的 1 伤害。 如果你想要随着时间的推移造成伤害效果,那么使用游戏滴答计时器的建议是正确的,但如果你希望你的敌人只能每 x 秒攻击一次,你需要对你的伤害函数实施某种冷却时间。例如加起来Time.deltaTime直到你想要的时间过去,然后敌人才能再次造成伤害。你可以用布尔值来做到这一点。

在更新循环中,当玩家在范围内时检查两秒后

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

如其他答案中所述,您每帧都在启动一个新协程。当执行退出 并重新进入 您的协同程序时,您应该在协同程序中进行所有等待和循环。这就是你如何编写它来工作

// 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;
}