Advertisement

How GameMaker:Studio by YoYo Games stores instance data in memory

Started by January 08, 2020 09:28 AM
2 comments, last by Juxxec 5 years ago

Greetings All!

Recently I started working on a little project that aims to be a clone of GameMaker but for a console that is not supported by the said software out of the box. I am writing this project in C to improve my C skills. I usually code in C++.

In GameMaker you define objects. Each object gets assigned a unique ID starting from 0. Each defined object can then later be instantiated. Each instance gets assigned a unique identifier that keeps increasing with each new instance created. Each identifier is used only once. When the instance is destroyed, the identifier is not freed, i.e. it will NOT be assigned to another instance ever. (During the session, i.e. when the game is restarted, the instance counter also resets).

I am curious how they achieved this. How are they storing the instance data and instance identifiers internally so that they are constantly increasing and are not reused?

My goal is to have a way to store instances in my C game engine so that:
1. Time to create a new instance is O(1)
2. Time to remove an instance is O(1)
3, Lookup time for an instance is O(1). Optionally it can be O(nlogn).
4. Minimum memory is used to store data about the instances and handles.
5. Handles are consecutive. (If I skip this condition and the one below it, then I would have no trouble storing instance data using the data structure from the article below.)
6. Handles are not reused.

I found this article https://www.gamedev.net/articles/programming/general-and-gameplay-programming/game-engine-containers-handle-map-r4495/.

The data structure in the article does what I want, but the handles are not consecutive and are reused.

If I were writing this in C++ I would like it like below. Probably YoYo Games did the same thing.

typedef uint32_t Handle;

static uint32_t gs_InstanceIDCounter = 1000000;
static uint32_T gs_ObjectIndexCounter = 0;

class GM {
  std::map<uint32_t, Object *> m_objects;
  std::map<uint32_t, InstanceData *> m_instances; 
  
  // . . .
  
  uint32_t object_add(const std::string&amp;amp;amp; name)
  {
    uint32_t object_index = gs_ObjectIndexCounter ++;
    Object *obj = new Object(name, object_index);
  	m_objects[object_index] = obj;
  	return object_index;
  }
  
  uint32_t instance_create(uint32_t object, int x, int y)
  {
  	std::map<uint32_t, Object *>::iterator it = m_objects.find(object);
  	if (it != m_objects.end())
  	{
  	    uint32_t handle = gs_InstanceIDCounter ++;
  		InstanceData *instance = new InstanceData(object, handle, x, y);
  		m_instances[handle] = instance;
  		// Optional: Do some sort of grouping here
  		return handle;
  	} 
  	
  	return INVALID_ID;	// -1, i.e. MAX_INT
  }
  
  int object_get_depth(uint32_t object)
  {
  	std::map<uint32_t, Object *>::iterator it = m_instances.find(object);
  	if (it != m_instances.end())
  	{
  		return it->second->getDepth();
  	}
  	
  	return 0;
  }
};

// Example usage

static uint32_t gs_objPlayer;
static uint32_t gs_rmMain;

int main(int argc, char **argv)
{
  // TODO: Init engine
  
  gs_objPlayer = GM.object_add("objPlayer");
  gs_rmMain = GM.room_add("rmMain");
  
  uint32_t i = GM.instance_create(objPlayer, 10, 10);
  GM.room_add_instance(gs_rmMain, i);
  
  // TODO: Game Loop
  // TODO: Terminate engine
  return 0;
}

There is nothing AI here, just use a map/dict with incrementing counters.

Advertisement

@Alberth Yes. I know that there is no AI here. I just created the post without changing the topic. I forgot to change it and now I cannot change it anymore. In the end, this is the solution I used. I have a map with increasing counters.

This topic is closed to new replies.

Advertisement