GameMaker A General Solution to Item Persistence

E

Ephemeral

Guest
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 by a moderator:
R

royer14

Guest
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
 
E

Ephemeral

Guest
var new_list = [noone];
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

Member
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.
 
L

Leonem

Guest
Hey there! I'm trying to use this for obvious reasons but I'm getting the same error as royer14.

Error in Object hndl_persist, Event Room End, Action 1 at Line 4, Position 17: Unexpected symbol in expression.
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.
 

FrostyCat

Redemption Seeker
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.
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);
 
E

Ephemeral

Guest
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.
 
Top