Best way to iterate over IEnumerable<Pawn> and remove

Started by skullywag, October 21, 2014, 05:29:39 PM

Previous topic - Next topic

skullywag

As per title, I feel there are good ways and bad ways to achieve this, part of me says I shouldnt be removing anything from the IEnumerable<Pawn> and should be using a strongly typed list, does one exist?

or for clarity:

public static IEnumerable<Pawn> FindAnimals(IntVec3 position, float distance)
        {
            return
                from p in Find.ListerPawns.AllPawns
                where p.RaceProps.IsAnimal && p.Position.WithinHorizontalDistanceOf(position, distance)
                select p;
        }


Is there a better way of finding Animals nearby that would then allow me to loop through them and destroy() them or equivalent?
Skullywag modded to death.
I'd never met an iterator I liked....until Zhentar saved me.
Why Unity5, WHY do you forsake me?

Rikiki

I find your code quite elegant. :)
If it works you can then just use a foreach loop on the resulting pawn list.

JuliaEllie

#2
I usually use foreach loops with if statements. It might look like this:

public static void killanimals(IntVec3 pos, float dist)
{
foreach(Pawn p in Find.Map.ListerPawns.AllPawns)
{
if (p.RaceProps.IsAnimal && p.Position.WithinHorizontalDistanceOf(pos,dist)
{
p.destroy();
}
}
}

I didnt test it and it might have some errors because my Visual Studio isnt open and I wrote it from memory. But Im not sure if destroy() leaves a corpse or not I never tried it to be honest :D Maybe you should use destroy(DestroyMode.Kill).

edit: other ways COULD be
p.health = 0;
p.HealthTracker.Dead = true;
those are public variables which SHOULD be accessable

Rikiki

You should better use the pawn.Destroy(DestroyMode.Kill), it is safer than modifying individual parameters.

The default mode of destroy is Vanish, so no corpse, no meat! ;)

What do you plan do do? An eletrocuting trap? A dark energy pulse wave from the altar to defend against crazy animals assault? ;D

skullywag

#4
Its not the destroying that's the issue you can't remove a thing from an IEnumerable list cuz then youve changed the ID position. A for loop would work or even a while as they know the position but a foreach would not work as it doesn't know the position. But I'm hqving issues with for loops, ill grab the error I get shortly.

To be clear my issue isn't destroying, I understand that perfectly my issue is if I have an array list (IEnumerator) how to cycle over it and remove an entry. Knowing that foreach will not work.
Skullywag modded to death.
I'd never met an iterator I liked....until Zhentar saved me.
Why Unity5, WHY do you forsake me?

Rikiki

Maybe create another "enumerable2" and only add into it the element you want from your "enumerable1".

Or add more conditions while selecting the items you want into the enumerable.

By the way, do you know the difference between List and Enumerable? ???

skullywag

I do, I typoed above, hard morning (my 1 year olds being a butt).

Ok so going back to my main problem, ill just ask for different ways of doing this as I'm not at my pc so can't be specific. Give me ways of grabbing all pawns near a thing (building) then loop through and effect those Pawns (destroy in this case). Cuz all the ways I've tried have ended in errors (again not at pc so can't get at em)
Skullywag modded to death.
I'd never met an iterator I liked....until Zhentar saved me.
Why Unity5, WHY do you forsake me?

Rikiki

Sorry I was not testing you, just asking because I don't know the difference. :-[ If you could simply explain it to me...
I believe the Enumerable is a List you can easily iterate on? Or am I all wrong??

skullywag

Technically enumerator should be a readonly list. Thats the fundemental difference. Hence why what I'm doing feels wrong.
Skullywag modded to death.
I'd never met an iterator I liked....until Zhentar saved me.
Why Unity5, WHY do you forsake me?

darktakayanagi

here's my 2cents on it:
from my experience coding in java, u cant remove an element from a list while cycling the elements, what u can do is:
add it to another list
cycle that list and remove them from the original list
clear the 2nd list

im just a beginner programmer so im sure there are better ways to do it, im just trying to help :)

skullywag

Gonna revive this as Ive got a way that works but..it soft errors in the console and im wondering of Tynan/someone can give me a pointer here, I have (for plants, pawn can be used here, its interchangeable):


//List all things in a cell
List<Thing> list = Find.ThingGrid.ThingsListAt(pos);
//Loop over things if there are things
if (list.Count > 0)
{
  //iterate backwards as we have a removal in here
  for (int i = list.Count - 1; i >= 0; i--)
  {
     //If we find a plant
     if (list[i].def.eType == EntityType.Plant)
     {
        //If the plant isnt Ivy
        if (list[i].def.defName != "PurpleIvy")
        {
           //kill it
           list[i].Destroy();
        }
      }
    }
  }
}


I think its this thats erroring with "argument is out of range, parameter name: index".

Is there a better way to loop things in a cell and kill one based on some logic?
Skullywag modded to death.
I'd never met an iterator I liked....until Zhentar saved me.
Why Unity5, WHY do you forsake me?

mipen

I'm pretty sure you could go with your original method and use a foreach loop. Killing something that meets the criteria in the list won't remove it from the list, just set it to being 'dead' or 'destroyed'. At least thats what I think :L