# FAQ

## **It seems like you might need to have every individual variable be its own scriptable object, so for 50 enemies, each enemy’s HP would be 50 different scriptable variables?**&#x20;

Yes. If you don’t want to create the variables beforehand, you can instantiate Scriptable variables at runtime containing the HP and pass it as a reference to your different systems (see [Runtime Variables](/soap/soap-core-assets/scriptable-variable/runtime-variables.md) and [Runtime Injectors](/soap/soap-core-assets/runtime-injectors.md)).

However, maybe that is not the best approach. Scriptable variables are best for things that have dependencies with other systems but are singular. It suits more for things like Player HP or a Boss HP as well. For many enemies maybe it's overkill.

Most of the time, if there are a lot of enemies, you don’t really want or need to solve dependency with their individual stats. Instead, the most common use case is to create a [Scriptable List](/soap/soap-core-assets/scriptable-list.md) of enemies that you can reference anywhere (solving most of your dependencies) and access their stats there.

## Why OnValueChanged doesn't trigger when you modify a field in a custom C# class ? (And how to fix it)

If you define a class like this:

```csharp
[System.Serializable]
public class Stats
{
    public float Speed;
    public int Damage;
}
```

And you create a Scriptable Variable of that class:

```csharp
[CreateAssetMenu(menuName = "Examples/StatsVariable")]
public class StatsVariable : ScriptableVariable<Stats>
{
    
}
```

You might expect that modifying any of the fields (e.g., `Speed` or `Damage`) would trigger the `OnValueChanged` event. However, this doesn't happen by default due to two important reasons:

1. **`ScriptableVariable` only triggers the event when the reference changes**

   The default implementation uses references to compare the current and new values. If the reference doesn’t change, the comparison considers it “equal” — even if internal fields were modified.
2. **`OnValueChanged` is only fired by the `.Value` setter**

   When you mutate a field directly, you're not reassigning `.Value`, so the setter isn't called and no event is fired.

**For example:**

```csharp
var old = _stats.Value;
old.Speed = 10;    // ❌ No setter call → no event
_stats.Value = old; // ✅ Setter call → event fires  
```

✅ How to Trigger the Event on Field Mutation

If you're modifying a field like this:

```csharp
_stats.Value.Speed += 1;
```

…the event **won’t fire** unless you explicitly notify the variable. There are two ways to fix this:

#### 1. Reassign a New Object to `.Value`

You can manually assign a new instance of the class to `.Value` with the updated data:

```csharp
var copy = _stats.Value;
_stats.Value = new Stats { Speed = 10, Damage = copy.Damage }; // ✅ Fires event
```

This works because you're assigning a **new reference**, and the setter compares the new value to the old one.

#### ✅ 2. Call `NotifyChanged()` After Mutation

**Manually tell** the Scriptable Variable that its value has changed:

```csharp
_stats.Value.Speed = 10;
_stats.NotifyChanged(); // ✅ Manually fires the event
```

Full Example:

```csharp

[SerializeField] private StatsVariable _stats;
private void Start()
{
    _stats.OnValueChanged += OnStatsChanged; 
    
    // ✅ Assignment via setter – event fires:
    var copy = _stats.Value;
    _stats.Value = new Stats { Speed = 10, Damage = copy.Damage };
    
    // ✅ or manually notifying ValueChanged after setting a field
    _stats.Value.Speed = 10;
    _stats.ValueChanged();
    
}

private void OnStatsChanged(Stats value)
{
     Debug.Log($"Stats changed: Speed = {value.Speed}, Damage = {value.Damage}");
}

private void OnDestroy()
{
    _stats.OnValueChanged -= OnStatsChanged; 
}
```

### 💡 Optional: Use `struct` Instead of `class`

If you define your custom class can be defined as a `struct instead`, every field mutation will require reassignment — which naturally triggers the setter. This avoids manual `NotifyChanged()` calls and helps reduce heap allocations.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://obvious-game.gitbook.io/soap/soap-core-assets/scriptable-variable/faq.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
