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

在Unity中用ScriptableObject替代Enum是否过度设计?

阵营关系处理:ScriptableObject vs 带显式值的Enum

核心结论

不是你对ScriptableObject(简称SO)的使用有误解,而是两种方案各有适用场景——关键看你的阵营/关系需求是动态配置导向还是轻量固定导向。

方案一:带显式值的Enum(适合固定场景)

如果你的阵营数量少、关系逻辑长期稳定(比如默认敌对,仅少数友好组合),带显式值的Enum完全够用,而且简单直接。

解决Enum的修改隐患:给每个阵营Enum指定固定的、间隔较大的整数值,避免调整顺序或删除元素时破坏序列化数据。配合静态关系映射字典,就能快速获取阵营关系:

public enum Faction
{
    A = 100,
    B = 200,
    C = 300
}

public enum RelationshipType
{
    Hostile,
    Friendly,
    Neutral
}

public static class FactionRelations
{
    private static readonly Dictionary<(Faction, Faction), RelationshipType> _relationMap = new()
    {
        {(Faction.A, Faction.B), RelationshipType.Hostile},
        {(Faction.A, Faction.C), RelationshipType.Friendly},
        // 补充其他需要自定义的阵营组合
    };

    public static RelationshipType GetRelation(Faction a, Faction b)
    {
        return _relationMap.TryGetValue((a, b), out var rel) ? rel : RelationshipType.Hostile;
    }

    // 简化业务代码调用的快捷方法
    public static bool IsHostile(Faction a, Faction b) => GetRelation(a, b) == RelationshipType.Hostile;
}

这种方案优势是代码轻量、性能好,不需要额外的SO资源,适合小体量、需求稳定的场景。

方案二:优化后的ScriptableObject方案(适合动态配置场景)

你之前的SO方案问题在于关系分散管理,导致获取关系繁琐。正确的做法是用一个全局关系数据库SO统一管理所有阵营关系,发挥SO可编辑、无需编译的优势。

优化后的结构:

  1. FactionSO:仅存储阵营基础标识(名称、唯一ID),不包含关系逻辑
  2. FactionRelationDatabaseSO:作为全局可引用资源,集中存储所有阵营间的关系映射
  3. RelationshipType:用简单Enum定义固定的关系类型(敌对/友好/中立),因为这类类型很少变动

示例代码:

// 阵营SO,仅存基础信息
[CreateAssetMenu(fileName = "NewFaction", menuName = "Game/Faction")]
public class FactionSO : ScriptableObject
{
    public string factionName;
    public Guid factionId; // 用Guid避免重名或引用失效问题
}

// 固定的关系类型Enum
public enum RelationshipType
{
    Hostile,
    Friendly,
    Neutral
}

// 全局关系数据库SO
[CreateAssetMenu(fileName = "FactionRelationDB", menuName = "Game/Faction Relation Database")]
public class FactionRelationDatabaseSO : ScriptableObject
{
    [Serializable]
    public class RelationEntry
    {
        public FactionSO factionA;
        public FactionSO factionB;
        public RelationshipType relation;
    }

    public List<RelationEntry> relationEntries;
    private Dictionary<(FactionSO, FactionSO), RelationshipType> _relationCache;

    private void OnEnable()
    {
        // 初始化缓存,避免每次遍历列表
        _relationCache = new Dictionary<(FactionSO, FactionSO), RelationshipType>();
        foreach (var entry in relationEntries)
        {
            _relationCache[(entry.factionA, entry.factionB)] = entry.relation;
            // 若关系是双向的(A对B友好则B对A也友好),添加反向映射;单向关系则去掉这行
            _relationCache[(entry.factionB, entry.factionA)] = entry.relation;
        }
    }

    public RelationshipType GetRelation(FactionSO a, FactionSO b)
    {
        return _relationCache.TryGetValue((a, b), out var type) ? type : RelationshipType.Hostile;
    }

    // 快捷判断方法,简化业务代码调用
    public bool IsHostile(FactionSO a, FactionSO b) => GetRelation(a, b) == RelationshipType.Hostile;
    public bool IsFriendly(FactionSO a, FactionSO b) => GetRelation(a, b) == RelationshipType.Friendly;
}

这种方案的优势:

  • 策划可直接在Unity编辑器中添加/修改阵营关系,无需修改代码或重新编译
  • 支持后期动态新增阵营,扩展性强
  • 关系逻辑集中管理,避免分散维护的混乱

如何选择?

  • 选带显式值的Enum:阵营数量固定(比如你现在的A/B/C三个)、关系逻辑很少变动,且不需要可视化配置
  • 选优化后的SO方案:后期可能新增大量阵营、需要非技术人员调整关系,或者存在单向关系等复杂逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 03:05:24