- Home /
Usable items - How can I create an asset, that could reference gameObjects that live in separate scenes?
I'm working on creating a Usable
items system. By Usable
I mean stuff that you use on triggers - (think Keys, Lighter, ManholeOpener, Crowbar, etc)
The approach I'm going for is - (which I think is the easiest) - is to have the Usable
item reference the triggers that it's used on.
One note about Usable
items, is that one item could be used in many places (triggers)
So I thought I save my items as prefabs, and then travel between scenes to set the appropriate triggers for my item. (So, a SkeletonKey
could be used to open RazorDoor
in SceneA
and DeathDoor
in SceneB
)
But the problem is, prefabs can't reference scene objects - they'll just die and be null.
(A normal prefab won't even allow you to assign scene objects - but with a custom editor, you could assign values - but they'll just be nulls)
So... how can I create an asset, that would be able to reference gameObjects in separate scenes, and persisting those references?
If you think there's a better approach to Usable
items, I'm all ears.
(Maybe create an asset of a ScriptableObject
, and then save all the usable data for all the items there? - something like a table of "item-triggers[]")
Thanks for any suggestions.
The references do "percist", they're just referencing something that has been removed from memory, ala null
. You just can't reference something that doesn't exist. It's quite literally trying to point at something that isn't there, so you're really not pointing at anything (Yes that was a reference to pointers).
A good idea is to give your items specific identifier keys, such as a index number or some sort of code that you can use to reference the objects.
Well, one id would be the item's name. But that would turn into a headache if the item's name were to change.
$$anonymous$$aybe have a static list of unique number IDs inside Trigger
(the triggers that the items are used on) - and write a custom editor for Usable
, that allows me to add "Trigger"s in a drag-drop fashion, and then maintain a list of all the triggers it have, based on their Id? It's kinda difficult to explain, maybe because it's not even clear in my head.
Could you elaborate more on your method? maybe give an example?
Answer by Benproductions1 · Dec 28, 2013 at 07:55 AM
Hello,
I'll try to narrow down the problem before I explain how I would do it:
Lets say you have two different objects, Key
s and Door
s. Key
s are prefabs and are part of some inventory system while Door
s should be able to take a key from any number of keys.
The problem here is that a runtime object needs to link to a non-runtime object through another runtime object.
The easiest solution to this problem would obviously be to reference the Key
s from the Door
s:
//Door
public Key[] keys;
Doing this is going to make it very easy to link Key
s to Door
s but does pose another problem, being that you can't compare the instance of a key with the prefab it came from. This is the real problem here and has many solutions:
1 By name:
You could compare the name of the instantiated Key
to the name of the Key
prefab. But what if you wanted two items to be called the same thing and allow the player to have them both but still need them to be specific? Well, then you can't use names.
2 Some other identifier:
If you use other identifier, your problem comes down to generating it. Whether it's a special predefined name, some key generated at runtime or even just the index of the Key
in some list, it does get rid of the previous problem but makes it either quite annoying to setup, debug or plain use.
3 Backreferencing (What I would use):
Awake
, Start
, Update
are all called on the instance, so I would make another function called New
or Init
that gets called on the prefab before instantiation. In this the prefab can make a reference to itself
(`this`) before it is instantiated. You can then compare this prefab reference to the reference from the Door
. This makes things much easier to keep up, but it does require you to call a function before instantiating a Key
prefab and it means you can't just place that prefab in the scene and have it work. (It would help if Unity had a Prefab callback, but you could do that with and extension yourself)
Depending on your situation you could choose any one of the three, but that's completely up to you ;)
Hope this helps,
Benproductions1
Thanks for your answer.
So, your approach is kind of the other way around - have the doors reference the keys via their prefabs.
Couple of things I didn't find so clear in your last point:
I would make another function called New or Init that gets called on the prefab before instantiation.
How would I do that?
the prefab can make a reference to itself (this) before it is instantiated
If it hasn't been instantiated yet, how would 'this' be available?
It not being instantiated doesn't mean that it doesn't exist. You can still call functions on them and everything still works, they just aren't part of the runtime (and never will be)
O$$anonymous$$ so how would make a function, that gets called before the prefab is instantiated?
//Prefab
public void Init() {
prefab = this;
}
//somewhere else
prefab.Init();
Instantiate(prefab);
Just like you would normally
Sorry but, isn't doing so won't let me instantiate my prefabs at editor time? (by just drag-dropping them into the scene) but only at runtime? - I thought you're gonna tell me of some OnPrefabDroppedIntoScene
type of callback :D