Hey,
I am a medium skilled coder but not too familiar with c#. I have found a lot on this error but nothing helps because my array is a Quaternion array and none of the solutions I have found work. In the code below the quaternion value stored in pellets[ i ] is changed in the code and when it loops back it throws the error.
error: InvalidOperationException: Collection was modified; enumeration operation may not execute.
I am trying to find out which line of code is changing the array value and how can I prevent it from happening or do a work around of some sort. Thank you.
[PunRPC]
void RPC_Shotgun()
{
//play sound
audioS.clip = sound_shoot;
audioS.Play();
audioS.time = 0.0f;
Quaternion q;
//create the shooting bullet
int i = 0;
foreach (Quaternion quat in pellets)
{
pellets[i] = Random.rotation;
GameObject inst_pellet = Instantiate(shellPrefab, w_nozzle.position, Quaternion.Euler(0, 0, 0));
inst_pellet.transform.forward = w_nozzle.right;
inst_pellet.transform.rotation = Quaternion.RotateTowards(inst_pellet.transform.rotation, pellets[i], spreadAngle);
inst_pellet.transform.SetParent(bulletCointainer.transform);
Shell bulletSc = inst_pellet.transform.GetChild(0).GetComponent<Shell>();
bulletSc.objective = hit.point;
bulletSc.playerORigin = PV.Owner;
//dump values of rotation
Vector3 rot = new Vector3(inst_pellet.transform.rotation.eulerAngles.x, inst_pellet.transform.eulerAngles.y, inst_pellet.transform.eulerAngles.z);
i++;
}
//a bullet is created and subtracted from the number of bullets
nb_bullets -= 1;
}
what is the type of pellets?
I wouldāve typed the solution if a medium coder would give me the necessary tools to work with.
edit:
I assume itās just a list (edit2: sorry Iāve just seen you said itās an array)
you can fall back to a for loop, itās actually what I would recommend anyway, because a) youāre using a counter and b) foreach is not terribly efficient for such use cases and doesnāt not improve readability in your case
you can make a copy of the list before you run this loop (probably too expensive, but still, you could make a non-allocating recyclable list, maybe even private static for this purpose)
you could always try and comment the inner block then uncomment each line to see what exactly affects the collection
edit2:
well, because itās an array, please donāt use a foreach in this case.
itās an absolute overkill for a nimble structure such as 1D array that should run fast and be friendly to your memory composition. use a for and be happy.
it helps to learn what exactly foreach does under the hub. itās not a bad programming practice, but when youāre making games youāre supposed to squeeze your performance out of anything. in this case the compiler has to make a hidden enumerator class for your array, and to call bunch of methods to be able to traverse it, and then you also stumble onto this error, which means there is an overhead of error checking in the background, which is just mindboggling.
my general recommendation would be to use foreach when:
a type youāre iterating is truly an enumerable: lacks an index, is unordered, or has a complex record, like dictionaries have key-value pairs (though dictionaries also donāt have indices and are unordered)
you call this seldomly and it drastically improves readability of your code
if you need to get a good grasp on C# feel to be able to discern best practices on your own, ask me on its features here, Iāll try to elaborate whatās what. Iāve been there 10 years plus ago, coming from a different environment, I know what itās like. and it was worse back then, it used to be very boilerplate-y, but in the meantime C# became much more slick and productive, tbh.
I want to thank you for the help and apologize in advanced for not being a āmediumā coder but a stupid noob. The following code is what I used to create the list and fill it with starting values. All of this is from a tutorial I followed that was close to what I want to achieve.
List pellets;
public void Awake()
{
pellets = new List(pelletCount);
for (int i=0;i <pelletCount; i++)
{
pellets.Add(Quaternion.Euler(Vector3.zero));
}
}
It is a list. What I am attempting to do is create a shotgun effect, firing a number of pellets out in one shot, randomly changing the angle of each pellet. Once each is instantiated, it is treated like a bullet and the resulting prefab has the controls for velocity and collisions and this script just instantiates it and points it in the right direction.
I found answers that say to copy the list, but they donāt seem to work in this case as the toList isnāt available, if that helps.
In general, thatās a Linq feature (IEnumerable extension), you need to using System.Linq; to get it.
While weāre at it, I donāt recommend using Linq in game dev, unless you have a really good reason: i.e. it makes your code massively more compact and/or readable or (in rare circumstances) improves your performance (by being more memory-aware or cycle-conservative, but this is rarely the case). Use it seldomly though, and when you feel you get things under control, especially stuff like copying large objects heap to heap and such.
Linq is basically āfilthyā because it does things that are too cumbersome for the most part, even if they look nimble. Itās a compilation thing (google up c# lowering) and not essentially a feature of CLR, like that foreach you used that can bite your ass off if you donāt master the fundamentals first.
So what Iām saying is that you need to have a pretty good understanding of what Linq does, if you want to use it competently. I have nothing against it but its simplicity is an enticing gateway to a pretty bad abuse/misuse.
This is why Iāve offered my help. There is A LOT to learn. But itās really rewarding. I was angry at C# at first, it made me really angry, as it was very cumbersome to write when I started, coming off from a far less strict but much more productive environment.
The simplest of things were a pain to do, so many ways just to loop over things, not a single best way to do anything because of legacy stuff holding you back, no useful mnemonics to gather around patterns in your head, so few ways to manipulate an array, but no associative arrays, callbacks stupidly hard to implement, then thereās Linq, delegates, generics, structs, too many stuff going on all at once. But I was persistent, and had to adapt, and learned learned learned, until Iāve had it mapped in my head. Iām still learning though, ten plus years in the future, itās bizarre how big it is. In its latest incarnations, it has seriously become my favorite imperative language so far, and Iāve been coding since 1987.
Oh, Iāve been a VB guy in the late 90ās. I loved it, but then I fell in love with C syntax all of a sudden. Iām thankful for the VB chapter in my life, because I learned a lot from itās offline MSDN docs, pre-internet.
If it helps, my focus in code isnāt that much in getting things done, though Iām an engineer at heart, then a demo coder next. I like my code elegant, beautiful, and clever all at once, in that respective order, the latter being sacrificed the most (when a sacrifice has to be made). And itās a useful habit of mine, not because Iām popular at companies (Iām clearly not), but because I can stress test a language by trying to redesign the codebase until it resembles poetry. The language isnāt potent if it canāt look like poetry, at least in places. C# is 10/10 in this regard, even surpassing ActionScript 3 which is probably still the most expressive OOP language I have ever worked with.
Though it is necessary to distinguish such poetry from the clockwork code and the API code. These two typically require a different approach, because you simply have to make compromises either for performance or maintainability. Clockwork is very similar to C++ in C#, and I missed being able to go low in some higher languages, here youāre enabled to overload your operators, you can access memory directly, you can fiddle with how things will get compiled, optimize your calls, optimize access by reference, itās not only about applying the organizational structure and building patterns, you can truly design something really performant. So it really pays knowing what exactly is going on with this language.
You know i.e. you can set your goals to try and triangulate a patch of hundreds of sampled points in a 50 ms budget. And you can really pursue this goal and do all kinds of things, not just a straight triangulation, but ray casting, edge flipping, mesh relaxation, and there is still room to shave it more and more, and do marvelous things within the budget. The only other language capable of this, in my experience, is C/C++, but imo itās simply too wild to be saddled by a lone cowboy. This lets me get things done.