Order of FindObjectsOfType method in Unity - c#

I'm using the Method FindObjectsOfType inside Unity and I want to know what the order Unity find objects?
I tried to change the order of my game objects inside the hierarchy and even change the name of my game objects to 1_name, 2_otherName and still the list seems random.
Do it really random or there is an order for the search? There is no documentation about the order in the Unity website.
If someone really want, this is my relevent script:
[SerializeField] List<AreaMeshHandler> areaMeshHandlers;
void Awake()
{
areaMeshHandlers = FindObjectsOfType<AreaMeshHandler>(true).ToList();
}

Short answer, by InstanceID. can be seen on each GameObject in debug mode.
Tested by running this code in a scene with multiple GameObjects (some in hierarchy)
foreach (Target t in FindObjectsOfType<Target>())
Debug.Log($"{t.name}: {t.GetInstanceID()}");

Related

Reading from file more efficient than GameObject.Find?

Hey I'm new to Unity and I started creating a Tower defense game. Currently I can create one level and have monsters spawn and walk along a path I made with empty GameObjects ( Waypoints ). I can also drag and drop Heroes onto certain places called ( PlacePoints ); these are empty GameObjects, too. Here is a picture of my Level_1 prefab:
Level_1
This all works well so far but I read about GameObject.Find and Transform.Find being slow. And since I want to write fast and clean code right from the start, how would I make this faster and more efficient? Here is an example from my LevelManager script:
public Transform findPlacePoints()
{
return GameObject.Find("Level_1(Clone)").transform.Find("PlacePoints");
}
The question is, would it be faster to store all the information in a .txt file and load it in my LevelManager and then have each Script find the LevelManager which is a Singleton and ask for specific information? Basicly have the LevelManager act as a distributer? Informtion would be:
Spawn Times
Positions of ( SpawnPoints, Waypoints, PlacePoints, etc.)
Enemy Types
Don't fall into the trap of Premature Optimization. GameObject.Find is only slow if you make it slow (searching lots of objects in your scene). Check out the Improving Performance of Our Code section of Unity's Optimizing Scripts in Unity Games if you want to learn what writing good patterns looks like in Unity. It should provide you with some tips and not have to worry about deep-diving into GameObject.Find and disk operation optimizations.
As stated, It really depends on how many items you are searching and how you write the code. From my understanding direct references, such as setting a variable in the inspector, is the most efficient way to "find" something in scene.
Unless you are doing it a lot and in updates, it really shouldn't hurt performance that much. I would focus my optimization time on not destroying/instantiating, keeping UI updates out of the game loop, and keeping light scripts on frequently used objects.
Hope this helps!
What I would do (not saying it is the best) is have a static class just to store some informations (not a monobehaviour) let say Utilities. Have a public GameObject[] waypoints in it. On each of your level, add a script that will overwrite Utilities.waypoints with it's own GameObject[] variable. In the inspector, just drag/drop your waypoints on this script. You can then call Destroy(this) which will delete only the script after completion.

How to find a GameObjects Prefab during runtime with Unity version 2018.3

After updating to Unity 2018.3.0f2 I`m unable to find a GameObjects prefab while the game is running. In the previous versions i was simply using this line:
GameObject prefabObject =
PrefabUtility.GetCorrespondingObjectFromSource(gameObject);
But after the update this function only returns null, so I tried the new functions:
PrefabUtility.GetPrefabInstanceHandle
PrefabUtility.GetNearestPrefabInstanceRoot
PrefabUtility.GetOutermostPrefabInstanceRoot
but all of them return null but I`m sure that I am handing a prefab over as parameter. Any ideas what I am doing wrong here?
As soon as editor start playing (Application.isPlaying=true) prefab linkage with scene game objects will be broken (blue game objects turned into gray) and thus you cannot obtain prefab related information from it.
If you really need a scenario were you want to access such information on runtime, you should save it as Serialized variable in script component so that it will later available on runtime.
For example: this is a simplified contraption of what Mirror (Unity network plugin) is doing by issuing asset ID related stuff to help distinguish each prefab to spawn things in network on runtime.
[SerializeField] string m_AssetId;
void OnValidate() // Which will be called on build or editor play
{
#if UNITY_EDITOR
// Deposit UnityEditor API dependent into some field
m_AssetId = UnityEditor.AssetDatabase.GetAssetPath( gameObject );
#endif
}
Anyway, for running editor script, if you want to test or look for original prefab. UnityEditor.PrefabUtility is somewhat hard to find a full example of how to use them.
You can refer to my git repository on how to use them with examples.
https://github.com/wappenull/UnityPrefabTester

How to have an object in Unity 3D that stays in scenes and does not recreate

