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

Unity平台生成重叠卡顿问题求助(附移动与生成脚本)

问题描述

我编写了一套可定期生成平台的Unity脚本,但运行一段时间后平台会聚集在一起,导致严重卡顿。以下是平台移动脚本SetMove与生成脚本set_make:

平台移动脚本

using System.Collections;
using UnityEngine;

public class SetMove : MonoBehaviour
{
    int j;
    int y;

    private IEnumerator Start()
    {
        y = Random.Range(15, 20);

        Rigidbody2D playerRG = GameObject.Find("player").GetComponent<Rigidbody2D>();

        while (transform.position.x > -15)
        {
            yield return new WaitForSecondsRealtime(0.1f);

            transform.Translate(Vector3.left / 5);

            j++;

            if (j == y)
            {
                GameObject.Find("controller").GetComponent<set_make>().StartCoroutine("Start");

                y = Random.Range(15, 20);
            }

            if (playerRG.gravityScale == 0 && transform.position.x <= 0)
            {
                playerRG.gravityScale = 1;
                GameObject player = playerRG.gameObject;
                player.transform.position = transform.position + new Vector3(0, transform.localScale.y / 2);
            }
        }

        Destroy(gameObject);
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        GameObject.Find("player").GetComponent<player>().canJump = true;
    }

    private void OnTriggerExit2D(Collider2D collision)
    {
        GameObject.Find("player").GetComponent<player>().canJump = false;
    }
}

平台生成脚本

using System.Collections.Generic;
using UnityEngine;
 
public class set_make : MonoBehaviour
{
    public GameObject short_block;
    public GameObject long_block;
    public GameObject med_block;
    int num;
    int pastnum;

    public void Start()
    {
        float level = -3.5f; 
        num = Random.Range(1, 4);
        switch (num)
        {
            case 1:
                Instantiate(short_block, new Vector3(13, level + 0.5f), Quaternion.identity);
                pastnum = num;
                break;
            case 2:
                Instantiate(med_block, new Vector3(13, level + 1f), Quaternion.identity);
                pastnum = num;
                break;
            case 3:
                if (pastnum != 1)
                {
                    Instantiate(long_block, new Vector3(13, level + 1.5f), Quaternion.identity);
                    pastnum = num;
                }
                else
                {
                    Start();
                }
                break;
        }
    }
}

我尝试调整生成间隔但无效果,请求协助解决该卡顿问题。


问题分析与修复方案

核心卡顿原因

  1. 重复生成逻辑触发:SetMove协程中每次j == y时,都会调用set_make的Start方法作为协程执行,导致多个生成逻辑同时运行,短时间内生成大量平台堆积。
  2. 递归生成的栈溢出风险:set_make的Start方法在不符合长平台生成条件时直接递归调用自己,可能瞬间触发多次生成,加剧平台聚集。
  3. 高频GameObject.Find调用:在协程和触发器方法中反复使用GameObject.Find,这是性能开销极高的操作,会放大卡顿问题。

具体修复步骤

1. 重构生成脚本,控制生成节奏

将生成逻辑改为协程管理,添加生成锁避免重复触发,同时移除递归调用:

using UnityEngine;
using System.Collections;

public class set_make : MonoBehaviour
{
    public GameObject short_block;
    public GameObject long_block;
    public GameObject med_block;
    int num;
    int pastnum;
    private bool isGenerating = false; // 防止重复生成的标记

    private void Start()
    {
        // 启动自动生成协程
        StartCoroutine(GenerateLoop());
    }

    private IEnumerator GenerateLoop()
    {
        isGenerating = true;
        float level = -3.5f;
        num = Random.Range(1, 4);

        switch (num)
        {
            case 1:
                Instantiate(short_block, new Vector3(13, level + 0.5f), Quaternion.identity);
                pastnum = num;
                break;
            case 2:
                Instantiate(med_block, new Vector3(13, level + 1f), Quaternion.identity);
                pastnum = num;
                break;
            case 3:
                if (pastnum != 1)
                {
                    Instantiate(long_block, new Vector3(13, level + 1.5f), Quaternion.identity);
                    pastnum = num;
                }
                else
                {
                    // 不符合条件时重新生成,用yield避免递归栈溢出
                    yield return GenerateLoop();
                    yield break;
                }
                break;
        }

        // 设置和平台移动速度匹配的生成间隔(平台每秒移动2单位,从x=13到x=-15需14秒,间隔设为8-12秒避免堆积)
        float spawnInterval = Random.Range(8f, 12f);
        yield return new WaitForSeconds(spawnInterval);

        isGenerating = false;
        // 循环启动下一次生成
        StartCoroutine(GenerateLoop());
    }
}

2. 优化移动脚本,移除重复生成调用

提前缓存所有需要的组件引用,移除触发生成的逻辑,让生成器自主控制节奏:

using System.Collections;
using UnityEngine;

public class SetMove : MonoBehaviour
{
    int j;
    int y;
    private Rigidbody2D playerRG;
    private player playerScript;

    private void Awake()
    {
        // 仅在初始化时获取一次引用,避免高频查找
        GameObject playerObj = GameObject.Find("player");
        playerRG = playerObj.GetComponent<Rigidbody2D>();
        playerScript = playerObj.GetComponent<player>();
    }

    private IEnumerator Start()
    {
        y = Random.Range(15, 20);

        while (transform.position.x > -15)
        {
            yield return new WaitForSecondsRealtime(0.1f);
            transform.Translate(Vector3.left / 5);
            j++;

            // 移除此处的生成触发逻辑,由生成器自主控制
            // if (j == y)
            // {
            //     GameObject.Find("controller").GetComponent<set_make>().StartCoroutine("Start");
            //     y = Random.Range(15, 20);
            // }

            if (playerRG.gravityScale == 0 && transform.position.x <= 0)
            {
                playerRG.gravityScale = 1;
                playerRG.transform.position = transform.position + new Vector3(0, transform.localScale.y / 2);
            }
        }

        Destroy(gameObject);
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        // 给Player添加标签,用标签判断更高效
        if (collision.CompareTag("Player"))
        {
            playerScript.canJump = true;
        }
    }

    private void OnTriggerExit2D(Collider2D collision)
    {
        if (collision.CompareTag("Player"))
        {
            playerScript.canJump = false;
        }
    }
}

3. 额外性能优化建议

  • 给平台添加对象池,复用已销毁的平台对象,避免频繁Instantiate和Destroy的性能开销。
  • 给player和controller对象添加标签,使用GameObject.FindWithTag替代GameObject.Find,进一步提升查找效率。
  • 检查平台的Collider设置,禁用不必要的碰撞检测,减少物理计算开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 04:37:54