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

Unity实现NPC间隔3秒依次沿路径点移动的问题求助

实现NPC间隔3秒依次启动移动的方案

你当前的问题原因是所有NPC的Start生命周期函数几乎同时执行,每个NPC都各自等待3秒后启动移动,所以最终还是会同时触发移动逻辑。你可以选择以下两种方案实现间隔启动效果:

方案1:由WaypointsManager统一控制启动(推荐)

该方案逻辑更清晰,后续修改启动间隔、调整启动顺序都更方便。

第一步 修改WaypointsManager脚本

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

public class WaypointsManager : MonoBehaviour
{
    public GameObject npcPrefab;
    public int numberOfNpcs;
    public GameObject waypointsPrefab;
    public List<GameObject> waypoints = new List<GameObject>();
    public int numberOfWaypoints;
    public bool useWaypointsPrefab = false;
    // 新增:NPC启动间隔
    public float npcActivateInterval = 3f;

    private GameObject waypointObject;
    // 新增:存储生成的所有NPC的移动脚本
    private List<Waypoints> spawnedNpcs = new List<Waypoints>();

    void Awake()
    {
        for (int i = 0; i < numberOfWaypoints; i++)
        {
            if (useWaypointsPrefab)
            {
                // 注意:你原代码这里写的是Instantiate(npcPrefab),属于笔误,已修正
                waypointObject = Instantiate(waypointsPrefab, Vector3.zero, Quaternion.identity);
            }
            else
            {
                waypointObject = new GameObject();
            }
            waypointObject.tag = "Waypoint";
            waypointObject.name = "Waypoint";
            waypointObject.transform.position = new Vector3(Random.Range(0, 10), Random.Range(0, 10), Random.Range(0, 10));
            waypoints.Add(waypointObject);
        }

        for (int i = 0; i < numberOfNpcs; i++)
        {
            if (npcPrefab != null)
            {
               GameObject npc = Instantiate(npcPrefab, Vector3.zero, Quaternion.identity);
               Waypoints npcMoveScript = npc.GetComponent<Waypoints>();
               // 直接给NPC赋值路径点,避免每个NPC全局查找标签优化性能
               npcMoveScript.waypoints = waypoints;
               spawnedNpcs.Add(npcMoveScript);
            }
        }
    }

    private void Start()
    {
        // 启动依次激活NPC的协程
        StartCoroutine(ActivateNpcsInOrder());
    }

    private IEnumerator ActivateNpcsInOrder()
    {
        foreach (var npc in spawnedNpcs)
        {
            npc.StartMove();
            yield return new WaitForSeconds(npcActivateInterval);
        }
    }
}

第二步 修改Waypoints脚本

删除原Start方法里的StartCoroutine(MoveNpc());调用,新增公共启动方法,同时可以删除原路径点查找逻辑:

// 原Start方法修改后
void Start()
{
    // 下面这行查找路径点的代码可以删掉,路径点已经由管理器直接赋值
    // waypoints = GameObject.FindGameObjectsWithTag("Waypoint").ToList();

    numberOfWaypoints = waypoints.Count;

    if (reverse)
    {
        waypointIndex = waypoints.Count - 1;
    }
    else
    {
        waypointIndex = 0;
    }

    // 删掉原来的StartCoroutine(MoveNpc());
}

// 新增公共启动方法
public void StartMove()
{
    go = true;
    // 如果你需要每个NPC启动时再额外等待3秒,就把上面的go=true换成下面的协程调用
    // StartCoroutine(MoveNpc());
}

// 其他原有代码保持不变

方案2:仅修改NPC脚本实现(无需改动管理器)

如果不想改动管理器代码,可以用静态变量记录累计延迟时间,实现每个NPC的延迟依次叠加:

public class Waypoints : MonoBehaviour
{
    // 新增静态变量,累计所有NPC的延迟时间
    private static float totalActivateDelay = 0f;

    // 其他原有变量保持不变...

    void Start()
    {
        waypoints = GameObject.FindGameObjectsWithTag("Waypoint").ToList();

        numberOfWaypoints = waypoints.Count;

        if (reverse)
        {
            waypointIndex = waypoints.Count - 1;
        }
        else
        {
            waypointIndex = 0;
        }

        StartCoroutine(MoveNpc());
    }

    private IEnumerator MoveNpc()
    {
        // 每个NPC的等待时间依次叠加3秒
        float currentDelay = totalActivateDelay;
        totalActivateDelay += 3f;
        yield return new WaitForSeconds(currentDelay);

        go = true;
    }

    // 其他原有方法保持不变...
}

注意:该方案的静态变量会在场景重载、二次进入场景时保留累计值,导致延迟计算错误,你可以在场景卸载时手动重置totalActivateDelay = 0f避免该问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 23:36:00