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

Unity Scriptable Object运行时赋值未更新问题求助

Scriptable Object修改后UnitStats加载旧值的解决方法

问题描述

我用Scriptable Object作为单位数据库,每个单位通过UnitStats脚本的Start()方法加载数据库中的属性。此前运行正常,但今日修改Scriptable Object中的变量(如将maxHP从100改为110)后,UnitStats加载的数值仍为旧值。尝试过保存项目、提交Unity版本控制、重启Unity,Scriptable Object内的maxHP显示为110,但UnitStats加载的数值依旧是100。

附UnitStats脚本:

using System.Collections.Generic;
using UnityEngine;

public class UnitStats : MonoBehaviour
{
    [HideInInspector]
    public string unitName;
    [HideInInspector]
    public float attackRange;
    [HideInInspector]
    public float movementSpeed;
    [HideInInspector]
    public int maxHP;
    [HideInInspector]
    public int currentHP;
    [HideInInspector]
    public string type;
    [HideInInspector]
    public float attackInterval; 
    [HideInInspector]
    public int priority;
    [HideInInspector]
    public int dpa;
    //[HideInInspector]
    public int searchRange;
    [SerializeField] UnitDatabaseSO unitDatabase;
    [SerializeField] int ID;
    public Dictionary<GameObject, int> abilities;
    private UnitData unitData;
    [HideInInspector]
    public bool loaded;
    [HideInInspector]
    public float damageTime;
    [HideInInspector]
    public bool ranged;
    [HideInInspector]
    public float buildTime;
    [HideInInspector]
    public Sprite spriteIcon;
    [HideInInspector]
    public int visionRange;
    [HideInInspector]
    public int bloodDrop;
    [HideInInspector]
    public int bloodCost;
    [HideInInspector]
    public string description;
    [HideInInspector]
    public bool isWorker;
    [HideInInspector]
    public int MaxBloodPool;
    [HideInInspector]
    public int bloodAmount;
    [HideInInspector]
    public float height;

    void Start(){
        if(!loaded){
            unitData = unitDatabase.objectsData[ID];
            unitName = unitData.Name;
            attackRange = unitData.AttackRange;
            movementSpeed = unitData.MovementSpeed;
            maxHP = unitData.maxHP;
            currentHP = maxHP;
            type = unitData.Type;
            attackInterval = unitData.AttackInerval;
            priority = unitData.Priority;
            dpa = unitData.DPH;
            searchRange = unitData.SearchRange;
            damageTime = unitData.DamageTime;
            ranged = unitData.ranged;
            spriteIcon = unitData.SpriteIcon;
            buildTime = unitData.buildTime;
            visionRange = unitData.VisionRange;
            bloodDrop = unitData.BloodDrop;
            bloodCost = unitData.BloodCost;
            description = unitData.Description;
            isWorker = unitData.IsWorker;
            MaxBloodPool = unitData.MaxBloodPool;
            bloodAmount = 0;
            height = unitData.height;
            loaded = true;
        }
        HPBarManager.instance.CreateHPBar(transform, currentHP/maxHP);
    }

    public void AssignID(int ID){
        this.ID = ID;
    }
    public void ReceiveDmg(GameObject source, int damage){
        currentHP -= damage;
        if(currentHP <= 0){
            GetComponent<UnitStateMachine>().TransitState(UnitStateMachine.Unitstate.Dead);
            return;
        }
        HPBarManager.instance.UpdateHPBar(transform, currentHP/maxHP);
    }

    public void GainHP(int heal){
        if(currentHP + heal >= maxHP){
            currentHP = maxHP;
        }else{
            currentHP += heal;
        }
        HPBarManager.instance.UpdateHPBar(transform, currentHP/maxHP);
    }

    public bool IsDead(){
        return currentHP <= 0;
    }

    public int GetID(){
        return ID;
    }
}

解决方法

  • 重置loaded标志位:脚本里的loaded变量默认未初始化,可能在场景运行后被保留为true,导致后续无法重新加载数据。可以在OnEnable()方法里强制重置loaded为false,或者直接给变量初始值[HideInInspector] public bool loaded = false;。修改后的加载逻辑示例:

    void OnEnable()
    {
        loaded = false;
    }
    
    void Start(){
        LoadUnitData();
        // 转成float做除法,避免整数相除得到0或1的错误结果
        HPBarManager.instance.CreateHPBar(transform, (float)currentHP/maxHP);
    }
    
    private void LoadUnitData()
    {
        if(!loaded && unitDatabase != null && ID >= 0 && ID < unitDatabase.objectsData.Count)
        {
            unitData = unitDatabase.objectsData[ID];
            // 所有赋值逻辑保持不变
            loaded = true;
        }
    }
    
  • 验证Scriptable Object引用:检查场景中每个挂载UnitStats组件的对象,确认绑定的unitDatabase是你修改的那个SO文件,避免误绑定旧副本或其他SO。

  • 清理Unity缓存:

    • 点击顶部菜单Assets -> Refresh刷新所有资源
    • 关闭Unity后,删除项目根目录下的Library文件夹,重启Unity会自动重新生成缓存文件
  • 规范修改流程:不要在Play模式下修改Scriptable Object的数据,确保在Edit模式下修改并保存SO,再进入Play模式测试,避免数据未正确写入磁盘。

  • 检查UnitData序列化:确认UnitData类中的maxHP等字段是可序列化的——要么是public字段,要么加了[SerializeField]属性,且没有被[NonSerialized]标记,否则SO中的修改无法被正确读取。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 05:54:53