How to change prefab in Unity3D editor mode by coding - unity3d

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.

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

How do I reference a game object in a prefabs folder? Unity 2D

I am trying to reference a game object in a prefabs folder to insatiate how would I do that. also, the object I'm trying to reference is a particle effect if that helps anyone who is answering this.
In your MonoBehaviour scipt, add a [SerializeField] GameObject _prefab field.
e.g. here I've made a script called SlabMaker that makes endless terrain utilising a prefab:
public class SlabMaker : MonoBehaviour
{
[SerializeField]
private GameObject _prefab;
.
.
.
Then in the Editor, select the object with the previously mentioned script attached. In my example I have attached the SlabMaker script to a GameObject with the highly original name of "_Game". Notice the properties for the SlabMaker appearing in the Inspector along with a field for Prefab. Hurrah!:
...then drag whatever prefab you wish to use from the Project window into the Prefab property in the Properties pane:
In this example I will use my fancy jumpjet plane. Why I want to make endless terrain with Harrier Jumpjets is anyones' guess:
Now then all you have to do is to instantiate the prefab in your script. Job done.

why do we use GetComponent method in unity for accessing other components from our script ,can't we just make an object of that type?

why do we have to access a component from our script using GetComponent method ?
can we make its object instead?
e.g
instead of
Rigidbody rb;
rb = GetComponent<Rigidbody>();
can we use
Rigidbody rb = new Rigidbody();
and use methods based on that.
will the be result same ?
Thankyou.
P.s : I am new to unity
NO!
For your usecase though see the very last lines of this answer. ;)
It is completely illegal in Unity to use new for creating instances of a Component! You will also get a warning about it in the console.
For some stupid reason Unity still "allows" to do it though and does only throw a warning instead of an exception. However, that instance just will not "work" since most of things will not be initialized correctly.. and how should it? There is no GameObject related to it so what would the use of a Rigidbody without according GameObject be? - Right, it is absolutely useless ;)
A Component can only exist correctly if it is attached to a GameObject. Thus, there are only three valid ways of creating instances at runtime:
Use the constructor of GameObject like e.g.
var obj = new GameObject("SomeName", typeof(Rigidbody));
var rb = obj.GetComponent<Rigidbody>();
This creates a new GameObject called SomeName with only the Transform and a Rigidbody component attached.
Use Instantiate to either clone an existing GameObject or create an instance from a prefab.
[SerializeField] private Rigidbody prefab;
...
var rb = Instantiate (prefab);
Use AddComponent to add a new instance of given component type to an existing GameObject. The example from the constructor can also be implemented as
var rb = new GameObject("SomeName").AddComponent<Rigidbody>();
or in your use case to add that component to the same object your script is attached to
var rb = gameObject.AddComponent<Rigidbody>();
which probably comes closest to what your code tries to do

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

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.