Using foreach to remove and delete bullet in List - C#
Hi all,
EDIT: Using C#
I am trying to find a proper way to delete bullets and remove them from my List<>. Currently I'm removing them from within the foreach, and this gives me and exception becuase I'm trying to remove while the foreach is working:
//Shooting
if(Input.GetButtonDown("Fire1")){
Rigidbody bulletClone;
bulletClone = (Rigidbody)Instantiate(bullet, ship.transform.position + bulletCorrection, bullet.transform.rotation);
bulletClone.velocity = transform.TransformDirection(Vector3.forward * bulletSpeed);
bulletList.Add(bulletClone);
}
foreach(Rigidbody bulletSearch in bulletList){
if(bulletSearch.rigidbody.position.x > 10){
DestroyObject(bulletSearch.gameObject);
bulletList.Remove(bulletSearch);
}
}
I'm wanting to figure out the cheapest way to do something like this, and of course avoid errors.
I've tried using for loop, and creating seperate list to keep track of everything that needs destroying/removing but I've not been successful. If an answer is already available on this site or another please direct me there. Thanks--
Answer by aldonaletto · Nov 20, 2011 at 10:45 AM
Why do you need a list? If you just want to destroy the bullets which are above some y coordinate, forget about the list and place this code in the bullet script:
void FixedUpdate(){ if (rigidbody.position.y > 10){ Destroy(gameObject); } }But if you really need to keep all bullets in some list for other reasons, just let Unity do that for you: create an empty object, reset its position to 0,0,0, name it "Bullets" and child all bullet instantiated to it:
Transform bullets; // <- drag the "Bullets" empty object here ... if(Input.GetButtonDown("Fire1")){ Rigidbody bulletClone; bulletClone = (Rigidbody)Instantiate(bullet, ship.transform.position + bulletCorrection, bullet.transform.rotation); bulletClone.velocity = transform.TransformDirection(Vector3.forward * bulletSpeed); bulletClone.parent = bullets; // bullet is child of "Bullets" }Every destroyed bullet is automatically removed from the children list, thus you don't need to update it yourself. If you need to iterate through all bullets, use a foreach like this:
foreach (Transform bullet in bullets){
// do whatever you want with this bullet
}
Let me also note that this is in C# But what seems to be happening is that every time I fire the bullet, the reference to any transform is lost, so in order to retain this info to check for destruction parameters (past X location, and future collision detection) I'm storing in list, but will try doing your way and parenting with another object
alright, thank you sir! that worked great using the parenting
Answer by Owen-Reynolds · Nov 21, 2011 at 12:49 AM
If you do want to use your own list, this works (I'm not a native C# programmer, so there may be a more standard way.) I used a LinkedList type just because. List is probably the same:
LinkedList<MovingText> L; // global
LinkedListNode<listType> nn = L.First;
while(nn != null ) {
// Play with nn.Value:
nn.Value.update();
// grab reference to next, so we can safely delete:
LinkedListNode<listType> nNext = nn.Next;
if(nn.Value.isDead()) { // isDead is just my hand-written check
L.Remove(nn);
}
nn = nNext;
}
Answer by CaseyLee · Aug 18, 2017 at 09:35 AM
Old question, but no one seemed to notice the authors original code was getting an error because he was attempting to reference the object he had just destroyed...
if(bulletSearch.rigidbody.position.x > 10){
DestroyObject(bulletSearch.gameObject); //. Destroying parent GO also destroys components.
bulletList.Remove(bulletSearch); //. Now he's trying to reference null obj.
}
I don't think so. Destroy is not instantaneous so the object shouldn't be null yet. DestroyImmeadiate() might cause a problem.
The error is probably what the author says: modifying a collection you are enumerating over
The thing is, this is a typical total UA swerve question. The green answer really says "I think you're a total beginner in way over your head. You just grabbed that foreach off the internet and don't even know why you have a list. Just scrap it and use this limited, simple intro way ins$$anonymous$$d." And the OP accepted it, acknowledging "yes, you are correct."
So the poster asked a Q they didn't want the answer to, the first answer doesn't answer it, and, as N$$anonymous$$ points out, it's just a basic C# Q that doesn't belong here. I was a sucker and gave a straight answer (that was 6 years ago, but I still should have known better.) But now we have a HelpRoom, where "I'm lost and confused, any advice" Q's are fine.
Oh...I'm pretty sure I've used a Destroyed gameObject during that frame. I believe I've destroyed then disabled (in that order) and been fine. But it's probably a bad idea - the sort of thing that breaks in the next Unity version.