I’m trying to find a good way to play background music in Unity 3D. I want the music to keep playing consistently through scene loads. Don’t Destroy on load is fine and works, but every time I load the same scene, it makes another music game object because the scene itself has the game object in it. How can I solve my problem? I am a “beginner” (kind of), so I would like code I can understand.
I'd hands down recommend starting with an Asset like 'EazySoundManagerDemo'. It needs a little refactoring and refinement (ie it uses 3 arrays of audios with 3 sets of accessibility functions instead of one set with an AudioPurpose enum to increase code-reuse).
It does however solve the basic problem you have and is a good intro to using an audio manager / layer instead of simply playing audio directly from your GameObjects. Give that a shot, learn from it and then adapt it or create your own audio management layer.
Good Luck!
I recommend creating an audioSource object, then creating an script for this object and on the awake function do this:
void Awake() {
DontDestroyOnLoad(this.gameObject);
}
This will make the background music to keep playing between scenes. For more information you could use Unity's documentation about this function.
With help from a question on the unity forum, I think I have solved my problem. The link to the question is here...
https://answers.unity.com/questions/982403/how-to-not-duplicate-game-objects-on-dontdestroyon.html
The Best Answer is the one I’m using.
The code is this...
private static Player playerInstance;
void Awake(){
DontDestroyOnLoad(this);
if (playerInstance == null) {
playerInstance = this;
} else {
Destroy(gameObject); // Used Destroy instead of DestroyObject
}
}

Infinite Road Update

I am working on Unity for a month. I am new on Unity and C#, before Unity I worked other game engines. Whatever I am working on infinite run game, I wrote random road generator. Road generator is working well but I have problem about updating road. I can update road manualy like this. How can I update it automaticly?
void Update()
{
if(Input.GetKeyDown(KeyCode.A)) UpdateRoad();
}
My UpdateRoad method adding road like this(I am using object pooling).
I want to update after Link Road, OnExitTrigger or something I dont know. How can I do it?
You would need to implement Object Pooling.
I would suggest making your Design of Objects first so you can test. Or if not use, the stock Blocks Primitive of Unity3D as your Prefabs. I hope you already know prefabs. It is a major key for making infinite runner. Actually a main core for making any kinds of game.
Prefabs is an Object File where you can Instantiate it in a location. So lets say you will generate a Flat walkable, then Generate a Pit. You would probably want to stack them together.
Now Generating them is easy. You would not like to go in an Update? Approach because most likely you're not going to update, but you're going to further stack what is going on ahead, based on your game logic.
To further Understand this, Unity3D already made a project or Fully Detailed tutorial. It maybe made in 2D but it is going to be the same, if you're going to change the Collider2D to Collider <- this is important in your case.
https://unity3d.com/learn/tutorials/modules/beginner/live-training-archive/infinite-runner
Update
You would need to create an Object, that is invisible. Meaning a Trigger.
Then on Trigger call your method UpdateRoad();
https://unity3d.com/learn/tutorials/modules/beginner/physics/colliders-as-triggers
Detailed Videos about Trigger.
If I understood your needs correctly, you could create Empty Object name it SpawnPoint, set position for Spawn Point as you need (out of the camera view) and then Instanciate random prefabs of road. Concerning On TriggerExit - it could be used to destroy "old piece of road". But to have it working properly, dont forget to set collider and rigitbody to your objects. Dont add collider2D or Rigitbody2d, add and use Box Collider and Rigitbody components

Best way to tally objects in an area with collision? (Unity3D - C#)

What would be the best way to tally objects that are tagged under a specific name? What am i doing wrong? My current goal is to use a box collider to identify and tally up specific objects in a room. Any response to a solution or an alternative way of achieving this goal will be appreciated.
My attempt:
using UnityEngine;
using System.Collections;
public class roomColliders : MonoBehavior {
public int numberOfTargets;
void Start (){
numberOfTargets = 0;
}
void OnCollisionEnter(Collision col){
if(col.gameObject.tag == "Target"){
numberOfTargets += 1;
}
}
}
Additionally, I tried assigning with Box Colliders and Rigidbody in a myriad of ways with the objects and I had no success. I have three objects with a tag of "Target" assigned to them but in my inspector, the numberOfTargets tallies up only one object. I have come under the conclusion, that maybe I need to use a statement such as this "foreach(ContactPoint contact in col.contacts)". I could be wrong, tell me if so. If this is near the answer. Is it anyway I can assign 'col.contacts.tag = "Target"'? I get an error if I do so if I used it with 'foreach'.
If only you haven't do it intentionally, using OnCollisionEnter is wrong. You must use OnTriggerEnter instead. And do not forget to toggle on Is Trigger property on box collider attached to the object with roomColliders script.
And note that your script does not actually calculate number of objects currently intersected the trigger. It calculates number of times when objects of interest were start to intersect the trigger. But since the trigger may be moved to and fro, the same object of interest may intersect it more than once.

Categories