我正在创建一个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;
}
}
}
}
正如其他答案中提到的,你每一帧都要启动一个新的程序。你应该在你的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;
}
你在每次更新循环中都会启动一个coroutine,所以每一帧你的伤害coroutine都会被调用,并在2秒后应用你的1次伤害。如果你想要一个随时间变化的伤害效果,使用游戏滴答计时器的建议是正确的,但是如果你想让你的敌人每隔X秒才能攻击一次,你需要在你的伤害函数上实现某种冷却时间。例如将Time.deltaTime加起来,直到你想要的时间过去了,只有这样敌人才能再次造成伤害。你可以用一个布尔值来实现。
你可以使用 FixedUpdate
→ 设置一个局部变量 bool alreadyShoot = false
.
在你的 EnemyDamage()
添加 if(!alreadyShoot)
损害赔偿申请和设定前 alreadyShoot
到 true
在申请损害赔偿后。
在 FixedUpdate
你可以设置 alreadyShoot
到 false
.
您可以选择其他解决方案来设置 alreadyShoot
到 false
而不是 FixedUpdate
(例如一个每秒钟触发一次的程序,......)
在更新循环中,当玩家在范围内时,检查两秒是否已过。
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;
}