I'm spawning a prefab on MotherSpawner gameObject and I want to spawn that prefab again on positionWhereObjectSpawn gameObject.
What I'm planning to do is get the position of positionWhereObjectSpawn gameobject using GameObject.Find, then spawn on that position, but they say it's inefficient.
What's the efficient way to do this?
Something like this should work:
var posGo = GameObject.Find("positionwhereobjectspawn");
Instantiate(myPrefab, posGo.transform.position, posGo.transform.rotation);
One thing that's inefficient here is the GameObject.Find. If you do it at every spawn, yes, it is inefficient. If you find it once and simply place it into a variable in your class to be used later, it's efficient. Like so:
GameObject posGo;
Start() {
posGo = GameObject.Find("positionwhereobjectspawn");
}
Update() {
if(Input.GetKeyDown(KeyCode.SPACE)) {
Instantiate(myPrefab, posGo.transform.position, posGo.transform.rotation);
}
}
Next step to improve efficiency is to get rid of the Instantiate and use an object pool. You create game objects in advance, hide them, and use them when needed. For that, you should Google unity object pooling and use one of the options.
If this is static and you wont change the number of spawns you can do is make public fields and store the Transform of both the spots where you want to spawn a prefab just by making 2 public Transform fields OR if you want to increase the number of spawns you can simply store these positions in a collection and use that to spawn objects, and yea Gameobject.Find is inefficient, this method searches through your whole hierarchy so think how much time will it take to look through everything.
Related
I have a large room with tends of thousands of nested objects. I tried to select a group of objects that represents a single object out of hundreds. This was originally a sketchup file that got turned into a prefab variant and added to the scene.
using UnityEngine;
using System.Collections;
using UnityEditor;
public class CreatePrefab : MonoBehaviour
{
[MenuItem("Extras/Create Prefab From Selection")]
static void DoCreatePrefab()
{
Transform[] transforms = Selection.transforms;
foreach (Transform t in transforms)
{
GameObject prefab = PrefabUtility.CreatePrefab("Assets/Prefabs/" + t.gameObject.name +
".prefab", t.gameObject, ReplacePrefabOptions.ReplaceNameBased);
}
}
}
So I am trying to iterate through the selection and turn them each into prefabs. Its pretty ridiculous because there is close to 100,000 objects in total and everything, like nuts, bolts, rods that make up a chair are individual gameobjects.
I am trying to use GPU instancing to reduce framerate but this imported model needs to be converted into prefab somehow. I am trying to extract meaningful objects that repeat (ex. chairs) as individual chair prefabs but the problem is:
I don't know how to first combine/fuse the objects that make up a chair
If I am able to select a chair I need to be able to convert it into a chair prefab.
I have to basically repeat this process for each object that repeats excessively (ex. chairs, desks)
I get this error message from unity: can't save part of a prefab instance as a prefab,
How can I group the individual parts that make up a chair and turn it into a prefab?
Unity can neither handle that many objects nor a hierarchy this deep! (a nice article on Unity's own website about this). Thus you will never end up with good performance this way. You'll have to reduce and combine the objects in a dedicated software (usually 3D modeling software) and import those objects to unity.
The same requirement as your. Unity hasn't provided such a method to save a nested prefab modification, but can be achieved by a trick.
The solutions is:
Instantiate another nested prefab by PrefabUtility.InstantiatePrefab
Modify that new GameObject of the prefab
Save the modification by PrefabUtility.SaveAsPrefabAssetAndConnect
And because the gameobject hierarchy is a reference, the saved modification will also affect the nested prefab.
Here is the code:
var prefabPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(goInScene);
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
var anotherGo = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
// Do the same modification of the nestedGo to anotherGo
PrefabUtility.SaveAsPrefabAssetAndConnect(anotherGo, prefabPath, InteractionMode.AutomatedAction); // This save will affect all prefab in Scene!
DestroyImmediate(anotherGo);
Example: GameObject A has a script attached to it called MakeItRain. Inside that script is a public void Drizzle();
GameObject B also has a script and wants to tell MakeItRain to do Drizzle();
Inside the script of GameObject B, I can do this:
public GameObject makeitrain;
and then I have to use GetComponent to reach Drizzle(); in my code.
In the inspector, I drop GameObject A into the slot of makeitrain and I'm done.
However, I could also do this in the script of GameObject B:
public MakeItRain makeitrain;
and then just call makeitrain.Drizzle(); in my code of GameObject B's script, without GetComponent.
In both cases, in the Inspector, I have to drag and drop GameObject A into the slot of GameObject B.
Is there a difference or reason why I should definitely not do the last option? I understand that the first method gives me more flexibility because I could call other components of GameObject A as well and not just the script's stuff. Just wondering if there is any other rationale for not doing the second method.
The answer depends if you need to call any function or use variable from the MakeItRain script.
If you don't need to to call any function in the MakeItRain script or access any variables from it then it is better to use GameObject as the reference. Also, if what you need to do is activate, de-active, rotate the GameObject then use the GameObject as reference.
On the other hand, if you need to be able to call a function such as Drizzle or access a variable from the MakeItRain script from multiple places, then you need to use the MakeItRain reference. At this time, it doesn't make sense to use the GameObject reference since by using it, it's required to use GetComponent every-time you need to call a function or access a variable from the MakeItRain script attached to it.
Finally, when using the MakeItRain script to reference your object, you can directly and easily access the GameObject it is attached to without using the makeitrain.gameObject. This doesn't require the use of the GetComponent function.
Just wondering if there is any other rationale for not doing the
second method.
Performance issue due to the required use of the GetComponent function is the reason. Using it once in the Start or Awake function and initializing your MakeItRain variable is better.
For example, this is better:
public MakeItRain makeitrain;
void Start()
{
makeitrain = GetComponent<MakeItRain>();
}
void Update()
{
makeitrain.Drizzle();
}
than this:
public GameObject makeitrain;
void Update()
{
makeitrain.GetComponent<MakeItRain>().Drizzle();
}
And should be used to avoid having to search for the component on the native side every frame.
Using MakeItRain and explicitly defining the type is better than using GameObject.
As #hacksalot commented, using MakeItRain offers strong typing. One of the benefits of this is related to your comment:
In both cases, in the Inspector, I have to drag and drop GameObject A
into the slot of GameObject B.
If you explicitly set the public variable type to MakeItRain rather than GameObject, it is not possible to drag and drop a GameObject A into the slot of GameObject B unless GameObject A is has a script of the correct type. This gives you a compile-time/editor-time check that you are linking to the correct GameObject in the Unity Editor inspector.
Also, while not necessarily so, using GameObject references often encourages messier code, whether because of unnecessary chaining of methods together (e.g. GetComponent) just because the type wasn't specified, or because it adds a bit of friction to writing & using helper methods. Consider even in a simple example which one reads better:
makeitrain.Drizzle()
makeitrain.GetComponent<MakeItRain>().Drizzle()
I understand that the first method gives me more flexibility because I
could call other components of GameObject A as well and not just the
script's stuff.
Note that you still have the flexibility to access GameObject, it's just a bit more verbose (which is one downside of this approach):
public MakeItRain makeitrain;
void Start()
{
makeitrain.gameObject.SetActive(false)
}
However, you'll likely be using helper methods anyway (for anything more than basic calls), or even wrapper methods (which are inconvenient to write but sometimes helpful for readability).
In most cases, the benefits of linking to the class rather than the GameObject outweigh the downsides.
If u don't want to use GetComponent(), you can simply use SendMeassage(), like this
public Gameobject makeItRain;
void Start(){
makeitrain.SendMeassage("Drizzle");
}
Another way to link a script is that use FindObjectOfType(), which do not need to drag and drop GameObject into the slot, here is the sample
void Start(){
MakeItRain makeitrain = FindObjectOfType("MakeItRain");
}
Also you can use Gameobject.Find() to link a GameObject instead of dragging into slot, but I don't recommand this way, it cost a lot performance since you need to find every single GameObject in scene.
I watched Basic Platformer Game tutorial for Unity where presenter created coin pick-up script that he attached to Coin prefab. I want to know if the pick-up script should be attached to the Player or Coin GameObject.
Let's say we have a game with pick-upable objects. They do nothing more than incrementing the score (or affecting the player in another way) and destroy themselves on collision.
I was wondering that what is the preferred approach to this problem.
I've come up with two approaches:
Approach A
Have one ObjectPickup script on the player game object. This script would do whatever is required depending on the type of collided object.
private void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.CompareTag("Coin"))
{
IncrementScore();
Destroy(other.gameObject);
}
else if (other.gameObject.CompareTag("SuperSpeed"))
{
IncreasePlayerSpeed();
Destroy(other.gameObject);
}
}
Approach B
Have CoinPickup script on every coin and SuperSpeedPickup script on every super speed powerup.
private void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.CompareTag("Player"))
{
other.gameObject.IncrementScore();
Destroy(gameObject);
}
}
And other script:
private void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.CompareTag("Player"))
{
other.gameObject.IncreasePlayerSpeed();
Destroy(gameObject);
}
}
Is Approach A more efficient then Approach B? If so what is the rough number of GameObjects when Approach A becomes preferable?
Or is it always better to work with Approach B as it seems to be cleaner (when we have a number of different pick-upable objects)?
In your example, "approach a" would be more efficient than the other because the OnTriggerEnter2D is called once. With "approach b", OnTriggerEnter2D is called twice on two different scripts. It's slower for Unity to make callback calls let alone on two different scripts + the player. Also, OnTriggerEnter2D is sent to disabled MonoBehaviours which makes "approach a" more efficient choice. The main reason for the slow event call is because the call is made from native C++ side of the code to the Unity's C# API side and this is costly.
Note that it really doesn't matter that much. This is just an attempt to answer your question for which one is more efficient but what you're doing is a micro-optimization.
The thing that should play big role in this decision is the behavior of the coin after the trigger.
If the coins behave the-same then use "approach a" and do the detection on the player's side.
If the coins have different behavior like coins with different score values, color and action(animation) when they are collected then do the detection on the coins side and handle each coin. This is the reason why scripts are attached to GameObjects in the first place. You don't need different tags for each different coin. Use enum to distinguish their action in the OnTriggerEnter2D function. It would be awful to use "approach a" to handle this in this case.
Considering you can create a prefab for every coin and for every super speed power up with the second approach script already attached to it AND considering you can spawn them very easily from anywhere in the code I'd really stick to the second approach, making it more sensible, clean and clearly understandable from everyone.
I don't like (and I wouldn't absolutely use) the first approach for this specific purpouse mainly because the OnTriggerEnter2D is very likely to be fired a very large number of times since it's put on the player and the player is moving around colliding with stuff everywhere.
I should use the B, cause it's more like how object-programming works (at least on my head!) even if it's more expensive.
But Method A do not split interactions, so imagine that you can collide with 2 different pickable objects, and you collide with bouth at the same time. If you use Method A, it will use allways the same collision-order, which can be desired or not!
But clearly with Method B you don't really know which object will be picked first (in this concrete case!)
Approach A sounds a bit more performant, also it would work with multiplayer. If you have n players, local or online, you'd need to check the player id on the coin. Otherwise you'd need a lot of tags. No need to do that if the players detect item collisions themselves.
I have multiple enemies that move toward the player. I am trying to stop them from merging into each other, i.e maintain some type of minimum distance between each other. What I'm trying is this (from unity3d forums):
enemy1.transform.position = (enemy1.transform.position -
enemy2.transform.position).normalized * distance + enemy2.transform.position;
However, when I have >= 3 enemies they still seem to bunch up even when I apply this to every enemy combination.
I need a better method as this one does not work and does not scale.
What you do around your enemy prefab is place a quad box which in effect is a trigger element, then on you script for the enemy you set that if another enemy (using tag types, I imagine) comes within touching of the quad box then to run appropriate code to stop the enemy getting closer in and to prevent the enemy actually overlapping with this trigger box.
Your code you example in your question looks like it is referencing the enemy units specifically rather than as instance entitites which is very probably a bad way of coding, as you're finding, it's very inflexible dealing with not-specifically-named reference entities.
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour
{
private Transform otherEntity;
public float distance = 50.0f;
private Transform thisEntity;
void OnTriggerEnter(Collider other)
{
otherEntity = other.GetComponent<Transform>();
thisEntity = GetComponent<Transform>();
thisEntity.position = (thisEntity.position - otherEntity.position).normalized * distance + otherEntity.position;
}
}
I have not tested the above code but using the code you reference the values for the transform are loaded from the Game Component for the referenced entities, as this has changed ALOT in Unity since release of version 5.1 and your source for your code was an answer given in 2012!!
thisEntity is the object that the script is attached to, typically one of the enemy. The otherEntity is the object that comes within the quad trigger (please remember the quad needs to be referenced as a trigger element.
The values of the Entity variables need to be set once the trigger is entered, so that it always effects the correct other element.
(I may be totally wrong with my methodology but I hope this helps.)
I'd like some help with the following issue. I'm making a simple game where you have a character running and he has to jump over obstacles coming at him.
And I'm currently stuck when it comes to creating GameObjects and randomly generating them within the game scene at run time.
I've written a class to help accomplish this:
using UnityEngine;
using System.Collections;
public class randomObstacles : MonoBehaviour {
public GameObject myCube;
public Vector3 spawnLocation = new Vector3(0,2,0);
// Use this for initialization
void Start () {
GameObject SpawnLocation = (GameObject)Instantiate(myCube, spawnLocation, Quaternion.identity);
}
// Update is called once per frame
void Update () {
}
}
The above code is what I wrote to simply create Objects, one after the other. But when I run the game, it comes up empty -_- !
Can anyone please tell me where am going wrong, and from the look of it my code doesn't seem to do what I am hoping to achieve :(
I've attached the above script into an empty GameObject as I saw in a tutorial from the Unity Community forum, but that did not help either.
(I've looked around and it seems like no one has come across such an issue - I could bee wrong)
It would seem that your myCube variable is the root of your problems, having tested it in a scene of my own. By subsituting
(GameObject)Instantiate(myCube, ...
with
(GameObject)Instantiate(GameObject.CreatePrimitive(PrimitiveType.Cube), ...
I was able to produce a cube at (0,2,0) with no qualms. Perhaps your myCube GameObject is missing a Mesh Renderer, in which case it would appear in the Hierarchy during runtime even though it would not appear visible in Game View. Perhaps you are not assigning it in the Inspector before you run the game, in which case the myCube variable would refer to null and thus not be created. Additionally, though you may be assigning the GameObject you instantiate to SpawnLocation, it is an unused local variable (something MonoDevelop or your code editor should notify you of). Make sure you either provide a reference to a myCube GameObject in the Inspector before runtime or through script referencing to a loaded prefab/GameObject during runtime. It would also be helpful to provide a fallback (say, to PrimitiveType.Cube perhaps?), which will make your code more robust and able to handle errors in referencing should they arise.
Regardless, in order to achieve the functionality you have described, first make sure yo have properly prepared whatever you would desire myCube to be. Also, for future posterity, you may want to initialize your spawnLocation in the Start routine, and assign the variable coordinates by substituting Random.value * yourValueCeiling in for each random coordinate you would like myCube to spawn on. You could even go as far to make a helper method externalized and thus independent from the start routine, such that you will not have to have a hundred instances of a single script to create a hundred instances of what you need; rather, you can call the method through a single script, and save yourself trouble in this way. If you would so appreciate it, here is my implementation of your objective, hope this helps!
using UnityEngine;
using System.Collections;
public class randomObstacles : MonoBehaviour {
public Vector3 spawnLocation;
public GameObject myCube;
// Use this for initialization
void Start () {
if (myCube != true) {
Debug.Log("myCube not set");
myCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
}
if (myCube.renderer.enabled == false) {
Debug.Log("myCube not rendered");
myCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
}
CreateCube();
}
// Update is called once per frame
void Update () {
}
void CreateCube() {
spawnLocation = new Vector3(0, Random.value * 10, 0);
Instantiate(myCube, spawnLocation, Quaternion.identity);
}
}
It may be worth pointing out that you're creating your object in the Start method, which means your code will only run once: from the name of your class, I'd assume you want to create more than one object using this code.
If you move the code into Update you'll create one object per frame, which is most likely too many. My guess would be that you want something like a coroutine that will run on a random interval, and then spawn cubes repeatedly over time, something like this:
void Start () {
StartCoroutine("SpawnObjects");
}
IEnumerator SpawnObjects()
{
while (keepAddingObjects) // a boolean - could just be "true" or could be controlled elsewhere
{
GameObject SpawnLocation = (GameObject)Instantiate(myCube, spawnLocation, Quaternion.identity);
float delay = Random.Range(1f, 5f); // adjust this to set frequency of obstacles
yield return new WaitForSeconds(delay);
}
}
Taken from my own code in a game that auto generate mazes:
public class Cell
{
private GameObject instance;
public void CreateVisual()
{
// Load a GameObject that exist inside the "Resources" folder.
GameObject prefab = (GameObject)Resources.Load("Models/Walls/3W1");
// Create an instance of the prefab
instance = (GameObject)GameObject.Instantiate(prefab);
instance.transform.position = myPosition;
}
}
I think the part you are missing is the Resources.Load() method.