GdScript Global Array change and iterate

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By zhaishengfu

I have a big problem these days.

I have one global array such as Fruit, which has all the fruits. for example:

var Fruit = [Apple, Peach, Pear, …]

and there are one class “PLAYER”, which can change this array at any time.

PLAYER.eat(Apple) # will remove the Apple from Fruit array

Then, I have ten thousand Farmers that inherits another class called “NPC”. the NPC iterate the Fruit array and call the logic about each fruit, such as :

for each_fruit in Fruit: ....each_fruit.get_nutrition()

then there will be big problem: some fruit may be eaten in the for loop, so each_fruit will be null can cause an error

and i find some book that said the for lool will lock the global Fruit Array? is this true? But i find that PLAYER can always eat the fruit, so i really doubt it .

Anyone know the answer will help me a lot, thanks!

:bust_in_silhouette: Reply From: exuin

Removing an item from an array will not replace it with null, it will just remove it and shift the indexes of the elements to the right one to the left. But if you’re worried about null pointers you can just put an if statement to check if the element exists before calling the method.

As for the locking thing, I’m not sure if that’s true with GDScript. Where did you read that?

I think he is worried about item being freed in the exact moment of iteration. That can happen, will return null and crash with error. If this is it, correct check is is_instance_valid().

Inces | 2021-03-25 18:56

  1. I understand your means of using “if statement”, which should be the same as @Inces said by using isinstancevalid(). But I think this is not a elegant solution. If this way , each for loop will use one isinstancevalid(), for example

    for A in Array:
    …if isinstancevalid(A)
    …for B in getArraysAbout(A):
    …if B in isinstancevalid(A):
    …do_logic(B)

    put ‘isinstancevalid()’ performance aside, for large number NPCs, each for loop will use isinstancevalid() ??

  2. “the locking thing” is answered by @Vintagegodotuser for this question
    https://forum.godotengine.org/18424/a-question-about-modifying-arrays-and-dictionaries
    He said ‘Godot seems to work a bit strange handling arrays or dictionarys while iterating over their contents. Obviously those vars are locked (like a const!)

zhaishengfu | 2021-03-26 02:07

Yes, for large number NPCs, sometimes will cause strange error(array change or null).
‘isinstancevalid()’ should be one solution, but I think this is not elegant solution with high performance as I replied

zhaishengfu | 2021-03-26 02:12

The only other option I can see is to border timing of iterating farmers and player eating. You would have to hold one until another is done, with yield() for example

Inces | 2021-03-26 12:02

Yes, this is similar to use lock when PLAYER eat and unlock it when eat is done.

zhaishengfu | 2021-03-27 08:40