• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Persistent arrays of object instances without adding to layer

mcdreamer

Member
I'm coming at GML from a C++ background, and I want to have some global state to represent my player character, their inventory etc in an RPG game I've started. I really want to know whether it's possible to create an "array of structs / objects", similar to the following (C++):

Code:
struct Item

{
  std::string itemName = "Name";
  ItemEffect effect = ItemEffect::kSomething;
};

std::vector<Item> items = {
  Item { "Health", ItemEffect::kAddHealth },
  Item { "Weapon", ItemEffect::kIncreaseStrength }
};

for (const auto& item : items)
{
  draw_text(item.itemName);
}
It seems like the only way to get close to this in GML is to create an object type with some defined variable names, create instances of these on a layer, and then loop through these using "with" or similar. Whilst this is fine within a single room (using a layer of a depth over 16000 which isn't rendered, one per object type), I'm not sure how to do this for state which is global to the game. I wonder if I can use the persistent layer/instance property?

On top of this, are there any sorting algorithms outside of the built in alphabetical list sort? For example (C++ again):

Code:
std::sort(items.begin(), 
  items.end(), 
  [](const auto& item1, const auto item2) { return item1.effect < item2.effect; });
Apologies for all the C++! I'm hoping a lot of this will be rendered moot by the coming GML updates, but in the mean time I'd still like to know how this kind of thing has been done in GML over the years so I can continue with my game.
 

samspade

Member
I'm coming at GML from a C++ background, and I want to have some global state to represent my player character, their inventory etc in an RPG game I've started. I really want to know whether it's possible to create an "array of structs / objects", similar to the following (C++):

Code:
struct Item

{
  std::string itemName = "Name";
  ItemEffect effect = ItemEffect::kSomething;
};

std::vector<Item> items = {
  Item { "Health", ItemEffect::kAddHealth },
  Item { "Weapon", ItemEffect::kIncreaseStrength }
};

for (const auto& item : items)
{
  draw_text(item.itemName);
}
It seems like the only way to get close to this in GML is to create an object type with some defined variable names, create instances of these on a layer, and then loop through these using "with" or similar. Whilst this is fine within a single room (using a layer of a depth over 16000 which isn't rendered, one per object type), I'm not sure how to do this for state which is global to the game. I wonder if I can use the persistent layer/instance property?

On top of this, are there any sorting algorithms outside of the built in alphabetical list sort? For example (C++ again):

Code:
std::sort(items.begin(),
  items.end(),
  [](const auto& item1, const auto item2) { return item1.effect < item2.effect; });
Apologies for all the C++! I'm hoping a lot of this will be rendered moot by the coming GML updates, but in the mean time I'd still like to know how this kind of thing has been done in GML over the years so I can continue with my game.
I only have a little understanding of C and don't know any C++, so there are probably better people to answer this but, in general you do have to create an object to have anything exist. However, stuff like this in GameMaker is normally dealt with using arrays or lists and maps. You can then use as many or as few objects as you want.

For example, you would create a single object (e.g. obj_inventory) and you would make that object persistent, so that it would not be destroyed during room changes, and then you would create the inventory as a ds_list, and each item would be a ds_map that you add to the list. To draw everything you would then loop through the list.

Lists have a sort function, but it is somewhat limited if you want it to work on nested elements. You'd probably have to code your own. There are merge and bubble sort algorithms out there for gml and either would work for a normal sized inventory.
 

NightFrost

Member
Well my answer might change somewhat when 2.3 update hits with a bunch of new features, but... Firstly, it would depend somewhat how complex the item definitions need to be and how inventory & inventory management is going to be handled. At base level, I would define the items as some data arrangement. Typically with the tools available on GML right now, I would favor some sort of enumerator-indexed thing. One enumerator would define all the items, another all the qualities. Together they form the axes of a 2d data structure that defines all the items. An inventory, then, would be a simple 1d array where each cell contains some base data, like an item enumerator and the number of items held. I've done simpler arrangements too. One where there were just a few items (four or five I think) their qualities were defined in a function, as that was all that was needed. It just checked if used item was A, then do X, if it was B, then do Y, and so on.

(Also, I don't know any C++ so I don't really know what that code does, though I can guess.)
 

Binsk

Member
Expanding on what NightFrost said, until they actually add support for structs and the like (which I believe something similar is in the roadmap) you can use enum / array pairs. Something like this:
Code:
// Define structure layout:
enum ITEM{
   name,
   effect
}

// Create array in layout:
global.some_item = ["Banana", increase_health_scr];

// To get data from array:
show_message(global.some_item[ITEM.name]);
script_execute(global.some_item[ITEM.effect]);
You also have GameMaker's data structures, such as maps, which are global in scope (as long as you have a variable always pointing to the reference number). For example:
Code:
// Using String Labels:
global.some_item = ds_map_create();
global.some_item[? "name"] = "Banana";
global.some_item[? "effect"] = increase_health_scr;

// Using Enum Labels:
global.some_item = ds_map_create();
global.some_item[? ITEM.name] = "Banana";
global.some_item[? ITEM.effect] = increase_health_scr;
GameMaker datatypes and structures are pretty basic. You have to do a lot of the heavylifting if you want something special, that goes for your sort as well.
 

mcdreamer

Member
Thanks for all the responses! Sounds like maps indexed by enums will be the way to go for what I'd like. I suspect that I will have multiple properties per item type, but I guess I can do all of this with nested maps. And it seems like persistence will be handled in the way I want by making use of global objects.

As for the sorting, I guess in many cases I'll just want to show things alphabetically, so I can probably do something using the existing list sort functions and then use these strings as keys / lookup functions into the unsorted data.
 
Top