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

Unity同一脚本内跨类引用变量:波次生成系统实现遇阻

解决Unity波次生成系统中嵌套类无法引用外部列表的问题

针对你遇到的嵌套类Bubble无法访问WaveSystemScript中validBubbles列表,且希望在Inspector中从有效列表选择预制体的需求,这里提供两种实用解决方案:


方案一:自定义Inspector PropertyDrawer(实现下拉选择)

这是最贴合需求的方案,通过自定义属性抽屉,让Bubble类的bubbleSelection在Inspector中显示为下拉菜单,选项直接取自validBubbles列表。

步骤1:调整类结构(改为内部类)

先把Bubble和Waves改为WaveSystemScript的内部类,方便自定义Drawer访问外部类的列表:

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

public class WaveSystemScript : MonoBehaviour
{
    [SerializeField] private WaveBubbleScriptableObject waveBubbleSO;
    [SerializeField] private List<GameObject> validBubbles = new List<GameObject>();
    [SerializeField] private List<Waves> waveList = new List<Waves>();

    [System.Serializable]
    public class Bubble
    {
        [SerializeField] private GameObject bubbleSelection;
        [SerializeField] private float spawnInterval;

        // 提供Getter供外部验证使用
        public GameObject BubbleSelection => bubbleSelection;
    }

    [System.Serializable]
    public class Waves
    {
        [SerializeField] private List<Bubble> waveBubbles = new List<Bubble>();
        [SerializeField] private float waveLength; // 改为可序列化,方便在Inspector编辑
    }
}

步骤2:创建自定义PropertyDrawer

在Editor目录下创建BubbleDrawer.cs(必须放在Editor文件夹,否则无法识别):

using UnityEditor;
using UnityEngine;
using System.Collections.Generic;

[CustomPropertyDrawer(typeof(WaveSystemScript.Bubble))]
public class BubbleDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        EditorGUI.BeginProperty(position, label, property);

        // 获取当前挂载WaveSystemScript的组件实例
        WaveSystemScript waveSystem = property.serializedObject.targetObject as WaveSystemScript;
        if (waveSystem == null)
        {
            EditorGUI.PropertyField(position, property, label);
            EditorGUI.EndProperty();
            return;
        }

        // 拆分布局:左侧下拉选择气泡,右侧输入生成间隔
        Rect selectionRect = new Rect(position.x, position.y, position.width * 0.7f, EditorGUIUtility.singleLineHeight);
        Rect intervalRect = new Rect(position.x + position.width * 0.7f + 8, position.y, position.width * 0.3f - 8, EditorGUIUtility.singleLineHeight);

        // 构建下拉选项列表(包含空选项)
        List<string> bubbleNames = new List<string> { "None" };
        List<GameObject> bubbleObjects = new List<GameObject> { null };

        foreach (var bubblePrefab in waveSystem.validBubbles)
        {
            if (bubblePrefab != null)
            {
                bubbleNames.Add(bubblePrefab.name);
                bubbleObjects.Add(bubblePrefab);
            }
        }

        // 获取当前选中的气泡属性
        SerializedProperty selectionProp = property.FindPropertyRelative("bubbleSelection");
        int selectedIndex = bubbleObjects.IndexOf(selectionProp.objectReferenceValue);
        selectedIndex = selectedIndex < 0 ? 0 : selectedIndex;

        // 绘制下拉菜单并赋值
        selectedIndex = EditorGUI.Popup(selectionRect, label.text, selectedIndex, bubbleNames.ToArray());
        selectionProp.objectReferenceValue = bubbleObjects[selectedIndex];

        // 绘制生成间隔输入框
        EditorGUI.PropertyField(intervalRect, property.FindPropertyRelative("spawnInterval"), GUIContent.none);

        EditorGUI.EndProperty();
    }

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        return EditorGUIUtility.singleLineHeight;
    }
}

效果说明

完成后,在Inspector中编辑waveList里的每个Bubble项时,bubbleSelection会变成下拉菜单,只能选择validBubbles中的预制体或空选项,完全符合你的需求。如果要改用ScriptableObject中的列表,只需把waveSystem.validBubbles替换为waveSystem.waveBubbleSO.xxx(对应SO中的列表字段)即可。


方案二:OnValidate验证引用(简单防错)

如果不需要下拉选择,只是希望确保bubbleSelection的引用来自有效列表,可以在WaveSystemScript中添加OnValidate方法做验证:

private void OnValidate()
{
    foreach (var wave in waveList)
    {
        foreach (var bubble in wave.waveBubbles)
        {
            if (bubble.BubbleSelection != null && !validBubbles.Contains(bubble.BubbleSelection))
            {
                Debug.LogWarning($"无效的气泡引用:{bubble.BubbleSelection.name},已自动置空", this);
                // 这里需要通过反射修改私有字段,或者把bubbleSelection改为public
                var selectionField = typeof(WaveSystemScript.Bubble).GetField("bubbleSelection", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                selectionField?.SetValue(bubble, null);
            }
        }
    }
}

这种方法会在Inspector修改后自动检查,若引用不在有效列表中则置空并提示,适合快速实现引用校验的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 09:01:22