Custom Tilemap in Unity with Saving and Loading (Level Editor)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video we're going to take our grid system and create a very nice town map it will support adding simple tiles to our grid and define how they should be displayed in the end we're going to add saving and loading to a file so you could easily make a level editor for your game let's begin [Music] okay so in this video we're continuing from our grid system and applying a town map onto it we're going to have our next texture atlas and click to place very Styles but first of all let's talk about the built-in Talman unity already comes with a very nice town map that is extremely easy to use and supports a lot of nice features for a lot of simple scenarios the default Unity town map won't do just fun so if all you want is a simple sprite in a grid like structure then use that however if you have a more complex design or simply want to learn how it actually works then keep watching as I said we're going to be using the grid system we created in a previous video so check the link in the description if you haven't seen it already we added support for generics so implementing a town map is actually very easy alright so here let's begin by making our town map class so a new script call it our town map now in here let's get rid of monobehaviour since this will be a simple class let's make a constructor and in here let's just create a great instance of intz okay so here it is we just have our tongue lip we receive on our parameters then we create our grid using those parameters and over here at the end we have our nice simple func which returns the default on which in this case and let's just put it at zero okay so now we need a script to test this so in here let's make our testing script let's make a testing game object okay now in here all we're going to do is go into our start and we just create a town all right that's it let's test yep there's our nice stirring grid all right now let's make our grid work with a custom object rather than just int now previously we already made our grid work with generics so making it work with a custom object is actually very easy to do so in here let's define our class for the object that will be in our grid so we're going to call this the town map object now inside let's define an anoon here we have an enum for our town map sprite and we have none and ground and now let's also make the basic functions like we did in the previous video all right so just like that in here we have to find our next object that won't be in sin she ate it in every single one of our great positions so we have Deconstructor where we receive the bread the X and the y and then we have a function to set the town map sprite this also calls the trigger on object change functions so that the visuals can also update so all we need to do in order to make our grid work with this object is simply change in here so the grid is now of type town map object we make that in there make this type in here and in here we will turn a new town map object passing the grid DX and dy all right just like that now let's go into our testing code and in here let's make a update and we're going to test for input get mouse button down so when we press the on left mouse button let's modify our grid so in here I'm getting the mouse room position from a function in the utilities as long as you can download the utilities for free from in Tacoma comm here is the function in case you want to do it yourself and as you can see it just takes the camera and there's a screen to work point on the mouse screen position so using that now we want to go into the town map and modify the grid under this warm position so let's do that appear first we need a reference and now on the town map we need a function to be able to set a grid position all right so here is the function we simply go into our other line Grint we get the object on this position and if it is not now then we simply call the set our Maps write function which is down here so here I'm cussing we simply use that and when we click let's set it to grunt all right that should do it let's test okay so here we are and you can already see the grid working with our custom object type since instead of 0 it is now saying none it's say none because that's a default in home value now when I click there we go I change that one from now on into ground so right now I can click to modify the underlying and on that alright awesome ok so with this working now let's make our visual now previously we made our grid work with a heatmap visual so if you remember we had a nice object with a minimum and maximum of 100 so the underlying value was an INT so we can use this as our base in order to create our town map visual so I simply duplicate the script call it a town that little okay so here again the script is very simple we just have our mesh and we have a mesh filter attached to this object then we have a function which receives a grid we are subscribing to the on grid value changed and when that event is fired we update our visual we update our visual by creating a mesh and setting it correctly if you want to know how this was created from scratch then check the link in the description so using this as our base and let's go up here instead of working with a heatmap word object we're going to work with a tile map town map object so this is the base for our grits and let's change all these ok and now in here when we update we grab the current grid object and now here let's just for the town map sprite so we go to the grid object and let's have a function to return the town map sprite okay here it is now we use it in here and then let's set our UV based on what we have on our thumb up right so in here we define the vector 2 for UV and if detail Maps price equals none then let's display a black solid Quan so we go into the UV and we set it to vector to zero and if not then let's display a green square so let's set it to vector 2.1 okay so that's pretty much it now in order to test we need to create an object to hold our town map visual so we do that we drag our script now in here we also need to add a mesh filter and a mesh renderer and in the mesh renderer let's choose the black red yellow green material alright just like that ok and now finally we just need to call the separate functions so let's go to our testing script here and let's add a civilised field for our town math division and then here we go into the town map and we're going to make a function to set the town map zero okay let's make this so in here here we can't separate any person oh great all right so again we have our new town map visual script it is attached to a game object here we just create the mesh and update it in order for this to work on we need this to consecrate so in order to do that we have a reference on our testing script and then we go into our town map and you tell it to set the town map visual to be this one okay so just like this it should be working we should be able to see the grid with none display a black wad and if it's a ground it won't display a green one and yet there it is everything with black quads now I click and there you go we turn from black to green all right awesome and now if we pause and look at the scene wireframe so we go up here and instead of shading know it's like wireframe and as you can see we are drawing our grid using quads so each cell size is a different quad so that's great but in this case we don't want our town map to display the non sprites at all only the ones that have ground so in here we don't want to waste all of this rendering power we only want to display the green ground so let's go into our code and here on the town map visual here we are testing if we have a non sprite and if it's not none now in here in order to not draw something we have two options now the perfect option would be to really not right at all so essentially we would only generate our mesh with the size of the visible quads but if the grid is small or performance is not absolutely essential then we can keep things simple and here all we need is to set our quad to occupy no space at all so I can go in here and set the quad size if it is none selected vector 3.0 so at that point on 4 vertices won't be at 5 s 3.0 so essentially they won't draw anything at all so just like this let's test and there it is now the none no longer have a visual but if I click yep there you go the green one still shows up and if I pause and here we are looking at the wireframe and as you can see there aren't any quads on any of these positions only on the one that we drew so just like that we are no longer wasting a bunch of GPU resources all right awesome now instead of just a green square let's actually display a sprite over here in the textures folder I have this now texture appleís as you can see it contains four different towns so let's make a material for it and now here on the original let's use this material instead okay using this material with this texture and now here in the code we need to actually set up the values for the UV 0 and UV 1 as you can see that's what this function receives at the end there it receives a UV 0 0 and UV 1 1 so it's a UV for the lower left corner and the upper right so let's split this and here in order to display the full texture it's very simple we just set the zero zero on vector 2.0 and the one on what all right so just like this we should be able to see the whole texture let's see okay everything's invisible now click any of there you go there's the ground displaying our font texture alright great now obviously instead of displaying the whole texture we want to display just a single time that way we can draw a different sprites so let's do that again here we have our four different towns so it's going to our noon to add values here we are in our town Maps right so we're going to have none which is nothing then we have the ground and then let's say that so we have three possible town values with one of them being completely invisible so now here what's going to our testing and let's make it so we can select which sprite to add okay so here I've had a bunch of keys just to try out changing our town map sprite and then we simply set that one okay so here we are starting with nothing okay and if I click right now it's set to none so it doesn't happen so now let's press D Y and now I am selecting the ground now I press any of there we go now I'm placing the ground and I press you okay the next one will be a path and now I can place some path sprites alright awesome so here we have our three different types so now that we have all those valleys added to our enum let's actually display them here we already have the town maps right they were grabbing from our object and if it is none then we still do this so we display nothing and now if it isn't done we're going to need to manipulate the UV to select which town we want to display so for that let's go all the way up here and let's define a struct that we're going to set in the editor inside we have in a new field and then let's also have the coordinates for our UV so we have two vector two ends for the UV 0 0 and 1 1 in pixels so we're going to input the pixel coordinates of the unloader left and upper right corners and now here we just need to make the 0 wise field of an array of this and here to make sure that it shows up in the editor we have to add the attribute serializable which is inside system just like that ok now let's go to the editor and okay there it is you can see our UV array in there now here let's put it a size of 2 so we're only going to set two of them now in here we have the town map sprite so for this one let's choose the ground choose the palette and what's input deep pixels okay so here it is so for the ground we're going to use the second type so each of them is 64 by 64 so over here you can see the first one the X would be in here on 0 here on 64 here 128 here 192 and here 256 and for the Y we simply have 0 and 64 so just like that we have the correct coordinates to use this one as our ground texture and this one as the path texture so it's at this part that you can see where the Bolton Unity town map is already very user friendly is very easy to use in that one you just click and drag sprites whereas in here we need to manually set although if you wanted you could make a custom editor script to do exactly unlike the built in town so now that we have all our data set up we can go into our code and now we can use this data all the way down here into our UV however again we input in pixels and in here we need normalized values so let's convert them before we use them in here let's make another struct this won't be our UV coordinates so here we have the coordinates for the UV 0 0 and 1 1 and now in here let's define a dictionary where our key won't be a ton of sprite and the object won't be of type UV coordinates so now we can go here on our wake and now let's film these values so now here we need to convert our pixel coordinates into normalized in order to do that all that we need is an OD texture size ok so we go into our mesh renderer component access the material and access a main texture then we grab the width and height so now in here all we need to do is take our pixels so I'm Kal map sprite UV let's see the UV 0 0 pixels DX and we simply define it by the texture width and just like that alright so we have successfully converted from pixels into a normalized value so essentially with the design that we did here we have a nice user-friendly structure that we expose in the editor and then we have our nice internal structure that we use to run our code so now we can simply go down here with our dictionary let's grab the UV coordinates grab the UV coordinates from this sprite and we simply use the UV 0 and UV 1 and that's it just like that alright so we should now be able to see each different visual ok see you are everything at now now I press the Y key okay now I'm placing the ground now I click any of there you go it only plays exactly that ground so click more and I'm placing more ground now I'll impress you okay now I want to play see path and click and there you go now I'm placing d-pad correctly so here we are with no debug visuals and again let's play some ground and there you go some ground now let's place path and there you go very nice just like that and I can press none to essentially erase it so as you can see the town map is using our sprite atlas and correctly selecting a part of the texture depending on what Valley we have in our note right awesome so now let's just quickly see how easy it is to add another visual type in order to do that we just go here into our town map and add another enum value okay we have not value now on our testing let's add another key okay there it is and now finally we just need to go into our editor over here on our town map visual script let's add another one and set it and just like this we have at another time let's see okay can someplace the ground I can place the path and now I can place some dirt so just like that we add another type into our town map great now let's look into how we can save our town map in order to persist between place so for that I'm going to use the safe system that was created in a previous video go check out that video for an in-depth look into how we format our safe object with Jason and save it into a file here is the class as you can see we have our safe folder and save extension on the initialize we just make sure the folder exists then we have a function to save which receives a file name and the save string to save as you know Jason is stored in a string are you choose to overwrite or not so that's what this does make sure that this a file is unique and here we simply save it now in here functions to load from a specific file name or just the most recent one and the way we'll know this we just read all the text and then down here we have functions to save a safe object and the way that it does is it takes an object of type save object which can be anytime and we simply use the jason utility in order to convert that save object into Jason so that returns a string which then is saved on the function up here and then for the unload object function it does exactly the opposite we simply go into our jisun utility and convert from string into our save object as you can see in here we are also using generics in order to be able to save and load any object time so with this nice class we can easily add saving and loading for our Tama so let's go into our town map in here on our town map object okay let's go down here to define a same object and here we have all the fields that we need in order to store and now we make a function to save it which won't return a save object so here we are setting the values on the save object based on the ones that we have on this object alright so this is our nice save function and now let's go into the town map itself and in here let's make a save function and the way we're going to save it is by cycling through the home map so here we are cycling through all the town map objects on our grid now here we can go into the town map object in order to come save this will return a town map object save object so we add this into a list so at the end here we have a phone list with all of our save objects and I mean here let's have a save object for the town map itself in order to hold this list and here we can create this save object and we pass in that ok we just convert our listen to all right the reason why I'm using an array here is because Jason automatically works with a race but you need to do some work to make it work with own list so in this case let's Emily convert into an array to keep things simple so with that we now have our final save object which contains all the save objects for each single great sound position and now in here we can simply save our phone so we go into the save system and call save object and we pass in our save object alright so that you do it now in here one thing we need to make this work is to go down here into the town map save object and we need to make this serializable the reason is because we were using this same object inside another array so if we don't make it serializable then this would be empty and on this one since this is the main safe object we don't need to add it okay so that's pretty much it now let's go into our testing let's add a key in order to save ok so let's press P to save now let's test ok here we are let's paint a bunch of things so there's a bunch of ground what's your past and much inert okay now press P and there you go we have saved and I can look here in the project files we have a nice saves folder and inside we have a safe and over here you can see all the text that makes up our safe so as you can see our that is on there now if we wanted we could only save the values which are not default which would help cut down size but for now let's keep things simple so now that we have saving working let's see on weight loading here on turnip we have our save function and now here let's make our load function here we're going to go into our save system and calm load let's look at the most recent object so again we're using generics so in here we're going to load a type save object okay so this returns a save object now here again the save object contains an array of all of our town map objects save object so we cycle through it so here we have a town map object save object and then we simply go into our grid to get the grid object that is only save object at X and not Y and here we tell it to load so here we receive the same object and simply set our town map sprite to the one that is only save other and the x and y are already set in the constructor so here we just do that and we pass in that all right great so this should be working and now in here you could make this code a lot more robust so for example on the town map save object and here you could also include the width and height in order to support loading of different size of town ops only takes in order to soar and more information is just that fields unsaved objects so you'd add more fields in here for any film that you want to say for the Talmud and then down here more fields in here for any extra information you want to store on each town map object so as you can see this system is very easy to use in order to save and hello all right so that's it now one final thing is we need to make sure that our visual changes so for that we can use a nice event so let's make a event called unloaded and here when we load let's fire that event alright we if we have subscribers then we call the event and we pass in this okay so now for that we can go into the visual and here when we set the grid let's set the grid and also receive a reference to the camera so that we can subscribe to the unloaded and on the onload event reduce to the same as yellow we just update the mesh and finally in our testing code let's add a button to load the previous timer just like that okay alright so let's see okay here we are and everything is empty and after a personal note button there you go it correctly loaded exactly the same as we saved now I can add more stuff loaded again and there you go it raised that one and it completely loaded the entire state of art Elma so now I can modify it save it modify it again okay it raise it all press mode and there you go it load the previous state so I can modify anything I want paint anything delete anything do everything then I can save then I can erase the whole thing and unload any up there it is awesome so we have successfully built our own town map with the ability to have our underlying grid with whatever object type we want and also enabled saving and loading as you saw on the data for saving the town map is saved here in our project files so you can see how this would be very easy to make a level editor that your players could share with others now again as I said the built in town map is already very powerful so if your use case is very simple it might be easier to use down however by using this one you can use this for vision and then use another grid for keeping track of all your logic meaning that both your design logic and visual will use the same base class which helps reduce complexity and makes it easier to understand while developing your game regardless of what approach you take a place now you know how a town map works there's no magic in programming so even if you end up using the easy-to-use class it helps you understand how it works underneath it all as always acknowledge the project founds in utilities form in Tacoma comm if you liked the video subscribe channel for more unity to torrents post any questions you have in the comments and I'll see you next time [Music]
Info
Channel: Code Monkey
Views: 43,811
Rating: undefined out of 5
Keywords: unity tile map editor, unity grid tilemap, unity tilemap, unity tile pathfinding, unity level editor, unity tilemap tutorial, unity grid, unity tilemap navigation, unity tile game, unity grid system, unity grid movement, code monkey, brackeys, unity tutorial, unity game tutorial, unity tutorial for beginners, unity 2d tutorial, unity 3d, unity 3d tutorials, unity tutorial 2d, unity2d, unity3d, unity
Id: gD5EQyt7VPk
Channel Id: undefined
Length: 25min 31sec (1531 seconds)
Published: Wed Dec 04 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.