0

I am creating an ant simulation program where ants travel around and collect food and bring it to the nest. When a certain number of ants have collected from the food I want the food source to disappear. I have a separate class for antObject, foodObject and nestObject.

I have a 'int foodleft = 25' variable in my stationaryFood class. The foodobjects are placed onto the screen when the user clicks, and are immediately added to a list object 'foodList'. A draw method draws all the objects in the list. I cannot figure out how to make the specific food object disappear when its 'foodLeft' variable hits 0!

Here is my draw method in my stationaryFood class -

  public void Draw(SpriteBatch spriteBatch, List<stationaryFood> foodlist)
    {
        foreach (stationaryFood food in foodlist)
        {
            spriteBatch.Draw(foodImage, foodBoundingRectangle, foodColor);                                                              //draw each food object in foodList
        }
    }

And here is my attempted solution to the problem in my main 'game1' class in the update method

  if (foodList.Count > 0)
        {
            foreach (stationaryFood f in foodList)
            {
                if (f.FoodLeft == 0)
                {
                    foodList.Remove(f);


                }
            }
        }

However this does not work! I get an 'unhandled invalid operation error'.

In my draw method in my main game1 class I have this

        foreach (stationaryFood f in foodList)
        {
            f.Draw(spriteBatch, foodList);
        }

Can anybody see where I am going wrong?

rene
  • 41,474
  • 78
  • 114
  • 152
  • I've edited your title. See [Should questions include “tags” in their titles?](http://meta.stackexchange.com/a/130208/158100) where the consensus is "no, they should not". – rene Apr 14 '14 at 13:14

3 Answers3

3

You're modifying the collection as you're iterating through it, hence why you're getting an exception. In your case, instead of this:

foreach (stationaryFood f in foodList)
{
    if (f.FoodLeft == 0)
    {
        foodList.Remove(f);
    }
}

Do this instead (assuming it's available in XNA):

foodList.RemoveAll(x => x.FoodLeft == 0)

If it isn't, you can look at the answer in this question for an alternative.

Community
  • 1
  • 1
George Howarth
  • 2,767
  • 20
  • 18
  • Sorry im actually quite new to programming and haven't learnt this yet. What does the X signify? Also would the 'if' statement above it still be there or not? Thanks for the response – user3486095 Apr 14 '14 at 13:10
  • Also this doesn't give me an error which is good! But the food doesn't disappear! From what I can gather its because it only draws it once at the start of the game in the draw method and then even though its removed from the list it doesn't disappear because the list isn't drawn again :( – user3486095 Apr 14 '14 at 13:12
  • If that is the case, then you have to re draw the list. Any change you make to an object on the screen needs a call to the Draw method in order to reflect the change! – Nahuel Ianni Apr 14 '14 at 13:15
  • The syntax inside the `RemoveAll` method is a [Lambda Expression](http://msdn.microsoft.com/en-us/library/bb397687.aspx). In the answer, the lambda is executed for every item in the list where `x` is the "current item". If you wish, you can replace `x` with `f` if it's more readable for you. – George Howarth Apr 14 '14 at 13:16
  • Thanks for the explanation! I tried this foreach(stationaryFood f in foodList) { foodList.RemoveAll(x => x.FoodLeft == 0); f.Draw(spriteBatch, foodList); } But I got another error that the 'begin' method must be called before the draw – user3486095 Apr 14 '14 at 13:20
  • I think I need to somehow call my game1's draw method , but im not sure how to do that – user3486095 Apr 14 '14 at 13:26
  • It's best if you post a new question regarding your problem. – George Howarth Apr 14 '14 at 13:29
  • @user3486095 Looking at your second-last comment, you need to complete remove the foreach loop. Delete the foreach loop in your code and replace it with George Howarth's single-line solution. – user3256944 salutes Monica Apr 15 '14 at 07:55
0

George Howarth's answer will work perfectly fine.

If you are uncomfortable with lambda expressions you could try reverse iteration:

foreach (stationaryFood f in foodList.Reverse<stationaryFood>())
{
    if (f.FoodLeft == 0)
    {
        foodList.Remove(f);
    }
}

Reverse iteration allows us to loop through a collection and remove items at the same time.

  • The `Reverse` method will make a copy of the list, so you are not modifying the same collection. I would recommend against this method since it will lead to a performance penalty which is important to reduce in game programming. – Dustin Kingen Apr 14 '14 at 13:35
0

Preamble:

Game programming is a good way to get started with C#, but I would advise to read more into the basic constructs like for, foreach and the language conventions.

The first five modules in the Microsoft Virtual Academcy Programming in C# Jump Start will greatly increase your understanding of the language.

Answer:

I could not see a reason to use foodlist in the stationaryFood class. This will draw overlapped textures which is pointless.

public void Draw(SpriteBatch spriteBatch)
{
    spriteBatch.Draw(foodImage, foodBoundingRectangle, foodColor);
}

You can make a method which will remove items from the list.

private void RemoveFood(List<stationaryFood> foodlist)
{
    var foodToRemove = new List<stationaryFood>();

    foreach(var f in foodlist)
    {
        if(f.FoodLeft == 0)
        {
            foodToRemove.Add(f);
        }
    }

    foreach(var f in foodToRemove)
    {
        foodlist.Remove(f);
    }
}

Later on when you learn about lambdas it can be simplified to:

private void RemoveFood(List<stationaryFood> foodlist)
{
    foodlist.RemoveAll(food => food.FoodList == 0);
}

You can add this in the Update method.

if (foodList.Count > 0)
{
    RemoveFood(fooList);
}

And change the logic in the Draw method.

if (foodlist.Count > 0)
{
    foreach(var f in foodlist)
    {
        f.Draw(spriteBatch);
    }
}
Dustin Kingen
  • 20,677
  • 7
  • 52
  • 92