unity how do I get a component from another script? - unity3d

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>();

Related

How do I go from GameObject ID to an actual GameObject when Instantiating?

So I'm working on a save system for my app, and I'm trying to store objects in a GameObject array like so:
public GameObject[ ] entriesInScene;
When I store GameObject in the array it stores the GameObject ID. When I try and instantiate the object later on in the code using this if loop:
foreach (GameObject go in saveObject.entriesInScene)
{
Debug.Log(go);
GameObject entry = Instantiate(go, position, Quaternion.identity);
entry.transform.SetParent(null);
entry.transform.SetParent(scroll.transform);
entry.transform.localScale = new Vector3(1,1,1);
}
It give es me an error of MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it. Your script should either check if it is null or you should not destroy the object.
Does Anyone know how to fix this or know how to get the GameObject from the ID to make the instantiate work?
Through Unity you won't be able to save entire GameObjects directly through serialization as far as I know. My approach to a similar problem with implementing a save system was to have each object type stored as a prefab, and then I'd save the important values itself in my script (an example being a microwave prefab that a user could place, but I'd store the Vector3 for the position). In most cases you should be able to just store the values that change between instances of a prefab.

how to change variables in script attached to a prefab through script at runtime?

I have instantiated a prefab in the scene that gets destroyed after 2 secs. I want to change its speed variable in its move script so that whenever it instantiate it has new speed.
The instantiate function returns the game object you created.
GameObject prefabObject = Instantiate(...);
Then you can obviously do something like
prefabObject.GetComponent<moveScript>().speed = 4;
You have not provided enough information, but I will try to answer.
Will this be done by another script or the Move script you have attached on the prefab?
If from the Move script then:
private void Awake()
{
speed = MY_NEW_SPEED;
}
If from another script, then you first need to access the instantiated object and then its Move scripts. You have not provided enough information so I will assume you already have a reference to your instantiated object:
instantiatedObject.GetComponent<Move>().speed = MY_NEW_SPEED;
https://docs.unity3d.com/ScriptReference/GameObject.GetComponent.html

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;

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

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.

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.