Tile Scrolling Platformer | 6. Level Codes

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello fellow scratchers i'm griff patch and welcome back to part six of our series creating a tile scrolling platformer in scratch and wow are we making some amazing progress now that we have a level editor we are going to need a way to save and then reload multiple levels or even share level codes with friends now if like me you've had a lot of fun since the last episode creating a level that you don't want to lose then let me show you how to back it up before we continue with the tutorial make the tile grid list visible and then right click the list on the stage and click export make sure to choose a safe location on your computer to save the file to and click to confirm now if at any time you accidentally mess up your tile grid list just right click the list again and choose the import option find file and confirm to import it few it's back better safe than sorry backing things up should be a very important part of your coding process believe me okay to save a level in scratch requires us to be able to create a level code from our level you will no doubt have seen level codes used in scratch games already often looking like a series of numbers and letters the main point is that the value can be assigned to a single variable or copy and paste it to be shared with friends the process of changing the data in our tile grid list to a level code is called encoding and that is what we'll be covering in this episode let's create a new sprite for this purpose naming it level store and within this make a new list for this sprite only named level store so we need a way that we can take this huge level list and convert it into a single text value storing it as an item in this new level store list row 1 being level 1 row 2 for level 2 etc scratch has one very simple built-in way of encoding lists we can try it right away using an add to level store and then drop in the tile grid reporter yep it's almost too simple click the script to run it and watch what happens to the level store list when not in full screen mode we can select values in the list and copy it using ctrl c let me paste it into a text editor so that we can see it in more detail so this is just one long long series of numbers each separated by a single space letter in computer speak this would be referred to as a space delimited list the delimiter being the character that is separating all the values in the list this episode would be over much quicker if we were simply content with this but really this does not live up to the requirements of a good save code firstly it's just far too long and secondly using spaces as a delimiter make it hard to select with the mouse and leads to errors when people try to copy and paste it so what can we do we'll just have to create a list delimiter of our very own make a variable named encoded for this sprite only we'll use this to build up our encoded text value next make a new block named write value with a text input value a label of delimiter and an input letter all we're going to do is set encoded to the join of encoded and the join of value and letter lots of joining right but this simply appends the value and the letter variables onto the end of the encoded variable let's use this to begin creating our level encoder make a new custom block save level level hash as an input and set encoded to the empty value create a new variable tile index for this sprite only and set it to 1 the first tile in the tile grid now we'll repeat over each tile using a repeat grid height and within that a repeat grid width within these loops we'll write value item text index of tile grid with a delimiter of the underscore and then change tile index by 1. this loop will now write out each item in the tile grid into the encoded variable separating each value with an underscore delimiter below the repeat loops we delete all of level store and once more add encoded to level store recording the results of all this work now we can test this by clicking on the save level custom block i'll copy the results from the level store list into my text editor and we can compare the results look at that it's not really any different in size but all the spaces are gone and because of that if i double click on the text it all selects as one happy save code great work but this level code is really long is there perhaps any way to make it smaller i mean a lot smaller luckily the answer is yes there is you may notice when looking at the save level list that the same tile costume numbers are repeated over and over again in long runs well how about instead of recording all these duplicated values we simply record the first number and then the length of the tile one of that type this technique is aptly named run length encoding and is what we'll do next to achieve this we will need to make two new variables the first named length for this sprite only which we'll use to count up the number of tiles we find in the current run length and the second named tile for this sprite only that tells us which tile costume we are counting for before our repeat loop we set the tile to the current tile in the tile grid and we set the length of the current run to zero now we need an if else within the inner repeat being careful to keep the change tile index under the else now we compare the current tile to the next tile on the level that is item tile index of tile grid if it matches then we add one to the length variable counting it as one more tile of the same type but if it's not the same then we need to make a record of the previous run of tiles using our right value tile delimiter of underscore and another for the run length right value length delimiter of an underscore with that done we make a record of the new tile costume that we have just encountered by setting tile to the same item tile index of tile grid and then setting length to one it's a one this time because we need to count the new tile we just found and then the loop continues and repeats around as before moving on to the next tile but now only recording values when the tiles change so this is nearly done we just have one special case to cater for and that is the last run length never gets recorded by this loop to address this we just duplicate the two right valued tile and length scripts after the loops are done now let us test this again by clicking on the save level script let me paste the new save code into the text editor to see the difference and look at that how much smaller it has already become okay perhaps we can do even better you bet we can look at this level in which direction would you say the longest runs are found vertically or horizontally yep without a doubt the horizontals have it it's a shame then we decided to store our level column first rather than row first but not to worry we just need to transform the level as we encode it instead of adding 1 to the tile index to move up a tile each time we add grid height this will move as a column to the right then when we reach the end of the level we move up one tile by changing tile index by one and move back to the first column by subtracting grid width multiplied by grid height sorted let's test it again do you think it will have any effect at all copy and paste and oh boy yes it did we cut the size by another third but wait there's more we can do yet looking at the save code by far the most common character is the underscores now obviously we need something to act as a delimiter so that we know where each number starts and ends if we ensure each run length is no longer than 26 tiles long then we can encode the run length as a letter and use it as the delimiter for the tile first off how do we convert the number 1 through 26 to the letters a through z for that we need to create a new list named a to z for this sprite only add a row to it and enter the letters a b c all the way to z there should be 26 rows in total remember to click out of the last row to ensure it saves now if we were to want the third letter of the alphabet we just use item 3 of a to z simple or the 26th letter yep it said great to work the other way if we use an item hash of letter c in a to z then scratch reports three as expected or a one no problem we can convert letters to numbers and numbers to letters okay so this is where the magic happens look at our pair of right value blocks here we are going to simplify this to be just a single right value block keep the value as tile but switch the delimiter to be item length of a to z this will convert the length number to a single letter and use it as the delimiter of this tile we can now delete the second right value and remember to duplicate this change to replace the final pair of right values too we just need to ensure that our run lengths never exceed 26 in length so wrap the tile comparator with an and and check that length is less than 26 great we'll test this again to see how this has affected our save code size copy and paste oh yes all these underscores are gone cutting the size by another third this is getting really tight now in fact i only have one more targeted optimization to squeeze in we can observe that the most common tile on our level is tile number two because it's the empty tile so we can replace all tile twos with the empty string saving us one character per empty tile so before we write out the tile here add an if and check whether tile equals two if it does quickly set it back to the empty string and here goes the final test of our comparison copy and paste and there what an amazing reduction we have achieved cutting a final fifth off the size sweet we just need to add some header data to the save code to aid us in decoding it correctly after we set encoded to the empty value up here we add a write value 1 with a delimiter of underscore this is our save code version number next write out the grid width and then the grid height both with underscored limiters without this we wouldn't know the dimensions of the level lastly we want to stop assuming we are saving level 1 each time and support saving of any level number remove the delete all of the level store block then surround the add to level store block with a repeat block for level hash subtract length of level store we are using this to just pad out any missing level those to make sure the add item is just adding empty values to the level store next under the repeat block we introduce a replace item level hash of level store with encoded this is quite neat the repeat loop makes sure the list is long enough to allow us to add our level and then we can safely use replace item to put the level into the list let's try it use a save level block with a level of 10. click it and see what is stored in our level store all the rows before level 10 get padded out with blank values and the new level is sitting at row 10 and if we save as level 5 row 5 gets filled out leaving all the other rows just as they were as you'd expect saving is level one just replaces the previous level one row two with the save scripts complete let's delete all from the level store list and then use the save level script with a level number of one again to just populate the first level run that by clicking it and we're all set to go now we can focus on scripting a level decoder that takes our wonderfully compact level code and inflates it back into a fully playable level we start with the prerequisite make block naming it load level with a text input of level hash and run without screen refresh set encoded to item level hash of level store this gives us the encoded level ready for decoding create a new variable named read index for this sprite only and set it to 1. this holds the position in the encoded string that we are currently decoding starting with the first letter we'll make a new block named read letter and make a new variable named letter set letter right away to letter read index of encoded and immediately change read index by one this custom block is useful setting the letter variable to the next letter from our encoded level each time it's used we can see this working by using the load level block for level one click it next we click on the read letter script to find letter set to the first letter of the encoded script even better each subsequent click takes us to the following letter one after the other this will be very useful indeed okay now we expand the concept to reading whole values we make another block named read value and a variable named value for this sprite only setting it to the empty value ready to be built up use the read letter block to get the first letter followed by a repeat until block repeating until either letter is greater than nine or letter is the empty value this will loop around until we hit a delimiter that is any character that is not a number within the repeat set value to the join of value and letter this will build up value a digit at a time until the end of the number is found we should test this works too click the load level one block to reset the decoder and ensure that both the letter and value reporters are showing on the stage now click on the read value script value is reported as 1 and letter as underscore that's good that's the level save version and its delimiter click the read value script again and we get 100 and underscore that's the level width again for level height of 40 now one more time to get the first tile of the level and the letter shows a special a to z value that is the run length of the tile we could keep clicking now to read off the tiles one at a time right armed with this awesome script let's put together our full decoder locate the define load level script and we'll continue where we left off start by reading a value then we'll check whether it's not one if it isn't then we'll just stop right now this ensures we only allow decoding of level code version 1. next delete all of tile grid read the next value from this we can set grid width to value and read another value and set grid height to value so using a repeat loop we'll quickly recreate a blank version of the level grid list of the correct size by multiplying grid width by grid height and add the blank value to tilegrid we create the levelgrid list in advance of decoding to allow us to handle the transposed row first ordering if we click the load level 1 block now we should see all the level vanish and be replaced by empty values oh gosh goodbye beautiful level i hope we see you again soon now set tile index to 1 followed by a repeat until read index is greater than length of encoded that will only stop when the entire encoded level code has been processed okay so read the next value this is the first tile costume number in the level we must compare it to the empty value to handle that special case when it should really be tile costume 2. so if it is empty then set tile back to 2. we'll need a repeat block to create the run of tiles but what goes in the right side letter holds the encoded run length which was also doubling as the delimiter we can just use the item hash of letter in a to z block to decode it excellent now within the repeat we can then replace the tile at tile index of the tile grid with the tile costume value we just need to then move on to the next tile before repeating around but remembering we want to move across by a column not up a row so we change tile index by grid height next check if tile index is greater than grid width multiplied by grid height this happens when we've moved across a full row of columns so we then need to move up one row and also back to the first column simply change tile index by 1 subtract grid width multiplied by grid height so once we've completed one run length of tiles the outer repeat loops around and if there are more tiles to be read then it reads the next one and off it goes again in the end all the encoded data will be processed and then well job done did you follow all of that i hope so because no time to lose we should put it to the test and now the moment of truth do all these scripts work together click the load level one block and wham the level grid suddenly looks very full once more a very good sign indeed but of course the ultimate test is running the project to confirm that the level is loaded and playable click the green flag to run the project and if it all appears to be working then give a huge sigh of relief wow what an achievement well done at this stage we should hook things up so that the save and load scripts can be made use of in our game to begin with add a when i receive level hyphen save make a new variable named level hash for all sprites this will keep track of the current level number we are playing or editing and simply defer to the save level level hash block we'll also do the same with a new when i receive level load script and drop in a load level level hash block okay time for a change of scene click with me into the editor sprite we are going to activate the save and load scripts from there within the when i receive generate level script set level to 1 and then delete all of tile grid and finally broadcast and wait level load this should reset our game to level one each time it is run we can test this works by running the project we enter level editor by pressing the zero key and draw some random blocks around the level nothing unusual here but if we hit the green flag oh the changes we have made have vanished and why because the saved level has been reloaded without our recent changes that proves the level loading is working what we need to do next is hook into our level saving code too scroll to the when zero key pressed script we want to save when the user toggles out of the editor so add a broadcast and wait level save here just before editor is set to zero now we have to be a little careful the saving of the level must not run while the main mario game loop is still in progress so broadcast and wait for a new event named level stop putting it before the level load script we'll script the receiver for this event soon enough but before that we'll complete this script with a hide variable level hash and a broadcast not a wait this time to a new event level start game loop we don't wait because waiting for the game loop to finish would never end we need a similar set of scripts for loading the level when you enter the level editor below start with a broadcast to level stop and then set the editor to 1 before broadcasting and waiting for level load oh and we shouldn't forget to show the level hash variable for which we are editing very useful and finally broadcast level start game loop again without a wait now we can click into the mario sprite and find the define game loop custom block just move it down a little and we'll pop in a when i receive level stop hat block all we want to do in here is stop other scripts in this sprite that means that the game loop below will stop running before our level is saved then we need a when i receive level start hat and it simply relaunches the game loop now we have a way of stopping and starting the main game loop really easily super we can test again now so hit the green flag pressing the zero key to enter the level editor we can draw a few tiles and then press the zero key again to test the level and now the moment of truth click the green flag again to reload the level and this time the level has not been lost success now i can't help but feel we are kind of back to where we were at the beginning of this tutorial episode a single level that saves with the project hmm quite right so why all this effort well we are about to reap all those benefits as we add in a way to switch levels click into the editor sprite and we'll introduce a when l key pressed l for level selector then if editor is less than 1 stop this script as we only want the level selection key to work within the level editor now we ask the user which level to edit by using an ask block joining the words enter level number open bracket current with another join block with the level hash variable on the left and a close bracket on the right we'll confirm they entered a reasonable value with an if and check the round of answer is less than one and if it is then we stop this script so to change level the first thing we do is save the current level so broadcast and weight level stop followed by a broadcast and weight level save next set level hash to the round of answer now with the level variable pointing to a new level number we broadcast and wait level load and finally just a broadcast to level start no wait here it should be noted that if the level you switch to has not yet been created then it will save a copy of the existing level as the new level this can be quite useful let's see it in action run the project i can enter the level editor with a zero key noticing that i am on level one now i press the l key and i'm prompted to enter a level number i can enter two and confirm the level number has switched to say level two however as this is a new level i ended up with a copy of the previous level which i can then edit now pressing l again i can switch back to level one and look at that it's the original level and l again to jump back to level two yep it's still there yay this is working great time is running out for this episode but i really don't want to leave you without the ability to set a level size or simply clear a level we can duplicate the level changing script removing all the broadcasts and we'll trigger off the r key for reset level change the question to reset level are you sure and check if the answer is not equal to y if not then stop this script now we ask another question the join of enter level width current with the join of grid width and a close bracket if the answer is not empty then we set grid width to the answer duplicate the question and its if condition and change all the widths for heights we can now use the generate level block to create the blank level of the new size however now we have a problem if we change grid height all the tile clones in our level will be misindexed we need to sort this so add a broadcast and wait for the new event level done loading and tack on a broadcast level start game loop yep no waiting on that oh yes we mustn't forget to add a broadcast and wait to level stop just before the ask for level width otherwise our main game loop could go crazy when the level size is changed now scroll over to the define generate level script and we'll move the set grid width and height blocks out of here and up to before the block is used here otherwise generating the new level will forget the size we just entered we're nearly there click back into the level store sprite and find the when i receive level load hat block we need a broadcast and wait to level done loading after the level is loaded in case the level size has changed here too and this is it the last script of the episode click into the tile sprite and find a little space add a when i receive level done loading we are going to make sure that each tile has a valid tile index for the updated grid height this works just like our get tile at xy script but start by checking if tile index is greater than the empty value now if it is then set tile index to 1 plus the floor of tile y divided by 32 then we change tile index by grid height multiplied by the floor of tile x divided by 32 and guys that is it the last script is done and we can run the project to try this new feature out click the green flag and press the zero key to enter the level editor then press l and switch to level 2. finally press the r key to request a level reset then we enter y to confirm the reset next enter a new level width or we can press enter to keep it the same however i'll create a tiny level of width 20. then for the height i'll enter 15. and pow the level is reset and if we move around look how tiny it is so that definitely worked success we have made it to the end of this episode oh my gosh what a trip i can't believe i even tried to fit this all in it has been a lot of work but it will be well worth it for the flexibility it gives us moving forward and what should we look at next i'm thinking implementing the coin pickups for starters but feel free to drop me your suggestions under the video as always if you've enjoyed this tutorial please smash the like button and don't forget to subscribe to this channel to avoid missing my next exciting video but until then thanks for watching and scratch on guys [Music]
Info
Channel: griffpatch
Views: 76,755
Rating: undefined out of 5
Keywords: Scratch, Scratch3, Scrolling, Tile, Map, Coding, Tutorial, Tilemap, Platformer, Griffpatch, programming, animation, Mario, encode, decode, save, load
Id: IRtlrBnX-dY
Channel Id: undefined
Length: 30min 44sec (1844 seconds)
Published: Mon Mar 29 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.