Question about PreFabs

If I create a series of rooms and attach a script to these rooms, then make the rooms into prefabs, will the scripts be on the prefabs when I generate them into the scene? Right now I created some rooms and items and turned them into prefabs with scripts attached. However, the game objects that I had attached to the scripts disappear when spawned into the scene.

What causes this? How do I fix it?

I generally start with an empty game object and parent everything else to it.

If you create a prefab, then attach a script to the in-scene copy, the prefab won’t have that script automatically. You have to click the “Apply” button at the top of the inspector to apply changes back to the prefab; otherwise, Unity assumes you want the addition of the script to be a variant on the prefab.

The same is true of changing values, assigning links, etc. In general, if something appears “bolded” on an instance of a prefab, that means that that is a value that’s being overridden on the instance, rather than being what’s on the prefab.

Well, yes, I created an empty object and made all the object’s structures and scripts inside of the empty. I then made it a prefab.The problem that I’m having is public variables on that script have vanished, so only the original has the elements in place.
3895870--331474--StarTab-Inspector-No-Elements.jpg

So if I’m randomly generating items / rooms the scripts are useless. How do I fix this?

3895876--331477--StarTab-Inspector-No-Elements1.JPG
That’s the result of clicking Apply. I appreciate you showing me that! Cool! But why didn’t it work with the images? Does it have to do with private serialized fields?

The prefab in the Project window cannot access anything from the Scene/Hierarchy.

1 Like

I assume those objects are in separate hierarchies in the scene. Prefabs can have links to other components within the same prefab, or to other prefabs or assets in the project folder - but they can not link to objects in the scene outside of themselves. (Imagine this - what happens if you drop this prefab into a different scene?) So any links to objects in the scene can only happen on the instance, not the prefab.

If you need a link that is valid as soon as the prefab is instantiated, then you should store that link somewhere in the scene, and figure out a way to access it. One common approach is to use a singleton. This approach has some caveats in terms of code codependency and over-reliance (which are discussed in the linked article), but in a lot of situations it’s useful. I’m guessing in this case that “Star Img” and “Star Txt” are elements of your UI? If so, a singleton is a decent solution here, one step shy of what most experienced coders would consider the “correct” solution (which is dependency injection, and more complex and advanced). Basically, you’d have a singleton on your UI’s master controller, which has references to the star img and txt objects, and your StarTabletScript will be able to access them by calling SomeUIMasterScript.instance.starImg.

1 Like

For those, I do a find in the start method. Yeah, you can’t link to something not in the prefab.

1 Like

Hey, thanks for the link! I’m studying this now and trying to perfect it. However, I have a question. Is there not a way to add UI image component directly to the prefab? I see that there’s a GUI text component but no image exist.What is the difference between the GUI and UI?

You can add any component to a prefab, but you can’t reference anything that is in the scene and not in the project folders(‘project view’?)(like other prefabs, textures, sound clips, etc.)

GUIText and GUITexture are very very old, outdated, and obsoleted components from a UI system multiple UI system rebuilds ago, do not use them. The correct component to use is called simply “Text”.

Currently, editing a prefab requires you to drag it into the scene, making changes, and hitting Apply. An upcoming version of Unity will have a new prefab-editing workflow that will (in addition to other prefab features) have a special prefab-editing window separate from the scene. (And boy is THAT feature a long time coming, we’ve been asking for nested prefabs since like 2006.)

2 Likes

Maybe you could get better help if you explain what you are trying to do exactly. You want a UI image or do you want the sprite for a UI image?
I have a canvas that is persistent with DontDestroyOnLoad and I change the sprite for an image component of the canvas. I have the canvas tagged and use findObjectWithTag in the scene I am in, then just get the component with GetComponentInChildren(). I have an array of available sprites on a script on the canvas. They’re small so they don’t use much memory.

There are probably lots of ways to do what you want. Maybe you are trying to use a can opener when something else would work better.

I’m trying to create a series of rooms, and add everything these rooms will contain (Such as spawn points that will randomly generate items, enemies, traps, or powerups. ) After all of the scripting is completed and attached to these rooms, I then want these rooms to be able to randomly generate. To do this, I need the room to be prefabs. I also need my items, powerups, and enemies/traps to be prefabs.

However, the problem that I have encountered is that the prefabs cannot take in the script’s game objects.
I kind of follow what you’re saying about tagging the canvas. However, would I need a new canvas for each image I’m working with?

Hopefully it just took that long to completely perfect it lol
and not that it took that long to be ridden with so many bugs that it’s not even usable. !!!
But sounds good! Deff need this in my life! Doesn’t really make much sense for a prefab to not be able to take on scripts that carry game objects that are referenced directly from the hierarchy.

No, images are added to the canvas, as many as you need. They can be there and set inactive. The other objects sound like they could be sprites added to the image.
You might want to look at scriptable objects. They can have a sprite member, or members, which could be assigned to an image. I use them for inventory items and add them to my inventory bar. What I do on that is have an inventory which is a empty on the canvas, and I have one image prefab which I have a reference to on a script on the inventory. Then I instantiate and parent to the inventory, and give it a sprite from a scriptable object. I have an array of scriptable objects which I can search through and assign a sprite to the created image. Scriptable objects are kind of nice because they can be built in the editor instead of during runtime. They can have other information you might need like location or whatever. I am making an image prefab, so you should be able to do that also and I would think it would keep the sprite. You’ll just have to experiment. You should be able to do something like what you want if you play around enough. I’ve only done this inventory and I haven’t done much in 2d other than that.

Ok, I created 14 rooms. Each room has it’s own camera, item/enemy spawner, walls change color every time an entire level is generated, trap spawner, and there are scenery objects that’ll fill in as well.

Inside of my scripts, the many scripts attached to each room, I have used public variables in order to drag and drop the objects into the inspector. However, once I drag the rooms into the project folder to make them a prefab, I can no longer accessthe gameobjects that I dragged into the inspector for the scripts to read.

Well, the simplest way to accomplish that, which I do, is to do a find in the start method. You can tag them and use find object with tag, or whatever you want.
That’s the only way I accomplish that. Maybe you could parent the gameobject to the room and do it that way, but most tutorials I’ve seen, they use a findObject of some type in the start menu for that type of thing. It’s a scene object so you can’t expect the prefab to hold it.

public GameObject something;
void Start(){
something = GameObject.FindWithTag("tag");
}

or you can find by name, or many other types. As long as the find is in the start menu, it won’t take up much processor time because you only use it once at start up.

If it’s a sprite or a material or something you dragged up from the Assets folder, it should stay on the prefab, I’m pretty sure. If it’s a scene object, you have to use a find.

Well, I am aware of this, and it is unfortunate. I will have to add a script to each room without an object attached use Find() to GetComponent<>().

I was hoping to find a simpler solution.

It’s hard to go back and fix things like that, but it’s generally easier than you think once you get organized. It’s mostly a lot of copy/paste. Good luck with it.

1 Like