GMS 2 A General Solution to Item Persistence

Discussion in 'Tutorials' started by Ephemeral, Jun 11, 2018.

  1. Ephemeral

    Ephemeral Member

    Joined:
    Mar 1, 2017
    Posts:
    179
    GM Version: GMS2
    Target Platform: All
    Download: N/A
    Links: N/A

    Summary:
    A question I see asked a lot, is, "if I have my player character pick up an item in a room, how do I get that room to remember that the item shouldn't be there anymore after leaving that room and returning?"

    And every time, I see a different answer.

    (Sometimes the answer is, "just use the tickbox to make the room persistent in the IDE," which you should definitely not do.)​

    There are a lot of viable ways to set this up, and the method I am going to explain here may not be optimal for your game in particular, but it should demonstrate the principle in a way that is meant to be as widely applicable as possible.

    Tutorial:

    Before any code, you will need three things.

    An initialization room (which can double as your main menu or any other pre-game-world room, which means you probably already have this in some form).

    An object which we will name hndl_persist to handle the persistence. Place an instance of this object in your initialization room. Make sure hndl_persist has its "Persistent" checkbox ticked so that it will survive room changes.

    An object which we will name prnt_pickup to be assigned all pickups and items and whatnot as Child Objects.​

    First, in hndl_persist's CREATE EVENT, we will iterate through each room in your game and prepare an array to hold data later on.
    Code:
    if (room != room_first) show_debug_message("Persistence Handler was not created in First Room!");;
    
    // Get All Rooms
    var rid = room_next(room_first);
    var rdx = 0;
    while (rid != -1)
    {
        room_list[rdx] = rid;
        rid = room_next(rid);
        rdx += 1;
    }
    room_count = rdx;
    
    // Initilize Array
    for (var rdx = 0; rdx < room_count; rdx += 1)
    {
        pickup_list[rdx] = noone;
    }
    Next, in hndl_persist's ROOM START EVENT, we will check which room we're in, catalog all the items we need to deal with if we haven't been in this room before, or delete the items we already picked up if we have.
    Code:
    // Check Which Room We're In
    rdex = 0;
    while (room_list[rdex] != room)
    {
        rdex += 1;
        if (rdex > room_count) exit;
    }
    
    // Catalog Things if This is the First Visit to This Room
    if (pickup_list[rdex] == noone)
    {
        var pdx = 0;
        var catalog = noone;
        with (prnt_pickup)
        {
            catalog[pdx] = id;
            pdx += 1;
        }
        pickup_list[rdex] = catalog;
    }
    else // Remove Items Not On the List
    {
        var catalog = pickup_list[rdex];
        var pi_count = array_length_1d(catalog);
        var remove;
        with (prnt_pickup)
        {
            remove = true;
            for (var pdx = 0; pdx < pi_count; pdx += 1)
            {
                if (id == catalog[pdx]) remove = false;
            }
            if (remove) instance_destroy();
        }
    }
    Finally, in hndl_persist's ROOM END EVENT, we will catalog all the items that have been picked up and update the pickup list.
    Code:
    var catalog = pickup_list[rdex];
    if (!is_array(catalog)) exit;
    
    var new_list = [noone];
    var ndx = 0;
    var pi_count = array_length_1d(catalog);
    for (var pdx = 0; pdx < pi_count; pdx += 1)
    {
        if (instance_exists(catalog[pdx]))
        {
            new_list[ndx] = catalog[pdx];
            ndx += 1;
        }
    }
    pickup_list[rdex] = new_list;
    In summary, you have an instance of a persistent handler object which catalogs all the pickupable items in a room the first time the player enters it, then erases from that list any items which the player has picked up during that room, when the player leaves the room. Upon re-entering a room, it makes every pickupable item check the list, and delete itself if it is not on the list.

    There are no truly universal solutions, but this is as close to a general solution as I could come up with. Hopefully it helps.
     
    Last edited: Dec 4, 2018
  2. royer14

    royer14 Member

    Joined:
    Dec 6, 2017
    Posts:
    19
    I have obtained error in this,
    var new_list = [noone];
    you can make an example of the use of your tutorial, but publish in gmz,
    to know how you use it
     
  3. Ephemeral

    Ephemeral Member

    Joined:
    Mar 1, 2017
    Posts:
    179
    That's not an error. That prevents an error.

    Leaving new_list undefined on that line of code will crash the game if you enter a room in which you have already collected all the pickups.

    setting new_list = noone; (non-array) on that line will cause a room in which you have already collected all the pickups to reset to having nothing picked up.
     
    sylvain_l likes this.
  4. sylvain_l

    sylvain_l Member

    Joined:
    Sep 18, 2016
    Posts:
    705
    a comment, that has more to do with your naming; calling an array a list, is for me confusing due to the fact that GMS2 support a datastructure called ds_list.
    My 2 cents, as you publishes it as a tuorial, I think not having that kind of ambiguity in the naming would be better.
     
  5. Leonem

    Leonem Member

    Joined:
    Oct 14, 2016
    Posts:
    1
    Hey there! I'm trying to use this for obvious reasons but I'm getting the same error as royer14.

    You may say that it prevents an error but in the end I can't compile the game anyway...
    Also, I'm using GMS 1.4, does this only works for GMS2? It doesn't look like it's using anything exclusive to GMS2 but that may be the problem.

    Still, thanks for a possible solution for pickups persistance.
    I just need to make it work without this error.
     
  6. FrostyCat

    FrostyCat Member

    Joined:
    Jun 26, 2016
    Posts:
    3,689
    The in-line syntax for arrays works only on GMS 2. In GMS 1.4 you need to imitate it with a script.
    Code:
    ///Array(...)
    var arr = array_create(argument_count);
    for (var i = 0; i < argument_count; i++) {
      arr[i] = argument[i];
    }
    return arr;
    
    Code:
    var new_list = Array(noone);
    
     
  7. Ephemeral

    Ephemeral Member

    Joined:
    Mar 1, 2017
    Posts:
    179
    Yup, this is GMS2 focused, sorry.

    This did actually lead to me catching a different error though, so thanks.
    The Remove Items Not On The List part had a variable assignment in the wrong place. Fixed now.
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice