Jump to content
  • Advertisement
Sign in to follow this  

Collectable Items, Persistence and ECS Architectures

This topic is 1229 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

My current project is a 2D platformer where the whole game is made up of a series of "rooms" (like a level of Shovel Knight, but without a world map to split it up).


My rooms are currently defined like this (pseudo code):

room = {
    tilemap = "tilemap.tmx",
    init = {
         // Perform the initialisation of anything not in the tilemap, e.g. enemies and collectable items
    // Other irrelevant stuff

Each time you enter a room, the init code is run and all of the enemies/collectables you killed/picked up/whatever are all back in their original place. This is exactly how I want this to work.


At the moment saving the game is simple, I just serialize out the state of the player, which room they are on and that's it.


The problem I'm having is that I'm now at the point where I want to add one-off collectables (like the morph ball in the Metroid games) or one-off enemies (e.g. an extra hard one that spawns only once), once you've collected/defeated them, they are gone - and when you enter/re-enter a room they shouldn't be re-spawned along with everything else.


I'm struggling to come up with a concept to handle this without some kind of global manager to look after everything which feels a bit wrong to me.


I'm working with an ECS architecture (as a purely educational exercise, I don't want to go into the merits of ECS vs. non-ECS), and I know that I shouldn't try and force everything into it, but it feels like this is a problem that I should be able to solve with it.


As a rough stab at it I was thinking of the following:

  • a Persistence component which stores a key
  • a PersistenceSystem which keeps track of these keys and their state
  • when a Persistence component is added to an entity, if the PersistenceSystem says the entity shouldn't exist anymore, destroy it (this is to handle the case when I reload a room)
  • when I save the game I serialize the keys and their states from the PersistenceSystem along with my other data

Is this is a sensible approach? Is this something that should sit outside of the ECS? How have other people tackled this problem?

Share this post

Link to post
Share on other sites

Is this is a sensible approach? Is this something that should sit outside of the ECS? [...]

IMHO your approach is fine because it allows the level designer to deal with the problem in a consistent way (assuming that s/he is familiar with ECS, of course ;) ) and it seems to fit smoothly into the technical point of view, too.


The only issue I personally would have with that particular solution is that the term "persistence" is broader. I.e. if I would hit a Persistence component I would understand it as a (perhaps even) collection of attributes that persist a room switch. It seems not clear why "persistence" 


[...]How have other people tackled this problem?

Well, I do not have this exact problem because in my engine the overall state is persistent anyway. So it includes the persistence but without the need of an explicit Persistence component. A spawn point that is never disabled and triggered on a "entering room" signal then will spawn each time, and one that is disabled does not.

Share this post

Link to post
Share on other sites

To me at least, it's very strange to persist state for non-existent entities, especially for the sole purpose of indicating that the entity shouldn't exist. It's also weird to create entities when you know beforehand that they're just going to be destroyed. Waste of cycles and resources aside, you run the risk of other systems detecting or interacting with these entities in that limbo state and modifying your gamestate in unexpected and difficult-to-debug ways.


haegarr hinted at the notion of spawn points, which is how I've solved this sort of problem in the past. Spawners (as I like to call them) are logic-only entities that exist solely to create other entities. In fact, they can be used to manage the entire lifetime. Instead of placing enemies and collectibles directly into the level, you place spawners that are configured to create the enemies are collectibles. When a room is entered, the spawners are created and they check for and load their persisted data. This data includes, but is not limited to, whether or not they've already spawned their entity (or entities), and whether or not it/they can spawn again (generally speaking, this could be a "max spawn count" parameter with a special "infinity" setting that means no limit). When you leave a room, the spawner state is persisted, and the spawner can chose to destroy its entities based on a flag or other setting (i.e. "auto-destroy if room left"). If the entity isn't destroyed, then it and its link to the spawner can also be persisted. Let's say that you have a boss that only appears once, but you don't want its health to reset when the player leaves the room. The "only appears once" is handled by the persistent spawner, the health is managed by persisting the boss state (as long as it's alive), and once the boss is killed, it no longer leaves a trace of data behind.


And of course, since spawners are just entities themselves, you can theoretically have spawners that create spawners, which then create entities (or perhaps more spawners!). The possibilities start to explode from there, but I'd still caution against too many levels of indirection; things can quickly get out of hand.

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!