You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在OnTriggerStay2D中实现定时重复执行攻击函数?

射击型敌人攻击逻辑实现方案

问题核心

你之前用while/for循环直接在Update这类每帧执行的方法里触发攻击,会导致每帧内循环瞬间完成N次迭代,自然疯狂生成子弹甚至引发崩溃——因为Update每秒会运行几十上百次,循环完全没有起到“间隔3秒”的作用。

正确实现方法

以下两种方案都能实现“玩家进入射程后每3秒攻击一次”的需求:


方法一:使用InvokeRepeating(简洁高效)

Unity内置的InvokeRepeating可以直接实现延迟启动+定时重复执行的逻辑,无需手动维护计时器:

public class EnemyShooter : MonoBehaviour
{
    public float attackRange = 10f;       // 敌人攻击射程
    public float attackInterval = 3f;     // 攻击间隔时间
    public Transform player;              // 玩家对象(需在Inspector赋值)
    public GameObject bulletPrefab;       // 子弹预制体
    public Transform firePoint;           // 子弹发射点

    private bool _isAttacking = false;

    void Update()
    {
        // 计算与玩家的距离
        float distanceToPlayer = Vector3.Distance(transform.position, player.position);

        if (distanceToPlayer <= attackRange)
        {
            // 玩家进入射程且未开始攻击时,启动重复攻击
            if (!_isAttacking)
            {
                // 参数:要执行的方法名、首次攻击延迟、重复间隔
                InvokeRepeating(nameof(FireBullet), 0f, attackInterval);
                _isAttacking = true;
            }
        }
        else
        {
            // 玩家超出射程时,停止攻击
            if (_isAttacking)
            {
                CancelInvoke(nameof(FireBullet));
                _isAttacking = false;
            }
        }
    }

    // 子弹生成逻辑(对应你图片中的代码)
    void FireBullet()
    {
        Instantiate(bulletPrefab, firePoint.position, firePoint.rotation);
    }
}

方法二:手动用Time.deltaTime计时

如果不想依赖Invoke系列方法,可以手动维护计时器变量:

public class EnemyShooter : MonoBehaviour
{
    public float attackRange = 10f;
    public float attackInterval = 3f;
    public Transform player;
    public GameObject bulletPrefab;
    public Transform firePoint;

    private float _attackTimer = 0f;

    void Update()
    {
        float distanceToPlayer = Vector3.Distance(transform.position, player.position);

        if (distanceToPlayer <= attackRange)
        {
            // 每帧累加计时器
            _attackTimer += Time.deltaTime;
            // 计时器达到间隔时触发攻击,并重置计时器
            if (_attackTimer >= attackInterval)
            {
                FireBullet();
                _attackTimer = 0f;
            }
        }
        else
        {
            // 玩家不在射程内,重置计时器
            _attackTimer = 0f;
        }
    }

    void FireBullet()
    {
        Instantiate(bulletPrefab, firePoint.position, firePoint.rotation);
    }
}

注意事项

  • 绝对不要在Update/FixedUpdate这类每帧执行的方法内使用while/for循环来控制攻击间隔,这类循环会在单帧内执行无数次,直接导致性能崩溃。
  • 确保player变量已正确赋值(可以在Inspector拖拽玩家对象,或在Start方法中通过GameObject.FindWithTag("Player")获取,后者尽量少用)。
  • 子弹的飞行、碰撞等逻辑建议单独写在子弹脚本中,不要冗余在敌人的攻击方法里。

内容的提问来源于stack exchange,提问作者mikloskristian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 21:25:41