- Home /
How do I clone a ScriptableObject reference at runtime?
Hi all, I have the following setup:
I have a custom class which is linked via inheritance to ScriptableObject, and then which I extend with specific classes that contain specific behaviour, like this:
ScriptableObject -> PluginEffect -> SomeSpecificEffectScriptIWrite
I then have what are called 'behaviour' scripts which I attach to objects. All these scripts do is provide an exposed public member to the editor, of type PluginEffect. After I've used a tiny editor script to create a ScriptableObject asset of type 'SomeSpecificEffectScriptIWrite' I then drag this new asset into that exposed field and at runtime the behaviour script calls methods on it magical things (are meant) to happen.
I do this so that I can have a fairly generic drag/drop system whereby I can interchange numerous hardcoded behaviours between objects and they just work nicely. Now when testing with multiple objects, I realised that only one of them will process the ScriptableObject, so for example if my class 'SomeSpecificEffectScriptIWrite' creates a load of explosions and smoke and fire around the object that uses it, and I have 3 objects that all reference this via the inspector who all die at the same time, well, only one of them (the last one to die as it takes control of the reference) processes that code and runs. This is clearly not going to work out and isn't what I want. So upon discovering this, I used ScriptableObject.CreatInstance(); to make a new instance, this worked, except, it uses all default settings as set in the code, which won't work for my purposes because I need to set colours, effect types, sizes, durations, references to objects and prefabs and so on.
So the problem I am having is in trying to clone this reference to my specific PluginEffect. I have now tried this:
using UnityEngine; using System.Collections.Generic;
public class DeathBehaviour : MonoBehaviour { public PluginEffect deathScript;
PluginEffect pfx;
void Start() {
pfx = (PluginEffect)Instantiate( deathScript );
}
void OnObjectDestroyed() {
if( pfx != null )
pfx.StartProcess( transform, this );
}
}
Which actually works, in that it gives me an new clone with the settings I set in the inspector and even if multiple objects use it, they can do so without stealing control of it away from another object - of course, since it's a proper clone. The downside of this is that I get a mystical error message:
metaFlags & kStrongPPtrMask UnityEngine.Object:Internal_CloneSingle(Object) UnityEngine.Object:Internal_CloneSingle(Object) UnityEngine.Object:Instantiate(Object) DeathBehaviour:Start() (at Assets\TPG\Scripts\Object\DeathBehaviour.cs:10)
[....\Runtime\Serialize\TransferUtility.cpp line 352]
Which I have not even the slightest idea of where to start. Searching yields nothing other than a post relating to GUIStyles which says you shouldn't use Instantiate to clone an asset. It says to use CreateInstance(). Which as mentioned I've tried and it doesn't work for my needs, as it doesn't use any settings I've set in the editor on my ScriptableObject asset.
So now I'm a bit lost as to where to go. Someone suggested using the 'new' keyword, but I do not know how to do that when I have a reference to my class, I can of course do:
PluginEffect something = new PluginEffect();
But that won't have my settings from the inspector or more importantly be of the 'SomeSpecificEffectScriptIWrite' class with it's unique behaviours. I can't do:
PluginEffect something = new SomeSpecificEffectScriptIWrite();
Because I don't know what class that is in code - I drag it onto the public method via the inspector. So perhaps I am either missing something obvious, or I am trying to do something that this ScriptableObject class is not meant for, I'm not sure and would appreciate some insight. Also apologies if this is complicated to follow, I did struggle trying to explain it and this is the best it has come out as. Thanks.
Digitalos.
Answer by Tetrad · Jun 24, 2010 at 05:24 AM
This probably doesn't help, but why not just use prefabs/monobehaviours to accomplish this?
You could set up something similar to how you have it, where you have a class hierarchy of monobehaviour -> plugineffect -> yourspecialeffecttype. That way you can instantiate an instance of your special effect object and seemingly solve your problems.
Yes that is actually what I had prior to this. The idea behind this is that later on I can make the PluginEffects a lot more modular and can craft a sequence of events from combining them, which all get processed when run and so on. I am doing a less generic way now because I didn't have the bandwidth to tackle that task to a usable level. :)
If this actually cannot work then I will revert to just using monos on prefabs. Thanks though!
Just curious, what kind of things can you do with ScriptableObject that you can't do with $$anonymous$$onoBehaviour? I haven't used the former.
Well the way this is setup is that I have a single mono component on some object in the game world, and can then increase the array and add SO's to it that have specific behaviour which it then runs when it's triggered by an event at runtime. I'm beginning to wonder now if this is perhaps a roundabout way to do it, as you suggest I could use monos on a prefab only with the latter I guess when I move to a proper generic setup where I combine components, I need to add the monos to GOs and then GOs to a prefab, and then instantiate that prefab, which seems like a headache.
Digitalos, did you ever figure this out? I have run into the same problem - I use ScriptableObjects as modular components for a finite state machine editor, but every instance of the state machine component shares the same ScriptabeObjects/State! I also tried Instantiate and got the same cryptic error...
Your answer
Follow this Question
Related Questions
Crash when using GameObject.Instantiate 2 Answers
How can I get the x position for the left(and right) of the screen? 2 Answers
How do I make a clone of a prefab appear on the correct layer? [5.2.2f1] 1 Answer
Assigning gameobject to an instantiated prefab through script? 2 Answers
How to Instantiate and change velocity 2 Answers