What is the best way to implement round based gameplay?

Our game design has the following requirements:

  1. A match consists of a number of rounds, whether another round will be started will be determined at the end of the previous round.

  2. The level should be reset in between rounds, everything cleaned.

  3. Some data should persist across rounds, probably in GameState and PlayerState.

  4. Music should not be interrupted or reset when transitioning to a new round.

Is there a way of accomplishing all of the above?

Optimally I would like a way to keep GameState, PlayerState and playing music over level loads.

GameInstance can be used to persist data, but it seems pretty hacky to have to save the GameState and PlayerState to it manually and load it back at the beginning of another round, and I’m not sure it would keep music playing.

I’ve looked at level streaming as a solution and that seemed promising. I could create a “Master” level to be persistent, play music, gamestate and playerstate always loaded in that, and unload/load a sublevel when a new round needs to be started. The issue is that nearly every single Actor spawned during the game should be tied to the sublevel so that it’s cleared when a new round is started.

Another option is somehow utilising SeamlessTravel and GetSeamlessTravelActorList to maybe keep GameState and PlayerStates over level load, but I have absolutely no idea how that would work.

Also networking is no concern, local multiplayer only for now.

So far level streaming seems like the best choice if I can find a way to spawn actors inside the sublevel.

Any thoughts?

This is a bit old, but I ended up tagging each actor class which I want to be tied to the round only (like character, weapon, etc) and destroying each actor with that tag when the GameMode ends the round.

This is okay for me because I want some things to persist between rounds, but might not be so good if you want the entire level to reset.

If I wanted the entire level to reset, I would look at using level streaming and passing in FActorSpawnParameters to UWorld::SpawnActor, specifying the ULevel* OverrideLevel to tie round specific Actors to the round level. Maybe expose a new function node SpawnActorInRound to blueprint, though not sure how to get all the nice features of automatically setting up pins for the selected class like the native blueprint Spawn Actor does, but that’s another issue. That solution would also let you use different maps for each round.