Download

Create GameState when loading level

Is there a way to dynamically create the GameState that a level will use? I want to be able to make a decision like “Load this level, using this GameState for level-specific details”.

Right now I’m calling UGameplayStatics::OpenLevel, but I don’t see how to specifiy a GameState. I also don’t see any virtual functions to override in the GameMode that would let me specify a different GameState at creation-time.

So… is this possible…? Can I direct the engine to load a map with a specified GameMode and GameState (ie not baked into the asset)?

It’s possible, think about how in a typical multiplayer FPS (which the design of the Unreal engine is rooted in), you can have multiple maps (levels) and multiple modes (deathmatch, team deathmatch). You can play a single map with different game modes.

So when loading the level you need to be able to specify the game mode to use. The game mode will in turn indicate what game state to use.

Check out the answers in this post by Nostrildumbass. Looks like you need to pass a query string to the level to determine which game mode to use:

https://answers.unrealengine.com/questions/710228/change-gamemode-on-loading-a-new-level.html

I’ll just quote it here in case that link dies:

I know this is super old, but I wanted to comment with what worked for me.

In my HUD widget (I was working on a simple main menu that lets me choose game modes), I used Open Level to load the level and added this as a parameter in the options input:

?Game=/Game/Player/Blueprints/ThirdPersonGameMode.ThirdPersonGameMode_C

Don’t be fooled, the _C at the end will not be in the name of your game mode. If it is, you might need another _C at the end. This is awful design in my opinion, as nothing anywhere in my gamemode/files had an _C at the end.

Hope that helps :grinning:

Ah. Searching through UnrealEngine.cpp for .HasOption, I can see that an option for “Game=” is indeed checked by UEngine::LoadMap. I hadn’t realized how widespread the URL for the level was being used.

How about GameState? Any way to specify that? (I don’t see any other options besides “Listen”, “failed”, “closed”, “restart”, “listen”, “quiet”, “DemoRec”, and of course, “Game=”)

Any way to direct the GameMode creation to use a specific GameState?

I’m not sure what’s the issue here. If you can define a GameMode, and the GameState is defined in the GameMode, then what’s stopping you from doing just that? Setting the GameState in the GameMode. GameMode and GameState work hand in hand, you shouldn’t really want to use different game states for a game mode.

I don’t want to make an entire GameMode per different GameState.

I was hoping to use the GameState to store level-specific details that I can use when loading the level. Let’s say I have multiple spawn points in the level for instance. I’d like to have the GameInstance be able to say “We’re going from Level 2 to Level3, and we want SpawnPoint C”. So I’d fill out a GameState with SpawnPoint C, then load Level3 with it. When Level3 loaded, it would check its GameState to figure out which spawn point to use.

I just want to launch the level with a parameter, essentially.

I can cheat by storing the state in the GameInstance before making the UGameplayStatics::OpenLevel call, so that when AGameModeBase::StartPlay is called it can ask… but I was just wondering if there was a less hacky way…

Sounds like you don’t need the GameState at all. Your GameMode can directly access the GameInstance and return the desired SpawnPoint from the FindPlayerStart function.

Pretty sure the GameMode(Base) is responsible for spawning its GameState anyway. So there is nothing that prevents you from overriding this functionality and deciding on a different GameStateClass dynamically. Although I believe there is some check to verify that the GameState and GameMode classes are compatible. Maybe that was just to ensure a Base class isn’t mixed with a non-Base class.

Game modes and game states tend to have a 1:1 relationship. Think about it, if your game mode is capture the flag, your game state needs to keep track of where is the flag, is it being carried by someone, how much time until a dropped flag should be returned to its normal position, etc. If you change the mode to team deathmatch you don’t care about the above, but you need to track total kills per team to determine when the game ends. In a deathmatch game mode you want to track individual player scores to determine which single player is the winner. Each of these modes requires a different game state.

The game mode and game state are created when the level is created. So your idea of storing the pawn point in a game state and then loading a level won’t work.

Storing state in the game instance is not “cheating”. That’s actually the primary use for the game instance. The game instance is the only framework object that persists between levels (until programming subsystems were created, see 2). If you want to pass information to a new level, you have to do one of the following:

  1. Store info in game instance and read it from the game mode, game state, or level blueprint once the new level is loaded.
  2. Same as 1) but use a game instance subsystem (which was designed so that you don’t have to store anything in the game instance).
  3. Pass info via options string when opening the level, parse the options string in the game mode initialization.
  4. Something else that is actually hacky, e.g. save data to a file and then read the file within the new level.

To summarize, the current level (whether that logic is in the level blueprint, game mode or game state) determines what level to open next and what spawn point to use. Then you use one of the above options to send data to the next level and issue an OpenLevel call.