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

如何保存同一Scriptable Object实例化的多份修改后预制件?是否需用唯一ID?

解决方案:保存多实例武器的修改数据与唯一ID设计

问题1:保存同一Scriptable Object实例化的多件修改后武器

Scriptable Object(SO)是全局共享的模板数据,直接修改SO变量会导致所有同类型武器同步变化,必须给每个实例化武器单独存储修改后数据,核心思路是「模板SO + 实例独有数据」分离:

步骤1:定义实例数据载体

创建可序列化类,专门存储单把武器的修改后变量(如等级、伤害、配件):

[System.Serializable]
public class WeaponInstanceData
{
    public int uniqueId; // 对应问题2的唯一标识
    public int level;
    public float modifiedDamage;
    public bool hasScope;
    // 其他升级/自定义变量
}

步骤2:改造库存项结构

把原库存中直接存储的BaseWeaponSO,替换成「模板SO + 实例数据」的组合类,同一SO可对应多个独立实例数据:

[System.Serializable]
public class InventoryItem
{
    public BaseWeaponSO baseWeapon; // 原武器模板SO
    public WeaponInstanceData instanceData; // 该物品的独有修改数据
}

若不想大规模重构原有库存逻辑,可临时用字典映射:Dictionary<BaseWeaponSO, List<WeaponInstanceData>>,但长期来看InventoryItem结构更清晰。

步骤3:装备/卸下时的数据同步

  • 装备时:实例化预制件后,将WeaponInstanceData数值同步到武器组件:
public void EquipWeapon(InventoryItem item)
{
    GameObject weaponObj = Instantiate(item.baseWeapon.weaponPrefab, playerHand);
    WeaponController weaponCtrl = weaponObj.GetComponent<WeaponController>();
    
    // 同步实例数据到组件
    weaponCtrl.currentLevel = item.instanceData.level;
    weaponCtrl.currentDamage = item.instanceData.modifiedDamage;
    weaponCtrl.hasScope = item.instanceData.hasScope;
}
  • 卸下时:先把武器组件当前修改值同步回WeaponInstanceData,再销毁预制件:
public void UnequipWeapon(InventoryItem item, WeaponController currentWeapon)
{
    // 同步组件数据回实例载体
    item.instanceData.level = currentWeapon.currentLevel;
    item.instanceData.modifiedDamage = currentWeapon.currentDamage;
    item.instanceData.hasScope = currentWeapon.hasScope;
    
    Destroy(currentWeapon.gameObject);
}

步骤4:保存与加载

直接序列化List<InventoryItem>即可,例如用Unity的JsonUtility:

// 保存
string saveData = JsonUtility.ToJson(new SaveData { inventoryItems = inventory });
PlayerPrefs.SetString("WeaponInventory", saveData);

// 加载
string loadData = PlayerPrefs.GetString("WeaponInventory");
SaveData loadedData = JsonUtility.FromJson<SaveData>(loadData);
inventory = loadedData.inventoryItems;

其中SaveData是包裹序列化列表的容器类:

[System.Serializable]
public class SaveData
{
    public List<InventoryItem> inventoryItems;
}

问题2:是否需要给武器创建唯一ID?

必须要,但不是让SO实例化对应ID的武器,而是给每个WeaponInstanceData分配唯一ID,核心作用:

  • 区分同一模板生成的多件武器(比如两把AK,一把LV3一把LV1),避免操作数据时混淆
  • 存档加载时,通过ID可准确关联实例数据和模板SO(比如存档存ID,加载时用ID匹配对应的BaseWeaponSO)
  • 升级系统中,每个武器实例的进度独立,ID是唯一标识

生成唯一ID的方式

在拾取武器时生成,例如用自增整数或GUID:

// 拾取武器时创建实例数据
public void PickupWeapon(BaseWeaponSO weapon)
{
    WeaponInstanceData newInstanceData = new WeaponInstanceData();
    // 方式1:自增ID(需全局维护计数器)
    newInstanceData.uniqueId = GlobalWeaponIdCounter++;
    // 方式2:GUID哈希(无需维护计数器)
    newInstanceData.uniqueId = Guid.NewGuid().GetHashCode();
    
    inventory.Add(new InventoryItem { baseWeapon = weapon, instanceData = newInstanceData });
}

额外建议(针对升级系统)

  • 不要在SO中存储任何实例相关变量,SO仅作为「基础模板」(如基础伤害、初始等级)
  • 武器组件(WeaponController)只存当前运行时数值,所有持久化数据都存在WeaponInstanceData中
  • 若担心序列化问题,可将BaseWeaponSO的唯一标识(如字符串ID)也存入InventoryItem,加载时通过ID从资源中加载对应SO,避免直接存SO引用的序列化风险

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 16:24:20