In this lesson, you will learn how to design extensible game systems by using ScriptableObjects to add new features through configuration instead of modifying your existing class code.
The Problem: Modifying Closed Systems
In standard game architecture, developers often use massive if or switch statements to handle logic (e.g., a CombatSystem that checks if (weapon == Sword) ... else if (weapon == Bow)...). The problem is that every time you add a new weapon, you must edit the CombatSystem script. This violates the Open-Closed Principle, which states that software entities should be open for extension but closed for modification.
The Solution: Configuration as Data
Instead of hard-coding logic, we treat behavior as data. We define an abstract base class for a WeaponAction, and then create individual ScriptableObjects for each weapon type.
public abstract class WeaponAction : ScriptableObject
{
public abstract void Execute(GameObject user);
}
// You can now create as many "Assets" as you want without touching the system!
[CreateAssetMenu]
public class SwordAction : WeaponAction
{
public override void Execute(GameObject user) { /* Swing Logic */ }
}
By defining a WeaponAction field inside your PlayerController, you can assign any ScriptableObject asset you've created. When you want to add a "Magic Staff" attack, you don't write new code inside the PlayerController. Instead, you create a new ScriptableObject asset, drag it into the inspector, and the system "inherits" the new behavior instantly.
Why This Works
The PlayerController acts as a generic "container" for behavior. It knows it needs to call Execute(), but it doesn't need to know what that logic does. Because the behavior lives in a separate asset file, the main system remains "closed" to modification, while the game itself remains "open" to infinite configuration. This decouples your core game mechanics from your content, preventing bugs and making your project much easier to maintain as it grows.
Key Takeaway: By moving logic into modular ScriptableObjects, you allow your game systems to support new features indefinitely without ever needing to rewrite your core class code.