Download

How do I keep previous changes to a level upon loading?

Hello, currently I am working on a Turn Based RPG game and have run into a problem when transitioning from the battle screen back to the exploration scene.

It works like so:

You run into an actor (or vice versa) on the exploration level, and then it will load you into another level where the game mode has changed and you are now fighting.

After you defeat everyone on that map, you will load back into the exploration level. However, this is where my problem starts. I want the exploration map to be updated with your location where the fight occurred and for the monster you were fighting to be gone. This doesn’t happen though, because everytime I load the exploration map, it returns to it’s initial state, with you at the player start, and the monster back where it started as well.

I’ve looked at a couple different options, like level streaming, sub-levels, and Save/Load Game states, but all of these don’t seem to specifically solve the problem.

It seems like a save/load state would work for this but another way would be to save the last player position and on begin play in the level blueprint, move the player or spawn point if the player hasn’t spawned yet. I haven’t looked into saving yet for my game so sorry for no real specifics.

I would probably look into GameInstance. Now, don’t take my word for it, but since GameInstance saves information between levels, I would imagine that if you had something in there saving the location of the player PRIOR to entering Combat Mode, and then calling up that location upon EXITING combat mode back into exploration mode, you should be good.

I was running into this same problem with a project I was working on. Pokemon sort of style turn based combat levels with open world main level. I tried ******** around with sub levels and things but it all ended up being too much of a hassle. So what I did was actually setup a new area on the map which when I run into an enemy changes me to be controlling a different player which is in my “fight room” along with spawning a replica of whatever enemy i ran into. I created a “global pause” event so that all the behaviour trees and everything else pause whatever they were doing until the fight is over, then when the fight is finished I unpause and everything goes back to normal.

You can still stream in a sub level for the actual combat area but I didn’t bother at the moment, i just tweaked some variables based on where the user was and the terrain etc to make it feel different, but if your combat areas are going to be different then just load in a sub level to a specific combat area, away from the main part of the map and unload it when you are done.

This currently seems to be the best method I have discovered for it, annoyingly on everything that does some kind of action you will need to check for this pause event, blueprint interface is probably the way to go.

The saving and loading node would work perfect for this.
You create a custom event . Eg onBeginBattle inside this event you create a saved game node , get the players position then save it. Call this custom event before you stream or load you’re battle level.

Then you do the opposite Create a custom event eg onBattleFinished. Inside this event you create a does save game exist node. Add a branch. If save game exists load the players transform. If it doesn’t spawn the player as normal

In you’re level blueprint call this load function/event either using the init event or on begin play so that it moves the player before the level actually starts . I’m not at my computer right now but this site shows how to do it although in this example he is saving transforms as well as other data

Saving just the players position is often not enough, you need to be saving the position of enemies, items, events etc etc.

For positions of enemies you just do the same as saving the player transform except you use an array of transforms.

And actually thinking about it ,saving and loading is not necessary. He could just save all the data inside variables inside the game instance which will persist through level changes anyway

Yep it definitely can be done this way, just often is not a great way to do it. Since loading levels is a lot more time consuming and intensive than just moving the camera. It really depends on the situation as to what the appropriate solution is.

Not really most saving and loading is done in the init or end phase unless you’re implementing some kind of auto save system that saves every few mins an even then it’s not that big of an impact.

so actually you’re way of doing things is a lot more intensive , and is more of a bodge job (quick fix) than actual good coding.

You’re not ‘just moving the camera’ you’re creating multiple copies of actors, and spawning them in , pausing everything else, probably having to write different logic to make the battle sequences work etc then reversing everything once the game is over.

Now in you’re situation this is fine as by the sounds of it you’re only having one battle event happening at one time but if you we’re to multiply what you are doing several times it would greatly impact the system and bog things down.

the thing with programming is most of the time there are several ways to accomplish the same thing the hard part is knowing when to do what.

TLDR just because it works and is easier , doesn’t mean it’s right.

I wasn’t talking about the saving/loading data being the intensive part. It’s the unloading and loading of the levels that is the time consuming part. If you unload the entire main level just to jump into a small combat scene and then try and load it again at the end then its going to take a long time. This gives you the problem of a lot of games from 5-10 years ago where you would go from an open world into a building and it takes 30 seconds to transition back out to the open world.

