试图让敌人每隔设定的秒数造成伤害(统一)。

问题描述 投票:0回答:1

我正在创建一个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;
            }
        }
    }
}
c# unity3d raycasting
1个回答
0
投票

正如其他答案中提到的,你每一帧都要启动一个新的程序。你应该在你的coroutine里做所有的等待和循环,因为执行退出的时候 并重新进入 你的coroutine来自yeild statment。你可以这样写

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

1
投票

你在每次更新循环中都会启动一个coroutine,所以每一帧你的伤害coroutine都会被调用,并在2秒后应用你的1次伤害。如果你想要一个随时间变化的伤害效果,使用游戏滴答计时器的建议是正确的,但是如果你想让你的敌人每隔X秒才能攻击一次,你需要在你的伤害函数上实现某种冷却时间。例如将Time.deltaTime加起来,直到你想要的时间过去了,只有这样敌人才能再次造成伤害。你可以用一个布尔值来实现。


0
投票

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

  • 在你的 EnemyDamage() 添加 if(!alreadyShoot) 损害赔偿申请和设定前 alreadyShoottrue 在申请损害赔偿后。

  • FixedUpdate 你可以设置 alreadyShootfalse.

您可以选择其他解决方案来设置 alreadyShootfalse 而不是 FixedUpdate (例如一个每秒钟触发一次的程序,......)


0
投票

在更新循环中,当玩家在范围内时,检查两秒是否已过。

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;
}
© www.soinside.com 2019 - 2024. All rights reserved.