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

Unity实例化对象交互异常求助:独立缩放与销毁逻辑故障

问题分析与修复方案

核心问题根源

  1. 全局脚本共享状态:用同一个全局脚本(如Spawner上的脚本)处理所有克隆体的协程,导致所有克隆体的缩放逻辑依赖全局的targetID和morphSizeController变量,新实例化对象时会覆盖这些全局值,进而影响所有旧对象的缩放。
  2. 索引错误:thisMorphClone = morphSpawnerScript.morphClones[this.targetID + 1];中targetID +1逻辑错误,targetID本身是从0开始的自增ID,直接用targetID作为数组索引即可,否则会取到错误对象。
  3. 按键监听与销毁不绑定:协程未绑定到具体克隆体对应的按键,导致释放任意按键都会触发所有对象的销毁逻辑。

修复步骤

1. 重构克隆体控制器,让每个对象独立管理自身逻辑

将大小插值、按键监听逻辑移到每个克隆体专属的MorphSizeController脚本中,确保每个对象的状态独立,互不干扰:

public class MorphSizeController : MonoBehaviour
{
    public int ID;
    public KeyCode boundKey; // 绑定当前对象对应的按键
    public float attackTime = 0.5f;
    public float decayTime = 0.3f;
    public float sustainValue = 0.8f;
    public float durationRelease = 0.4f;

    private Coroutine currentLerpCoroutine;

    // 启动当前对象的大小插值流程
    public void StartLerpChain()
    {
        if(currentLerpCoroutine != null)
        {
            StopCoroutine(currentLerpCoroutine);
        }
        currentLerpCoroutine = StartCoroutine(PerformLerpChain());
    }

    private IEnumerator PerformLerpChain()
    {
        bool keyReleased = false;
        // 攻击阶段插值
        yield return StartCoroutine(LerpTransformWithKeyCheck(0, 1, attackTime, transform, boundKey, () => keyReleased = true));
        
        if(!keyReleased)
        {
            // 衰减阶段插值
            keyReleased = false;
            yield return StartCoroutine(LerpTransformWithKeyCheck(1, sustainValue, decayTime, transform, boundKey, () => keyReleased = true));

            // 按住按键时保持当前大小
            if (!keyReleased)
            {
                while (Input.GetKey(boundKey))
                {
                    yield return null;
                }
            }
        }

        // 释放阶段插值后隐藏对象
        yield return StartCoroutine(LerpTransform(sustainValue, 0, durationRelease, transform));
        gameObject.SetActive(false);
        // 如需直接销毁可替换为:Destroy(gameObject);
    }

    private IEnumerator LerpTransform(float start, float end, float duration, Transform lerpingObject)
    {
        float startTime = Time.time;
        float elapsedTime = 0f;

        while (elapsedTime < duration)
        {
            elapsedTime = Time.time - startTime;
            float t = elapsedTime / duration;
            lerpingObject.localScale = Vector3.Lerp(Vector3.one * start, Vector3.one * end, t);
            yield return null;
        }
    }

    private IEnumerator LerpTransformWithKeyCheck(float start, float end, float duration, Transform lerpingObject, KeyCode key, System.Action onKeyReleased)
    {
        float startTime = Time.time;
        float elapsedTime = 0f;
        bool sameKeyReleased = false;

        while (elapsedTime < duration && !sameKeyReleased)
        {
            elapsedTime = Time.time - startTime;
            float t = elapsedTime / duration;
            lerpingObject.localScale = Vector3.Lerp(Vector3.one * start * 100, Vector3.one * end * 100, t);

            if (Input.GetKeyUp(key))
            {
                sameKeyReleased = true;
                onKeyReleased?.Invoke();
            }

            yield return null;
        }
    }
}

2. 修改实例化函数,绑定按键并启动独立逻辑

在Spawner的InstantiateMorph函数中,给每个克隆体绑定对应按键,并直接启动它的专属插值逻辑:

// 新增参数:传入当前按下的按键
public GameObject InstantiateMorph(Vector3 spawnPosition, KeyCode pressedKey)
{
    GameObject morphClone = Instantiate(morphObject, spawnPosition, Quaternion.identity);
    morphClone.SetActive(true);

    morphClones.Add(morphClone);
    latestMorphCloneIndex = morphClones.Count - 1;
    latestMorphClone = morphClones[latestMorphCloneIndex];

    // 获取或添加控制器组件
    MorphSizeController morphSizeController = morphClone.GetComponent<MorphSizeController>();
    if(morphSizeController == null)
    {
        morphSizeController = morphClone.AddComponent<MorphSizeController>();
    }
    SizeController2 sizeController = morphClone.GetComponent<SizeController2>();

    // 设置唯一ID
    int currentID = _idCounter++;
    sizeController.targetID = currentID;
    morphSizeController.ID = currentID;
    sizeController.tag = currentID.ToString(); 

    // 绑定按键并启动逻辑
    morphSizeController.boundKey = pressedKey;
    morphSizeController.StartLerpChain();

    return morphClone;
}

3. 修复按键检测逻辑,确保每个按键对应独立实例

在Spawner的Update函数中,按下不同按键时传入对应KeyCode调用实例化函数:

void Update()
{
    // 示例:检测WASD按键,可根据需求扩展
    if(Input.GetKeyDown(KeyCode.W))
    {
        InstantiateMorph(new Vector3(0,1,0), KeyCode.W);
    }
    if(Input.GetKeyDown(KeyCode.A))
    {
        InstantiateMorph(new Vector3(-1,0,0), KeyCode.A);
    }
    if(Input.GetKeyDown(KeyCode.S))
    {
        InstantiateMorph(new Vector3(0,-1,0), KeyCode.S);
    }
    if(Input.GetKeyDown(KeyCode.D))
    {
        InstantiateMorph(new Vector3(1,0,0), KeyCode.D);
    }
}

关键修复点说明

  • 每个克隆体的逻辑完全独立,不再依赖全局变量,新实例化对象不会影响旧对象的缩放。
  • 每个对象只监听自己绑定的按键,释放对应按键才会触发自身的隐藏/销毁逻辑,不会干扰其他对象。
  • 移除了全局脚本中错误的索引引用和共享状态判断,确保每个对象的插值只作用于自身。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 05:45:19