ZFGC

Resources => Coding => Topic started by: Theforeshadower on February 15, 2012, 04:38:49 am

Title: Need some help: C#/XNA List Remove
Post by: Theforeshadower on February 15, 2012, 04:38:49 am
Code: [Select]
            foreach (clBullet b in spriteList)
            {
                b.Update(gameTime, Game.Window.ClientBounds);
                if (b.position.X > 300)
                    spriteList.Remove(b);
            }
The code works fine until b.position.x > 300.  It won't remove it and causes the debugger to kick in with exceptions.
Any thoughts?

The bullets draw fine and update fine until the above situation happens.
Title: Re: New some help: C#/XNA List Remove
Post by: Cassyblanca on February 15, 2012, 05:48:25 am
Based on the symptoms you're describing, I'm guessing that there's something in clBullet.Update() that's causing them to be removed from the list already.

If that isn't the case, providing all information relevant to your situation (you know, like those exceptions you mentioned?) would certainly go a long way to helping us help you.
Title: Re: New some help: C#/XNA List Remove
Post by: Theforeshadower on February 15, 2012, 05:58:22 am
I ended up doing this:
Code: [Select]
            foreach (clBullet b in spriteList)
            {
                //if(b.position.X < 300)
                b.Update(gameTime, Game.Window.ClientBounds);
            }
            if (spriteList.Count > 0)
            {
                if (objBullet.position.X > 300)
                spriteList.Remove(objBullet);
            }
           
I don't get the error anymore.
Pretty sure there has to be a better way.  It was an enumerator error that was popping up.  I think the problem was that I was trying to remove something in the list while going through the list itself.  Lists are still a new area for me, so i do not quite understand the way it works.  I figured it would be best to handle bullets and other weapons this way and possibly enemies as well.


Here is the other code that may or may not help:
Code: [Select]
if (Keyboard.GetState().IsKeyDown(Keys.Z))
            {
                if (shootTimer == 1.5f)
                {
                    objBullet = new clBullet(Game.Content.Load<Texture2D>(@"Content/Images/sprBullet1"), new Vector2(objPlayer.position.X+8, objPlayer.position.Y+8), new Point(15, 5), 5, new Point(0, 0), new Point(0, 0), new Vector2(1, 1), true, 200);
                    spriteList.Add(objBullet);
                    shootTimer -= 0.1f;
                }
            }
            if (shootTimer < 1.5f)
            {
                shootTimer -= 0.1f;
            }
            if (shootTimer <= 0.0f)
            {
                shootTimer = 1.5f;
            }

            foreach (clBullet b in spriteList)
            {
                if(b.position.X < 300)
                b.Update(gameTime, Game.Window.ClientBounds);
            }
            if (spriteList.Count > 0)
            {
                if (objBullet.position.X >= 300)
                spriteList.Remove(objBullet);
            }

I need to put in some code to draw the number of objects in the list to make sure it is actually removing the bullets.
Title: Re: New some help: C#/XNA List Remove
Post by: Zaeranos on February 15, 2012, 06:36:25 am
Code: [Select]
            foreach (clBullet b in spriteList)
            {
                b.Update(gameTime, Game.Window.ClientBounds);
                if (b.position.X > 300)
                    spriteList.Remove(b);
            }
The code works fine until b.position.x > 300.  It won't remove it and causes the debugger to kick in with exceptions.
Any thoughts?

The bullets draw fine and update fine until the above situation happens.
The problem is the foreach this statement cannot be used to add or remove items from the source collection. You should use one of the other loop statements. A while loop is probably the best option.

try this:
Code: [Select]
            int i = 0;
            while (i < spriteList.Count())
            {
                clBullet b = spriteList.Item[i];
                b.Update(gameTime, Game.Window.ClientBounds);
                if (b.position.X > 300)
                    spriteList.Remove(b); // or spriteList.RemoveAt(i);
                else
                    i++;
            }
Title: Re: New some help: C#/XNA List Remove
Post by: Theforeshadower on February 15, 2012, 10:10:15 am
I can't quite get your code to work with mine.

My code I posted only removes one object from the list.  I will post more later, going to bed right now.
I tried a form of removeall as well but that didn't work either.  Still only one bullet is being removed.
Title: Re: New some help: C#/XNA List Remove
Post by: Xfixium on February 15, 2012, 10:50:43 am
First off Niek is correct about removing/adding things to a list in a foreach loop. I also think that Niek's code should work. I would set a break point and step through following the life of a single bullet object to make sure certain conditions are met.
Title: Re: Need some help: C#/XNA List Remove
Post by: Theforeshadower on February 15, 2012, 06:47:46 pm
Thanks for the help , guys.  I ended up doing it this way:

Code: [Select]
for (int i = 0; i < spriteList.Count; i++)
            {
                if (spriteList[i].position.X < 260)
                {
                    spriteList[i].Update(gameTime, Game.Window.ClientBounds);
                }
                else
                {
                    spriteList.RemoveAt(i);
                }
            }
Works like a charm :)

The problem with Niek's was the spriteList.Item.  VS 2010 was tossing compile errors and such over the word "Item".
Title: Re: Need some help: C#/XNA List Remove
Post by: Xfixium on February 15, 2012, 09:13:22 pm
Oh yeah, missed that. I'm so used to dealing with actual listbox.items[] that I passed right over that. The correction to that would've been:

