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
Related
This question already has answers here:
How to find child of a GameObject or the script attached to child GameObject via script
(4 answers)
Closed 4 years ago.
I want to access the animator component of my player character. The character is spawned under the GameObject Character position, which it self is the child of Game Manager.
The character prefabs have various names, so I cannot find them through exact name. So its easier to just get the only child of Character position.
Game Manager
Character position
Player Prefab
Ive searched online and tried GetChild by index and GetComponentInChildren. None of them work. Below is the script I wrote for this:
private Animator archerAnimator;
private float startSpeed;
GameObject charPos;
GameObject archer_;
// Use this for initialization
void Start () {
charPos = GameObject.Find("Game manager/Character position");
Debug.Log(charPos);
archer_ = charPos.transform.GetChild(0).gameObject;
archerAnimator = charPos.GetComponentInChildren<Animator>();
Debug.Log(archerAnimator);
}
charPos is found, but for archer_ I get the error, Transform child out of bounds. The player archer is not there but is spawned at run time when the scene starts, is this the reason it cannot find it so quickly?
Some guidance would be appreciated.
Thank you
I think you're scanning for the player too early. You should reverse your discovery logic. Instead of scanning for the player and its Animator, you should put a script on the player itself that runs after it is created and reports itself to the game manager or whatever object needs access to it, something like this:
void Start() { GetComponentInParent<GameManager>().OnPlayerSpawned(this); }
I'll also mention that some script finding an object by name and accessing its components is a generally bad idea. Here's a design guideline to always keep in mind: You should traverse Unity's object hierarchy as infrequently as possible, and even if you do, you should only traverse objects that don't have other scripts attached. In this case, you should also put the logic to control the Animator inside your Player script. Then, you wouldn't need to get a reference to the Animator in the first place.
In my fps level (Unity), targets spawn at a random position. I want to make sure targets can't spawn behind objects or inside objects.
To make sure they don't spawn behind an object, I've made a raycast going from the player to the target. If it's obstructed I recalculate the spawn point. This works fine, but, since the targets are spheres the raycast won't be obstructed when a target is 50% inside an object, for example the floor. I don't want that, obviously.
To determine whether or not the target is in the bounds of another object, I tried using OnCollisionEnter and OnCollisionExit. While this works when simply moving a target inside another object, it seems to be unreliable when one script's Update cycle is recalculating the spawn position while the target's Update cycle is keeping track of the Collision.
So I looked for a different approach. Here's what I came up with (from the Unity docs):
m_Collider2 = spawnpoints[i].GetComponent<Collider>();
m_Collider = world.GetComponentInChildren<Collider>();
if (m_Collider.bounds.Intersects(m_Collider2.bounds))
{
Debug.Log("Bounds intersecting");
}
The Game Object world is the parent in which I put all the objects of my gaming world.
The problem is that he only takes into account the collider of the first object. I basically want to use one big collider, which is composed by all the level objects.
Is this possible? Or does anyone know a different approach on how I can achieve this?
You should use the GetComponentsInChildren method instead of GetComponentInChildren, so that you can get from it an array of colliders on which you can execute a foreach to check if the bounds are intersecting.
I.E.:
m_Collider2 = spawnpoints [i].GetComponent<Collider>();
m_Collider = world.GetComponentsInChildren<Collider>();
foreach(Collider objCollider in m_Collider) {
if (objCollider.bounds.Intersects(m_Collider2.bounds))
{
Debug.Log("Bounds intersecting");
break;
}
}
But, this way of doing things is very heavy for the CPU, since GetComponent methods are really slow, so their use should be limited inside Awake and Start methods if possible.
Another approach to the problem would be to create a List<Collider> at the start, and add to it the starting children of your World game object. If another one is instantiated, just Add it to your list, if it's destroyed, just Remove it.
Then, just before instantiation, you can check the bounds by looping inside the List with a foreach, the check will be a lot more faster.
==================================
EDIT:
Ok, here's the deal. First of all, add these lines to your World game object script (I guess you called the class World):
using UnityEngine;
using System.Collections.Generic; //Namespace needed to use the List type
public class World : MonoBehaviour {
//The list which will hold references to the children game objects colliders
public List<Collider> childrenColliders;
private void Start() {
//Code used to populate the list at start
childrenColliders = new List<Collider>(GetComponentsInChildren<Collider>());
}
Now, since in the script which spawns a new object has already a world variable which holds a reference to the World class:
foreach(Collider coll in world.childrenColliders) {
if (coll.bounds.Intersects(m_Collider2.bounds))
{
Debug.Log("Bounds intersecting");
break;
}
}
And, of course, as I said before remember to add a newly spawned game object's collider to the list with:
void AddNewGameObject() {
// spawnPoint is the transform.position Vector3 you'll use for the new game object
var newGameObject = Instantiate(yourObjectPrefab, spawnPoint, Quaternion.identity, world.transform);
world.childrenColliders.Add(newGameObject.GetComponent<Collider>());
}
That's pretty much it. ;)
I am trying to attain the legendary skill of mastering how to make my scripts talk with any GameObject and their components wherever they are. To do that, i watched a couple of tutorials like https://www.youtube.com/watch?v=LrkfSqxz4jU, but my brain still seem to resist to smartness :(.
So far, i have understood than in order to do that i first need my
script to find the right gameobject in my scene (if the script is not
attached directly to it), and assign it to a variable, with for
example:
myVariable = GameObject.Find ("MyGameObjectName");
Then, when i have found this gameobject (and eventually summoned it if it was not in my scene), i find myself at loss to figure out how to call the right component (and inherently, how to call the right sub-element.
For example, i have at the moment a game object for my UI with :
RectTransform, CanvasRenderer,UI Controller (Script),Grid Layout Group (Script)
In order to modify the RectTransform 's Pivot X for example, my logic tells me to add to my script:
myVariable.GetComponent<RectTransform> ();
myVariable.RectTransform.Pivot.x = 0.75;
...Which get all red and bad, and i don't understand why. I am also not knowing how i am supposed to call the component GridLayoutGroup. I suppose there is a even dirtier trick in the sense that it is written (script)...
To give you another example that i find confusing, if i would type myVariable.transform.position.x , is it changing the RectTransform, or another hidden transform that i don't know of ?
It is confusing because i would think that logically, this should be called instead myVariable.RectTransform.position.x or something.
So the point of all that is: What's the big idea ? What is the core concept that i am missing ?
I am confused ! :D
Because having public fields is bad practice (accessible from everywhere) you should use serialized fields.
I'll just use the example Vancete made up, but with a serialized field instead of a public field.
[SerializeField] GameObject myGo; // a space to drop a GameObject will appear in the inspector too,
// with the benefit of not having a public field
// (not specifying public, private, protected etc. makes the field private in C#)
void Start() {
Image myImg = myGo.GetComponent<Image>();
myImg.sprite = // WHATEVER
myImg.color = // YOUR PREFERRED COLOR
}
At the bottom of this page, you'll find a nice table, comparing these modifiers.
These people here are all proving my concept. As the user, who wrote the last answer on the linked page, points out, even Unity is using [SerializeField] in their example project.
You'll find another proof in this article.
The fastest and best way to access a GameObject is declaring it as public and drag&dropping in the inspector.
GameObject.Find is slow (since it requires a tree search) and impractical (you will have problems if you rename the GameObject or change its hierarchy), things that can be avoided linking it in the mentioned way above.
For example, using GameObject.Find inside the Update is a real performance killer.
Also, if you are going to access to a GameObject component more than once, it's recommended to reference it before using it.
public GameObject myGo; // a space to drop a GameObject will appear in the inspector
void Start(){
Image myImg = myGo.GetComponent<Image>();
myImg.sprite = // WHATEVER
myImg.color = // YOUR PREFERRED COLOR
}
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
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.