I have a series of weapons the player can use. They are based on ScriptableObjects.
I’d like to connect a script to the SO, so I can easily indicate which script will fire when the weapon is activated. This will vary greatly from one weapon to the next, so I’d like this to be a modular approach.
My current structure is WeaponData(ScriptableObject) → WeaponScript(base class for weapon behavior) → Individual Weapon Script(inheriting from WeaponScript, in this example “Cleave.cs”)
WeaponData ScriptableObject
[CreateAssetMenu(menuName = "Inventory/Weapon")]
public class WeaponData : ItemData
{
public WeaponName WeaponName;
public WeaponScript Script;
public int CurrentLevel;
public int MaxLevel;
public int BaseDamage;
}
WeaponScript (base class)
public class WeaponScript
{
public virtual void Fire()
{
Debug.LogWarning("A weapon was fired but did not have a script assigned.");
}
}
Cleave (Inheriting from base class above)
public class Cleave : WeaponScript
{
public override void Fire()
{
Debug.Log("Weapon Fired");
}
}
I understand that SO’s can’t utilize some things because they can’t be instantiated so my approach may not be a good one.
Does anyone have any suggestions on how to connect my SO to a modular system where I can specifically code unique behavior for each SO type?
-------- Edit
Sorry, in my haste I forgot to mention the core of the issue is that this causes the script to be inaccessible in the inspector
I see. I didn’t really think it through when I initially posted that, but you could always just have a ScriptableObject keep a type as a value inside it, and then when attached to the actual “weapon”, the weapon could call AddComponent to it.
I think that would be a viable approach I hadn’t considered, but maybe not for my particular implementation.
The player has weapons in weapon slots (an inventory/list)
On cooldown, the system will cycle through each item the player owns and “fire” that weapon. So the only real object in this scenario is a singleton type weapon manager, so I don’t really want to be adding components to that. I’m wondering if there’s a way I can get a SO to point to a script or method in a way that each weapon can be uniquely identified
I suppose I could have a script on my singleton that just looks as the .name for each SO in the weapon slots, and act based on that. But it seems like an amateur way of doing this.
I don’t quite see why it wouldn’t work though, since you would be adding the Components to the Player. You could then cycle through your references of those components, and have them fire. Is there something I’m not quite understanding about your game? It kind of sounds like some Vampire Survivors like thing.
It is super similar to vampire survivors yes, and due to the ability to add/remove/upgrade/evolve weapons constantly and all the stat modifiers involved it would be a bit messy to do it this way. But more so how would I really even do that? I think I’d have to compare the name of the weapon and add a script component based on that weapon name, so really it’s just the same scenario as my previous reply but with more steps unless you know a better way
If you want to socket this behaviour directly onto an SO you either want to:
A: Make these behaviours themselves scriptable objects and plug those into your WeaponData SO
B: Or use SerializeReference to serialise behaviour directly into the scriptable objects
B requires custom inspector work to be possible, but there’s free options out there alongside paid ones too. I’d personally use B as I have said tools, but A works just as well.
You can absolutely put methods and functionality inside a scriptable object. They are just code as assets. Whether it be fields or functionality it’s all just code at the end of the day. Don’t limit your usage of them as just bags of data.
Fun fact, editor’s and editor windows are also scriptable objects. They’re definitely not just bags of data are they?
You could have a pretty simple abstract base class:
public abstract class WeaponScript : ScriptableObject
{
public abstract void Fire();
}
And you just derive from that, and insert it where you need it in your WeaponData objects.
Everything that spiney and Rad says is spot on… and there’s more!
You could even use C# interfaces in your ScriptableObjects or MonoBehaviours, such as having an IFireable and IThrowable and ISwingable and IKickable interface that weapons could implement, each one implementing it however they need to.
Using Interfaces in Unity3D:
Check Youtube for other tutorials about interfaces and working in Unity3D. It’s a pretty powerful combination.