Jump to content
  • Advertisement

Petar Titelski

  • Content Count

  • Joined

  • Last visited

Community Reputation

302 Neutral

About Petar Titelski

  • Rank

Personal Information

  • Interests

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Introduction Some games don't have levels. Open world games, flappy bird, ..and can't think of another example right now, but some games have levels. In this article, I will talk specifically about games where the character can move between levels, interact with objects around him and save the progress. Later he can load saved game and continue where he left off. Requirements First, let's write down the requirements that define our game: - the game has multiple levels, levels have static (inane) and moving (interactive) parts. - the player starts a new game at level 1 but can load the game at any subsequent level - the player moves between levels mostly forward, but he can go back to previous levels and he can jump between levels with some kind of teleport device. For example, on 5th level there is portal that takes him back to 2nd level, exactly the part of 2nd level that couldn't been accessed before. - a level has multiple entry and exit points. This means if you go from level 3 to level 4 you appear by the river at the cave entrance. But if you go from level 8 to level 4 you appear in front of traders house. So level 4 has two entry points. - the player can save position anywhere at any moment and load that saved position from anywhere in the game. if player exits game, unsaved progress is lost. This is how we define level: - it is the environment around the character with interactive pieces. - the player can change the state of interactive pieces, closed doors are left opened, aroused levers are pulled down, healthy living monsters are now not so well, coins are gone... - the player can not change static environment: background, props, ambient music, things that stay the same no matter what you do on that level (some games allow player to destroy background environment, leaving it completely changed - it's ok it just have to be taken into account as an interactive piece as well). In this article, I will discuss a simplified version of such game where level only has 10 colored balls and static background. Each level has a different background, but it can not be changed by the player so no need to save it. The player can move the balls around and paint them different colors so we want to be able to save these changes. We are using this simple scenario just to demonstrate the save/load ecosystem without adding the complexity of level itself. How do we code it? I'm going to use some pseudocode in this article that sometimes resembles JavaScript and json, but it's not the code you can copy-paste and run. First, we define Level class/object with these fields: LevelObj { //simple number id //image path background //position of balls and their color array levelBalls[{position,color}] //position of exits and where they lead to array levelExits[{position,idOfNextLevel,idOfNextLevelEntrance}] //position of player and facing upon level entrance array levelEntrances[{id,position,rotation}] } Let's say our game has 20 levels; we are going to create 20 objects that describe initial state of our levels (where the balls are, what is their color, where are level exits and entrances). In real life, we would store these in 20 different files, but for our very simple example we will use just one array with 20 elements: gameLevelsArray = [ //level 1 { id:1, levelBalls:[ { "position": {"x":2, "y":3}, "color": "red" }, { "position": {"x":4, "y":6}, "color": "red" }, { "position": {"x":9, "y":9}, "color": "green" }, ... ], levelExits:[ { "position": {"x":3, "y":3}, "nextLevelID": 2, "nextLevelEntrance": 1 }, ... ], levelEntrances:[ { "entranceID": 1, "position": {"x":1, "y":2}, "rotation": 90 }, ... ] }, //level 2 { id:2, levelBalls:[...], levelExits:[...], levelEntrances:[...] }, ... ]; Globals: - currentLevelPointer //initially null - gameState //initially GAME_STATE_MAINMENU; - arrayOfVisitedLevels //initially empty, but we push levels to this array as player visits them The player starts the game at Main Menu, and there he can choose "New Game" or "Load Game." We splash the loading screen and in the background load assets for either first level, or some saved level and position. Let me explain what arrayOfVisitedLevels is about. When the player starts the game for the first time, he appears on the first level. He can then move to other levels: second, third, fourth, all without saving the game. And if he decides to go back a level, we want him to see all the changes he made on those previous levels, although he didn't hit the Save button yet. So this is what arrayOfVisitedLevels does, it holds all visited levels (and their changes) in RAM, and when the player hits the Save button, we take all these levels and store them to permanent memory and empty the array. So when the player moves from level 4 to level 5 we have to ask these questions: - Is level 5 in arrayOfVisitedLevels? If yes it means player was just there - If not, is this level saved on disk? If yes we want to load it. - If not, the player never went to this level before, so we load its initial state from our gameLevelsArray. Below is what level loading could look like. This function is called when the player is just starting a game, or when changing levels while playing the game. //this function takes parameters //id - what level we are going to //entrance - what entrance we shall appear at function loadLevel(id, entrance) { gameState = GAME_STATE_LOADING; //if game hasn't just started, we need to cleanup previous level data if(currentLevelPointer != null) { //save current level - here we just push pointer to our level object to an array arrayOfVisitedLevels.push(currentLevelPointer); //clear current level - we want to render new one //for example this could delete objects from the 3d scene clearLevel(currentLevelPointer); //this function will have access to array of balls on that level and erase them, also the background } //if we are entering level that we already visited if(levelAlreadyVisited(id) //check arrayOfVisitedLevels to see if id is in there { //we get the level from array of visited levels //big idea here is that all the changes player made to this level are still in this object in memory nextLevel = getLevelFromArrayByID(arrayOfVisitedLevels,id); } else if(levelIsSaved(id) //check to see if level is saved { //we get the level from permanent storage nextLevel = getLevelFromArrayByID(savedLevels,id); } else { //get level from array of game levels - these are default unchanged levels //in real life we would load level from file here nextLevel = getLevelFromArrayByID(gameLevelsArray,id); } //now that we got the level we need, lets draw it loadLevelAssets(nextLevel); showLevel(nextLevel); //place player at given entrance player.position = entrance.position; player.facing = entrance.rotation; //remove the loading screen and start the game loop gameState = GAME_STATE_PLAY; } Game Save In this example, we don't address how the player moves around and changes the ball's color and position, but he does and he is satisfied with what he's done and now he wants to save it. Let's consider different saving scenarios: - The player starts a new game, moves through three levels and then press save. - He then fiddles some more on the third level and goes back to the second level, and presses save there again. - After that, he goes back to the third level, then fourth and fifth and finally saves again before exiting the game. We want to have 5 levels saved so that when the player loads the game he can go back and see those levels exactly as he left them. While the player was playing we decided to hold visited levels in a dynamic variable, in memory. When he presses save, it would be nice to store those visited levels in permanent storage and release dynamic objects from RAM. So first save is pretty straight forward - he hits the save - we save three levels, and release first and second level from memory (the third one is still being used). When the player wants to move to the second level again, we have to check first if we have that level in RAM, if not we have to check if that level was visited before, and if it is - we load it from saved file. So now player wants to hit save button second time. He is at the second level but has third and second changed a little, so we have to save that too. If he saves over the same game, we can overwrite those levels in saved file. If he saves new game slot, we have to keep previously saved data in case he wants to load that first saved game later, so we create new save file, but what do we put in second save file - just second and third level or all levels from the start? By the time he hits save button third time, we understood we need to go back one step and discuss save position some more. Save slots Some games have checkpoints for saving progress. On the level, there is some prop that player needs to approach to save the progress. If he dies, the game will automatically return him to last saved position. This is equivalent to one saving slot that is overwritten each time. Some games have multiple save slots, which allow you to name your saved game and then later overwrite it, or create a new one. When you think about it, saving each time to new game slot means last saved game should have all the data from previous saved games. We could make last saved game save only what is changed between a previously saved game and now. The differential approach means smaller save files, but we must traverse through all previously saved game files when we are looking for some older level. Alternatively, last saved game could have all the levels accessed (changed) from the game start. Now the fun starts. Imagine the player has 20 saved games, and more than half of the game finished. And then he decides to click 'New Game.' He (or his brother) wants to start the game from the beginning, and after 5 levels hits the save. Now whether you have differential or all-in-one approach, this saved game must be somehow separated from all others. And not just the "New Game," even if player load some older saved game and starts from there - he will take a new path from that point and branch into a parallel adventure. When he keeps saving games on this new path, the differential approach must be able to trace back previous saved games not just by date, but some smarter linked list mechanism. What I like to do here is create stories. Each time player starts a New Game he starts a new story. Each time he branches out from older saved game he creates another story. A story is a collection (linked list) of saved games that traces back to the beginning. Even if you make a game with one save slot (checkpoint use case) - you can use one story (in case you want to change it later). One save slot version has only one story. It can have numerous save nodes, but they are in a straight line. Load always loads the last one. Start from beginning starts a new story, and the previous one is deleted. In this post, I will only show the scenario with one story. You can then do multiple stories as your own exercise, haha. Here is example save function: saveLevel() { //here are some hints not related to our simple ball game: //save player stats in that moment: xp, hp, strength... //save player inventory, and also what he has equipped //these are level independent data, but needs to be saved each time //save player position and rotation //save what is in array of visited levels for (var i=0; i
  2. Petar Titelski

    Save/Load functinality for games with levels

      Thanks, fixed :)
  3. I wrote article about save/load game for games that have levels and let you go back and forth between levels. This basically summarizes my experiences while working on one such game, I thought it might be helpfull for someone in the future.   http://mysticpeanut.blogspot.rs/2016/11/how-to-implement-saveload-functionality.html
  • 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!