For mine its a 1v1 turn based combat, so my actor and pawn is always loaded, i simply adjust the variables on it, which are cast from the monster I collide with straight over. Nothing is spawned in new or having to be cleaned up, just a couple of variables switched out from a dataset. I could save these into the game instance and load up the new level to fight and then load the main level again but this would involve a lot of unnecessary loading screens compared to a simple matinee fade sequence and changing the camera location.

Like I said, I don’t know the OP’s situation and if thats the better solution or not, it’s just 1 which works for me and also several other people on here who have been doing that kind of combat.

I encountered a similar issue when building our turn-based RPG. How do you transition between battle maps and exploration maps in an efficient and timely manner?

The obvious solution is to save out the exploration stats prior to loading the battle map. This includes stuff like the player’s position, enemy and item locations, any persistent stats, etc. Save all this info out to a file, and reload it once you return to exploration mode. However, the problem with this that it’s extremely time consuming. As your levels get larger and gain more detail, the load time between them will become unbearable. No one is going to want to initiate a battle, take 20+ seconds to load the battle map, and then take another 20+ seconds to load the exploration map when they’re done. If your level is large and detailed, longer wait times. It’s just not good design.

Instead, we decided to go with a more efficient route. In our game, there is no discrepancy between a “battle map” and an “exploration map”… all of the logic is contained within in the same map. This allows us to only load the map once, at the beginning. It means we’re never forced to save information out to a file. It also means that for every level/map we build for the game, each map will use the exact same default classes (Game Mode, Game State, Player Controller, etc). It also means that there is zero transition time between exploration and battle. When you run into an enemy, you’re immediately into a battle. We actually need to program an artificial transition to allow for a delay; the immediate nature of the transition is too jarring for most players.

This design means you have to do some things differently… for example, if you have two separate maps (an exploration map and a battle map), you would then make the exploration map into a “master” map, while the battle map becomes a streaming level of the master map. You’ll place the actors of your battle map in an inconspicuous location inside your master map (for example, beneath the world where the player cannot see or reach it). Once you enter a battle, you’ll simply move the camera to the appropriate location so that your player now sees the battle map. You’ll also pause the movement and controls of the exploration player (so as to “save” his location on the exploration map) and then you’ll force the player’s controls to only work for battle stuff (like menu operation). When the battle ends, return the camera perspective to the exploration character, regain movement control, and go about your business as normal.

For us, we actually ditched the notion of creating entirely new battle maps… instead opting to hold battles directly on the exploration map. You get in a fight, the exploration-specific assets are hidden, and the battle-specific ones are unhidden (or moved to the appropriate location from a hidden location).

Do you just have all your logic for both exploration and combat in the same classes (player controller, game state etc…) or do you change them somehow when you start combat? I’m on the fence about having both logic in the same class. It could make it pretty bloated and hard to debug / maintain, thoughts?

Either use the built-in Save Game mechanic, or make the “combat level” actually be a smaller part of the main level, so you don’t need to re-load levels.
Although presumably you need to implement Save Game anyway, so that seems like the easiest way to go :slight_smile:

Unfortunately for this discussion, my game has evolved from a turn-based structure that requires this design. It’s a third-person realtime action game now.

Either way, I’d still do things the same way as what I posted last year. Either create battle maps as streaming levels inside your exploration maps, or make the battle “area” somewhere hidden within the exploration map (such as a battle area hidden beneath the floor of your exploration map. You can then possess a new camera, spawn battle actors and widgets, etc whenever you get into a battle.

Yes, in my imagining of this scenario, all of your logic would indeed be maintained within the same classes, as they’re not easily swapped out without fully unloading the persistent level (some may not be possible at all, like the game mode??). I’ve managed to work around this successfully by using proper “states” (i.e., inside the PlayerController, player controls work one way in exploration mode, but another way while in battle mode), which are nothing more than an enum variable with some switching and conditional checks as necessary. Yes, some code files can become complicated and bloated, but you can avoid some of this by refactoring your code where it makes sense to do so. Maybe put that group of functions into a reusable actor component. Maybe stuff those other functions into a common library file. How this gets organized is up to you and your project.