I'd like clarification about functions and creating/destroying.

Not favoritedFavorited Favorited 0 favourites
  • 9 posts
From the Asset Store
_________ Infinite ribbon creation kit ___________
  • There's something strange about how creating and destroying objects work in relation to functions, and I would really like clarification about what's happening in the examples below.

    Obviously in this example, If the layout had no sprites before the trigger, than the sprite count would be 1. Makes perfect sense, but if you count the sprites with a function, something completely different happens

    Even though it should be the same sequence of events in the same frame, the text will display 0 this time. And what's really confusing to me, is that this only happens if there are no sprites on the layout at the time of the trigger.

    This same concept also seems to apply destroying objects. In this example, the function will count the sprites before they are destroyed instead of after.

    One more thing is that if you put Wait 0 in-between the creating/destroying and the function, then everything works as you would expect.

    So basically this phenomenon seems to be a very frequent issue in a project I'm working on, (the examples have nothing to do with the project) and I would really like to understand exactly how and why this works so I can work with it better. Specifically, why does this happen in the first place, and why does Wait 0 fix it?

  • This is a known quirk in Construct: instances created in one event aren’t available to other events until that event finishes. The same applies to destroyed instances.

    There are several workarounds — the most common ones are using Wait 0 or picking newly created instances by UID. Wait 0 works because it delays execution until the end of the current tick.

  • I appreciate the help, but pick by uid isn't relevant to my project, and Wait 0 seems to mess everything else up. It seems simple but in execution, it never seems to work in a predictable way.

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • but pick by uid isn't relevant to my project

    Why isn't it relevant? You can pass the text.UID to the function as a parameter and then pick the text instance by UID inside the function - this is a very common approach, which works for newly created instances.

    Another option is to use a custom action.

  • Because my problem isn't with picking created instances, it's with trying not to pick instances that have already been destroyed. I don't know how to explain my specific problem, but I'm making a battle system that involves 4 symmetrical rows. On each turn, opposing units will deal damage to each other, in order based on their speed and I'm calculating it with one event that repeats 4 times and effects each row sequentially. It works perfectly if no units die, but if one is destroyed, the entire event just stops somehow, even if it hasn't repeated yet. I added wait 0 and it fixed the problem but introduced a bunch of new ones that I don't understand.

    "Action" takes the picked fish, calculates it's target and deals the damage, while "Update" checks all fish to see if they have below 1 hp and kills them. I have tried Wait 0 in every way I can think of and there's always bizarre seemingly erratic results. I might try custom actions instead of functions.

  • I forgot to mention it repeats 4 times again, because there can be a maximum of 4 units on each row.

  • It's a quirk or feature depending how you look at it with how created objects aren't generally pickable right away or how destroyed objects aren't destroyed right away.

    The logic behind it is under the hood the event system maintains four lists of instances of the objects.

    sprite.all = []
    sprite.picked = []
    sprite.new = []
    sprite.deathrow = []

    At the start of an unnested event picked is set to all the instances. Conditions after that will filter the picked instance list.

    When you create an instance the picked list will be set to only the new instance and that instance will also be added to the new list.

    When destroying an object it will be added to deathrow, but it won't actually be removed yet.

    So eventually the event engine has to do some bookeeping and update the all list by adding new instance to it and removing deathrow instances form it. Generally that occurs after each unnested event. However, trigger events that were called from another event don't follow that since they can be considered running in place where they were called.

    To illustrate that here is a simple example.

    On click
    -- create sprite
    -- call function
    -- sprite destroy
    
    on function
    -- create sprite

    Ok, now here is very verbose view of what is going on with those lists following those rules. Lets assume you started with one instance of sprite: A.

    # all=[A] picked=[A] new=[] deathrow=[]
    On click
    # all=[A] picked=[A] new=[] deathrow=[]
    -- create sprite
    # all=[A] picked=[B] new=[B] deathrow=[]
    -- call function
    # all=[A] picked=[B] new=[B, C] deathrow=[]
    -- sprite destroy
    # all=[A] picked=[B] new=[B, C] deathrow=[B]
    ## bookeeping is done here
    # all=[A, C] picked=[A, C] new=[] deathrow=[]
    
    on function
    # all=[A] picked=[A] new=[B] deathrow=[]
    -- create sprite
    # all=[A] picked=[C] new=[B, C] deathrow=[]

    You encountered another quirk of picking when you used the sprite.count expression in one of your examples. Basically, if there are no picked instances of an object all it's expressions will return 0. So you had the following in your example. Since you stated with no instances there will be no picked instances in the function so the expression is 0.

    On click
    -- create sprite
    -- call function
    
    on function
    -- set text to sprite.count

    or verbosely:

    # all=[] picked=[] new=[] deathrow=[]
    On click
    # all=[] picked=[] new=[] deathrow=[]
    -- create sprite
    # all=[] picked=[A] new=[A] deathrow=[]
    -- call function
    # all=[] picked=[A] new=[A] deathrow=[]
    ## bookeeping is done here
    # all=[A] picked=[A] new=[] deathrow=[]
    
    on function
    # all=[] picked=[] new=[A] deathrow=[]
    -- set text to sprite.count
    # all=[] picked=[] new=[A] deathrow=[]

    There may be better ways to convey how that works, but generally I've found most don't really grasp it.

    As to the wait 0 solution that has it's own side effects. The main one is it delays the stuff after it from running till the end of the event sheet, which may or may not be a problem if you are relying on things to run in a specific order.

    Another way around the picking could be "pick by uid" like dop suggested, but I've found that mostly only useful in simple cases.

    What generally try to do to avoid the create/destroy shenanigans is to create objects in one event and do the picking stuff in the next, but that largely depends on what you're doing.

    It's not really useful with nested events but for simpler ones like above I duplicate the event and split the events between them.

    On click
    -- create sprite
    -- call function
    
    on click
    -- sprite destroy
    
    on function
    -- create sprite
    On click
    -- create sprite
    
    on click
    -- call function
    
    on function
    -- set text to sprite.count

    Finally a third way is to deal with the picking system as little as possible and deal with lists of objects in a more traditional programming fashion. That's many's motivation to use js for example.

  • A simple way to exclude destroyed instances is to change one of their properties. For example, you can make them invisible or disable their collisions.

  • Thank you, both of you, I supper appreciate the help! It's a lot clearer how this works now and yeah, just giving the destroyed objects a variable or something that makes them unpickable is super simple. Don't know how I didn't think of that.

Jump to:
Active Users
There are 0 visitors browsing this topic (0 users and 0 guests)