Assuming Unity created 10 clones, I wanted to delete only 5 of them, so I used the following method.
for(int i=0; i<5l; i++)
{
Debug.Log("check");
Destroy(GameObject.Find("coin"));
}
However, only one was deleted.
Debug.Log() shows 5 outputs, so the loop seems to be working properly. Why does this happen?
This might be because
Destroy(GameObject.Find("coin"));
only destroys the game object specifically named, "coin", which is most likely the game object/prefab your clones are based on, and not the clones themselves because the names of all game objects created with
Instantiate();
are appended with "(Clone)".
Related
Im new to Unity and c#, I've been making a turn based game following one of Brackeys tutorial and i've added scriptable objects to it. Im looking to instantiate a random enemy everytime a fight starts.
Here's the lines that should be useful : ImageOfMyCode
The resources.LoadAll("Enemies") seems to work since I made 3 scriptable objects and the debug log also says 3.
Im really struggling past this to then shuffle allEnemies and instantite the randomly picked one.
Any help and guidance will be appreciated.
The error you get for the Instantiate is because you pass a number instead the object that you want to instantiate, you can read more about it here: Object.Instantiate
What you can do is the following:
var randomRange = Random.Range(0,allEnemies.Length);
GameObject enemyGO = Instatiate(allEnemies[randomRange],playerBattleStation) as GameObject;
I have a list of game objects, this keeps track of the monsters i have in my game. when the monster is killed, it will be in position 0 of the list. i want to destroy the object in the scene and remove it from the list.
My question is, does the command: list.RemoveAt(0); call the object to get destroyed or does it leave it existing as some sort of memory leak?
I have tried removing the monster, destroying then removing, saving the monster to a var then removing then destroying and all of them cause bugs. If i knew how the command works, i could narrow down the issue to that or something else in my code.
If you make the list a public variable you can see it in the Unity inspector. When you destroy a monster you will see the list change to have the monster set to null. I would remove the monster from the list before destroying. You can call the OnDestroy method on the monster to remove the monster from the list before it gets destroyed. This uses the list's Remove function instead of RemoveAt.
No, removing it from the List won't destroy it. List.Remove() does not destroy GameObjects - it is just your personal list. You would need to call GameObject.Destroy(list[index]); and then you could list.RemoveAt(index); to remove it from your list. However, if we were talking about a list that was NOT GameObjects and it was your own plain Class(), then you don't need to worry about memory allocation because there is a thing called Garbage Collection where .NET will release an object's memory once noone has an active reference to the object anymore.
I had a similar issue just now.
The problem with storing a Unity GameObject in a list is that deletion becomes a two part problem. First you need to delete the GameObject, then the list item.
It becomes tricky if you are trying to do this in a ForEach loop, because deleting an item while in a ForEach loop causes issues as you are changing the conditions of the loop on the fly by deleting one of the collection.
My work around is to use a for next loop and a boolean flag to get the job done.
do
{
for (t = 0; t < BossObjects.Count; t++)
{
StillWorking = false;
if (BossObjects[t].FlaggedForDeletion)
{
Destroy(BossObjects[t].WholeBossBoxGO); // Delete the Gameobject
BossObjects.Remove(BossObjects[t]); // Delete the List item
StillWorking = true; // Flag we need another iteration
break; // Needed because we changed the list count
}
}
}
while (StillWorking);
Maybe im missing something obvious but to keep it short. I have working code for a character. When you "dash" I want to leave behind an after-image type effect, by cloning the player, removing its unneeded components and then applying a shader. Issue is as soon as I instantiate the clone the original player stops functioning (cant move etc). It still has all its components and everything as normal, and the clone does get the correct components removed. But it still breaks. As soon as I remove that line, its back to normal. Any ideas?
This is the only relevant code in the script that instantiates the clone.
private void DodgeEffect()
{
GameObject _DodgeSFX = Instantiate(gameObject, transform.position, transform.rotation );
Destroy(_DodgeSFX.GetComponent<PlayerController>());
Destroy(_DodgeSFX.GetComponent<PlayerCombat>());
Destroy(_DodgeSFX.GetComponent<WarpController>());
Destroy(_DodgeSFX.GetComponent<Animator>());
}
its because you are making a copy of gameObject. while Instantiate() returns a GameObject, it also returns whatever you put into the first section of the method. instead, make a seperate gameObject than the player in the editor, and make _DodgeSFX public so you can put the copy into the slot. Then, just instantiate that seperate GameObject and you wont have to destroy the components through script(because you remove the components in the editor), saving time
Ok so from some testing I think its down to the Unity.InputSystem only allowing 1 instance of each Input to be enabled at once. When I instantiated a clone of the player, it still goes through the Enable/Awake functions before those components are destroyed, and since the Inputs on that clone were never disabled, that becomes the "main" one. If I set the main player's scripts with Inputs deactive and then active again, it all works as normal. Note that the script was still working on the main character just fine, it was only the inputs that was broken. Im still not sure why this is the case, if its a limitation of the input system, or intentional, cant seem to find documentation of this experience anywhere.
I'm running a robot simulation in unity where each of the 300 robots runs the same script and I'm using RayCast for communication between robots. Each robot cast 36 Rays in 10 degree increments to cover all 360 degree every 0.02s. This is done using the RaycastCommand so its done in parallel and isn't causing any performance issues. The issue comes when trying to process the RayCast Data.
I need to loop over every result and compare the tags and ID in each robot script as such:
for(int k =0; k< results.Length; k++) // For every result
{
if(results[k].collider !=null) // Check if RayCast collision happened
{
if(results[k].collider.tag == "Robot") // Check that collision is with robot
{
var ID = results[k].collider.GetComponent<RobotControl>().ID; // Get The robot ID
if(!listID.Contains(ID)) // Check that it hasnt comunicated with that robot yet
{
listID.Add(ID);
Debug.DrawRay(origin + (0.55f* Directions[k]), Directions[k] * results[k].distance , new Color(Directions[k].x, Directions[k].y, Directions[k].z, 1));
// Grab important info here
}
}
}
}
The main problem being I cant use IJobParallelFor since I'm accessing the collider and trying to read the tag, and this is the part of the code tanking my performance since everything else is done using Parallel Jobs. The real issue is accessing the components is expensive.
Any Ideas on how to make it more efficient or somehow parallelize it?
Is there a way to access GameObject specific data, like ID, without accessing their components?
In general instead of 36 casts per robot can't you just use a Physics.OverlapSphere would probably already reduce it a lot since an overlap sphere is pretty easy to compute for the physics engine (if(distance < sphereRadius))
Then one thing costing a lot performance in your case is probably that Contains on a List. There you should rather use a HashSet. See Performance List vs HashSet for your 300 objects that would probably be worth it.
Or further to me it sounds like you would want to know which other robots are close to that one ... you could give each robot a SphereCollider on a certain layer so they only collide with each other, make it Triggers and store them in OnTriggerEnter andremove them in OnTriggerExit.
Is there a way to access GameObject specific data, like ID, without accessing their components?
Well, yes, you can access GameObject specific data like e.g. .name. But that ID is clearly not something GameObject specific but in your RobotControl class so, no, there is not really a way around GetComponent.
However, in newer Unity versions the GetComponent isn't that expensive anymore since the references are hashed and serialized on edit time.
Question is do you really need that ID list or would it be enough to simply save the collider/GameObject references and access the specific component only when really needed?
In your specific case here also the Debug.DrawRay is something extremely expensive and you should not do it too often and for possible 300 * 299 times ;)
I made a fade out effect on a parallax layer and I've done this:
if(currentBackgroundPhase == BackgroundPhase.Night)
{
foreach(SpriteRenderer sprite in GetComponentsInChildren<SpriteRenderer>())
{
if (sprite.name.Contains("Cloud"))
{
sprite.color = new Color(opaqueCloud.r, opaqueCloud.g, opaqueCloud.b, transitionTimeElapsed / TRANSITION_TIME);
}
}
}
The parallax keeps repositioning cloud sprites and this is the only way I can think to do this.
I've looked profiler and didn't see a drop on performance when the if is called.
Is this too expensive / unefficient because the GetComponensInChildren? If so, is there other way to do this?
I looked on profiler's scripts graphic to see if this is too much but didn't notice anything strange.
I can't test on a bad device because I don't have one, and I want this to work on every android device...
The maximum amount of spriterenderers that can be in children is 20 or so.
Well there are some tips that could be helpful to you
Use object pooling if needed as you don't have to destroy and instantiate clouds again and again.
Try Avoiding Foreach loop its not noticeable right now but it does have an impact over for loop.
If a for each loop used for collection or array of object (i.e. array of all elements other than primitive datatype), GC (Garbage Collector) is called to free space of reference variable at the end of a for each loop.
foreach (Gameobject obj in Collection)
{
//Code Do Task
}
Whereas for loop is used to iterate over the elements using an index and so primitive datatype will not affect performance compared to a non-primitive datatype.
for (int i = 0; i < Collection.length; i++){
//Get reference using index i;
//Code Do Task
}
You can try pooling Gameobjects. Just activating deactivating them.
If one cloud is 100% transparent you can deactivate it and reuse somewhere else. If you are moving the clouds it should be possible.