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

Unity游戏开发:实现生成点激活/停用,解决重复碰撞问题

解决方案

核心修改点

  1. 新增变量记录当前激活的SpawnPoint,避免重复触发
  2. 碰撞时禁用当前SpawnPoint的碰撞器,切换到其他点时重新启用旧点的碰撞器
  3. 调整生成逻辑,只在当前选中的SpawnPoint生成对象,匹配需求

修改后的完整代码

public class NewSpawnScript : MonoBehaviour
{
    public GameObject[] SpawnPoints;
    public float spawnTime = 2.5f;
    public GameObject[] threeD;
    public List<GameObject> possibleThreeD = new List<GameObject>();
    // 记录当前激活的SpawnPoint,用于切换时重新启用旧点
    private GameObject currentActiveSpawnPoint;
    // 标记是否已开启生成循环,避免重复调用InvokeRepeating
    private bool isSpawning = false;

    void Start()
    {
        // 初始化可生成对象列表
        foreach (var obj in threeD)
        {
            possibleThreeD.Add(obj);
        }
    }

    private void OnTriggerEnter(Collider other)
    {
        // 只响应玩家对象(你的标记为"Obj")
        if (other.CompareTag("Obj"))
        {
            GameObject hitSpawnPoint = gameObject;

            // 若之前有激活的SpawnPoint,重新启用它的碰撞器
            if (currentActiveSpawnPoint != null && currentActiveSpawnPoint != hitSpawnPoint)
            {
                currentActiveSpawnPoint.GetComponent<Collider>().enabled = true;
            }

            // 禁用当前SpawnPoint的碰撞器,防止持续触发
            GetComponent<Collider>().enabled = false;
            currentActiveSpawnPoint = hitSpawnPoint;

            // 重置可生成对象列表(若允许重复生成相同对象可注释此段)
            possibleThreeD.Clear();
            foreach (var obj in threeD)
            {
                possibleThreeD.Add(obj);
            }

            // 控制生成循环:未开启则启动,已开启则重置定时器
            if (!isSpawning)
            {
                InvokeRepeating(nameof(SpawnItems), spawnTime, spawnTime);
                isSpawning = true;
            }
            else
            {
                CancelInvoke(nameof(SpawnItems));
                InvokeRepeating(nameof(SpawnItems), spawnTime, spawnTime);
            }
        }
    }

    void SpawnItems()
    {
        if (currentActiveSpawnPoint != null && possibleThreeD.Count > 0)
        {
            // 随机选择要生成的对象
            int spawnObjectIndex = Random.Range(0, possibleThreeD.Count);
            GameObject spawnObj = possibleThreeD[spawnObjectIndex];

            // 在当前激活的SpawnPoint位置生成对象
            GameObject newObj = Instantiate(spawnObj, currentActiveSpawnPoint.transform.position, currentActiveSpawnPoint.transform.rotation);
            
            // 关联SpawnPoint到Destroyer脚本(保留原有逻辑)
            Destroyer destroyer = newObj.GetComponent<Destroyer>();
            if (destroyer != null)
            {
                destroyer.mySpawnPoint = currentActiveSpawnPoint;
                newObj.transform.parent = currentActiveSpawnPoint.transform;
            }

            // 若需避免重复生成相同对象,移除该对象;否则注释此行
            possibleThreeD.RemoveAt(spawnObjectIndex);

            // 对象列表为空时重置(可选,根据需求调整)
            if (possibleThreeD.Count == 0)
            {
                foreach (var obj in threeD)
                {
                    possibleThreeD.Add(obj);
                }
            }
        }
    }
}

关键逻辑说明

  • 禁用碰撞器:玩家碰撞SpawnPoint后,立即禁用该点的Collider,阻止后续重复触发OnTriggerEnter,直到切换到其他点时重新启用。
  • SpawnPoint切换:碰撞新的SpawnPoint时,先重新开启旧点的碰撞器,再禁用当前点,保证同一时间只有一个SpawnPoint处于“不可触发”状态。
  • 生成逻辑修正:将原随机多点生成改为仅在当前激活的SpawnPoint生成,匹配“碰撞哪个点就从哪个点生成”的需求。
  • 避免重复循环:用isSpawning标记控制生成循环,防止多次触发导致生成频率异常。

额外注意事项

  • 确保每个SpawnPoint对象都挂载此脚本,且碰撞器的Is Trigger选项已勾选。
  • 若Destroyer脚本负责对象重生,无需额外处理SpawnPoint状态,状态切换仅由玩家碰撞触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 06:05:36