How to keep references to UI elements in a prefab, instantiated at runtime - unity3d

I have a prefab, which has a script component as MonoBehaviour. This script has 3 public fields as text; which are assigned in the inspector, before saving the gameobject and remove it from the scene.
Now, this works fine if I have a UI element, like a panel. Every text field on the panel, defined in the prefab, is still assigned when the prefab is instantiated at runtime.
This sadly does not work on another prefab that I have made; which is not a UI element. In my case it is a meshgameobject with various components on it (navmesh agent, capsule collider, rigidbody, animator and so on)
I believe this is due the fact that with the UI panel, the elements are already in the gameobject hierarchy, while when the reference is on a different gameobject; Unity does not keep track of them.
This means that I have to always add at runtime via code, the elements that I want to reference on each prefab, if they are not part of the game object itself? In this case I would just avoid to have my references public then, since I won't be using the inspector in this case (every gameobject of this type is instantiated at runtime).
Just checking if there is any other solution to work around this.

Use List to save reference for each generated object.
Lets assume that the object you want to add to store the reference is called meshgameobject.
Example:
List<meshgameobject> meshGOB;
initiaize inside Start function
void Start(){
meshGOB = new List <meshgameobject>();
}
Then create and use list.add() to add reference during runtime like
meshGOB.Add((meshgameobject)Instantiate(prefab, Pos, Quaternion.Identity);
OR
meshgameobject tempGOB= (meshgameobject)Instantiate(prefab, Pos, Quaternion.Identity);
//Do something with meshgameobject
tempGOB.someAction......
then add the reference to the List
meshGOB.Add(tempGOB);

Do not make a perfab which references to other gameobjects in the scene but are not in the hierarchy of the perfabI itself. AFAIK, Unity can not track this kind of references.
Even if Unity supported this kind of prefab, you could not use this kind of prefab in other scenes because the specific references, so it is not make much sense to make a perfab like that. If you have to make it a pefab just because the scene and the game object are maintained by different person, you may use Find() to populate the references at runtime.

Related

unity how do I get a component from another script?

I have an animator component on one object and I have to access it in one of my scripts. But I do not know how to do it. Of course, it could be done via SerializeField, but I can't do that, since I can't select the animator of another prefab for my current prefab (since it's not visible to it). So it remains to do this only through code, if possible. The access modifier for the animator has already been configured (public).
I assume you have a GameObject A with an animator component, and a GameObject B with a custom script that needs a reference to an animator component.
If both are in the scene, or if A is a prefab:
Select GameObject B, then drag GameObject A into the reference slot of your custom script. If A is a prefab you can call Instantiate(animatorOnA) and it will return a reference to the animator on the newly instantiated object.
If both are instantiated in the same script, you can use GetComponent() on the instantiated copy of A's prefab to get a reference to the animator. Then you can assign the animatorOnA field on B using this reference.
If A is a child of B then you can assign it directly in the inspector, and it will automatically update the reference.
So I assume at one point you instantiate the prefabs in the scene, I don't know which one you instantiate first but you could do this in the script that instantiates those prefabs like this:
// The instantiate function will return the object you instantiated so you can store that in a variable
var prefabWithTheAnimator = Instantiate(yourPrefabWithAnimator);
var prefabThatNeedsTheAnimator = Instantiate(yourOtherPrefab);
// Now you can get the animator of the prefab that has it and set it to the variable in the script you need
prefabThatNeedsTheAnimator.GetComponent<TheScriptWhereYouNeedTheAnimator>().animatorRequired = prefabWithTheAnimator.GetComponent<Animator>();

Why couldn't I use the "Resources.Load" result directly?

The Unity Manual says the Resources.Load returns the requested asset as an Object.I wonder why could't I use the returned Objectdirectly.For example,I have a Text prefab and I want to add it's instance to the Hierarchy,but the Code below won't work
Text prefab;
private void Start()
{
prefab = Resources.Load<Text>("Prefabs/Text");
GameObject canvas = GameObject.Find("Canvas");
prefab.transform.SetParent(canvas.transform);
}
I must Instantiate the return of the Resources.Load first like below
Text prefab;
private void Start()
{
prefab = Resources.Load<Text>("Prefabs/Text");
GameObject canvas = GameObject.Find("Canvas");
Text text = Instantiate(prefab);
text.transform.SetParent(canvas.transform);
}
I don't know what's the difference between the Instantiate result and Resources.Load result,and what the Instantiate do ,so that it's return can be added to Hierarchy.
Forgive my poor English!
To use the Method Instantiate(GameObject) you would write a new component, create a new variable of type GameObject, attach the component to an GameObject, and fill the variable in the inspector.
To use the Method Instantiate(Resource.Load("object path")) you just need the name/path of the Prefab.
this is extremely useful if you have a huge amount of generated parts in your game (so there are no gameobjects placed in the editor), if you'd want to avoid Resource.Load you'd need some "data-holder-gameobject" placed in an nearly empty scene. edited to make my point a bit clearer
it is aswell helpfull if you have large number of different Prefabs and your method knows the name of the object it wants to build, or you just simply dont want to drag and drop all those prefabs into the inspector window
Resource.Load, loads data from your drive. it's possible that your game is played from a Hard drive, which would mean to load the prefabs the hard drive needs to rotate, position the read-head, and so on.
Instantiate is slow itself even without the need of Resource.Load Instantiate is not that fast. if it happens that you need it very often ( multiple times per second) you should consider some kind of object-pool 1

Unity, Spawn a prefab from another prefab

I'm new to Unity. I have an invisible GameObject , call it A, with only a script, that instantiates a prefab B multiple times. I need spawned clones of B to have reference back to A, I have learned that in order for this to work, A has to be a prefab itself (correct me if I'm wrong) Spawned B objects react to mouse clicks and call a method of A. The problem is that inside this called method of A, the variables of A itself have values that I don't expect, for example a certain variable that was initialized to 0 in Start() and never used has a value of 12. It seems like every spawned object B has a reference to its "own" A, and variables of A have random values. What am I missing?
in order for this to work, A has to be a prefab itself (correct me if I'm wrong)
I assume that you are setting the relevant field in the script on prefab B to the prefab of A, which is not what you want. A doesn't have to be a prefab at all.
A prefab is a serialized GameObject that contains specific shared default values for easy GameObject management through the Editor and Editor/in-game scripts. A prefab is used when dealing with a large number of similar objects; each prefab instance will be similar to another with the exception of a few modified properties. This allows for large scale instantiation modification of prefab instances in a single click. For example, storing a gun projectile object as a prefab allows you to modify the default size of all gun projectiles with a single click, while allowing for property customization on a per-instance basis. You can think of prefabs as templates you can use to instantiate a GameObject.
When spawning an instance of prefab B through the script on A (henceforth referred to as ScriptA), simply set the required field on the script on the spawned instance of B (hereafter referred to as ScriptB) to the gameObject (or some other) field of ScriptA, like the following:
// ScriptA's method which spawns instances of prefab B
GameObject bInstance = Instantiate(prefabB);
ScriptB scriptOnBInstance = bInstance.GetComponent<ScriptB>();
scriptOnBInstance.referenceToAGameObject = this.gameObject;

Is there any way to use AddComponent with a script in Unity if there is no instance of that script in the game yet?

I need a way to add a script to an object that I just Instantiated. Ideally I could just set the script to add in the inspector. The problem is that I can't use
public Component scriptToAdd;
because then I would need to already have an empty object or something with the script on it. While that would work it feels kind of dirty or hackish to make an empty that just stores references to something. Also the point of doing it like this for me is to make it more efficient to swap out different scripts. If I had to swap out a script on an empty and then drag the new one in I'd lose on some of that efficiency I'm after. Thanks for any help.
After you instantiate, you should use the GameObject.AddComponent() Class, to add any component Type you want.
for example, if you want to add a camera to the scene.
void Start () {
GameObject myNewCamera = new GameObject();
//creates an empty game object, you can already attach components to it.
myNewCamera.AddComponent<Camera>();
//adds a component of type Camera
}
You can also use the overloaded constructor
GameObject myNewCamera = new GameObject("my object name", typeof(ScriptToAdd));
GameObject myNewCamera = new GameObject("my object name", typeof(ScriptToAdd), typeof(MoreComponentsToAdd));
Also, you should never be afraid of using an empty GameObject on your scene, for keeping information, references, variable values, saves, or anything really. It doesn't really affect the performance of your game, and you can make your life easy just by having an easy to find tag, such as "Engine".
Then you can access anything just by adding:
GameObject.FindGameObjectWithTag("Engine");
I hope I was able to help you :)
-Noe

How to change prefab in Unity3D editor mode by coding

i am writing a MenuItem to apply some modification to a series of prefabs. what i was thinking to do is below:
Instantiate the prefabs one by one
apply the modification to the instance
save the instance to prefab using PrefabUtility.ReplacePrefab
a piece of code would like this:
GameObject sequenceObject = Instantiate(Resources.Load("Cinematic/"+sequenceName)) as GameObject;
Object targetPrefab = PrefabUtility.GetPrefabParent(sequenceObject);
// do some change to the sequenceObject
PrefabUtility.ReplacePrefab(sequenceObject, targetPrefab, ReplacePrefabOptions.ConnectToPrefab);
the problem is that targetPrefab is null
and the instance of the prefab generate by the code in the Hierarchy is called xxxxx(Clone), which is different with the one when i drag a prefab into Hierarchy, and the latter one can using the method above to modify the prefab.
so anyone can help?
Edit1: my question is the same as this one: Instantiate Prefab but not linked to the prefab, but the solution is not i want
Finally, I found the solution:
GameObject sequenceObject = PrefabUtility.InstantiatePrefab(Resources.Load("Cinematic/" + sequenceName)) as GameObject;
This is what I want.