Code: [Select]
spriteList[i]
Which you've demonstrated you understand in your new code. Honestly, I would still see if that for loop you use works correctly. Because the i < spriteList.Count; portion of the for loop I believe gets evaluated each loop. It might give you unexpected results.

EDIT: Also, how about the lambda expression for a RemoveAll as an alternative? I usually use this sort of evaluation for finds but I'd imagine it'd work for removes as well:

spriteList.RemoveAll(s => s.position.X < 260);
Title: Re: Need some help: C#/XNA List Remove
Post by: Theforeshadower on February 16, 2012, 06:33:38 am
I was trying something similar to that but it was not working right.  Probably something wrong with my code.  it would only remove one bullet total.  I am fairly certain my code works like it should as I have a string of the spriteList.Count drawn on screen for me and the number seems exact to the number of bullets on screen now.  before, it just kept adding up and up then removing one if I stopped firing.

So, if my understanding of a list.count is correct that it keeps track of the number of items in the list, it should be working fine.
Title: Re: Need some help: C#/XNA List Remove
Post by: Zaeranos on February 16, 2012, 06:35:10 am
Okay, I hadn't checked if it really worked and I mostly went by the MSDN site what they offered. However I still think that your code is wrong in that you are using a for loop. The while loop is a better choice.

The for loop forces the variable i to be increased every itteration. However when you remove item A from the list every thing gets shifted up. Thus the item B at i+1 becomes the item B at i and the item C at position i+2 becomes item C at position i+1.  In the for loop the i gets increased by 1 again and you will update or evaluate item C. Item B will never be evaluated or updated after the remove of item A.
Title: Re: Need some help: C#/XNA List Remove
Post by: Theforeshadower on February 16, 2012, 06:43:37 am
I had tried the while loop in a few different variations and it caused the game to hang-up and the debugger went nuts in VS 2010.  I haven't had any problems since I tried my code.  I think it is working fine at this point because there are no enemies that you can shoot down yet.  So, the process is linear in that bullet 2(or b as you said) will never go past the screen before bullet 1(or a).

Thinking about what you said, I might have to rework the code once I start tossing enemies in there as bullet b could go outside the screen but bullet a may be removed from the list due to hitting an obstacle or enemy.
In that case, I am thinking I may just need to add conditions in my for loop for collisions with enemies and obstacles. Or maybe not...I guess I will find out when I get there.
Title: Re: Need some help: C#/XNA List Remove
Post by: Zaeranos on February 16, 2012, 06:50:18 am
The only issue would be that bullet B would stand still for one frame and the distance between bullet B and C becomes smaller. And you must be doing something very wrong if you cannot substitute a for loop with a while loop.
Title: Re: Need some help: C#/XNA List Remove
Post by: TheShyGuy on February 24, 2012, 01:38:46 pm
Code: [Select]
  foreach (clBullet b in spriteList)
            {
                b.Update(gameTime, Game.Window.ClientBounds);
                if (b.position.X > 300)
                    spriteList.Remove(b);
            }
------------------------------
Code: [Select]
for(int i = spriteList.Count -1; i >= 0; i--)
{
    b = spriteList[i];
    b.Update(gameTime,Game.Window.ClientBounds);
    if(b.position.X > 300)
      {
         spriteList.Remove(b);//or spriteList.RemoveAt(i);
      }
}





its working its way backwards down the list.  Removing anything wont affect the current sprite and you wont skip any because it will remove from the back of the list.
Title: Re: Need some help: C#/XNA List Remove
Post by: hawthorneluke on March 31, 2012, 01:38:51 pm
Not sure if this is too old, but for anyone with problems when removing things from a list: generally it seems to be best to use a for loop (not foreach) and go through the entire list in reverse, like shown in the post above.

A list is far more complicated than an array and if you are to remove something from it, it'll clean itself up so there are no gaps in it by moving items and changing its length. That's generally very helpful, but having that happen half way through a for loop obviously isn't and just asks for disaster. But if you plan for this, by creating a for loop where it doesn't matter if the length if decreased by one the last loop or items are shifted by one the last loop then you should have no problem. What sort of set up would deal with this? One that starts at the top and goes down, keeping up with a shrinking list, not one that starts at the bottom and aims to go to the very top of the list that could change in size half way through. Of course if there is the change of you removing more than one item from the list in one loop, then you'd need to do a check to see if the current i is <= the length/size of the array. (You of course could do this same check with a normal bottom to top for loop to see if the i is still in range and break out of the list if it isn't, but then what happens when all the items above the removed item are shifted down one? You skip checking one item because the i has moved on, but the index number of all the items above the removed one has decreased by one. This doesn't matter with a reverse loop as you've already checked all the items above the removed item. This is also why you can't use a foreach with loops dealing in lists that may change half way through, because you state you want to go through each index of the list at the very start, but half way through change the list. Of course the computer will get confused when it comes across an index it was told to go through that no longer exists.)

Also with lists in C#, you may run into problems where you update objects and then the list relays back something different to you. This is because (under certain circumstances?) once you change an object that is part of a list, you need to put it back into that list, otherwise the list will continue to point to the previous object state before you changed it, or something annoying like that.

Contact Us | Legal | Advertise Here
2013 © ZFGC, All Rights Reserved