Saving tileset to json/export?

0 favourites
  • 7 posts
From the Asset Store
Match the similar cards with each other and free all animals!
  • Hey all, im circling back to a project and using construct 3 for the 1st time. Im implementing this Level Editing tutorial by Game design by Reilly that works like a charm, although not with a tileset.

    Here's the events with my project

    Perhaps I need set tiles from Json action? I have not done saves before so not sure how to impliment it into the array/ajax.

    Link to my project: drive.google.com/file/d/1DVB3-sI8wdJyEYmp30AlErY-lVfPDnC7/view

  • I couldn't have a look at your file as it needs permission to access it.

    But in general, if you just need to save the Tiles of a tilemap, then you can save the JSON "Tilemap.TilesJSON" in an (Array or Dictionary) and download it.

    Then load from AJAX the (Array or Dictionary) first and after that load the Tiles Tilemap from that "Tilemap.TilesJSON" that you saved in one of those plugins.

    Here is one example:

    https://www.dropbox.com/scl/fi/y9o8swpe7xthug47awb85/1-TileMap-Load-From-JSON.c3p?rlkey=t36g5zfwa09wrxv749nu086g6&dl=0

  • Thank you for the response! I guess a better question would be, how to fit the tilemap json data into the array and the downloaded file. The concept of arrays is really confusing to me, but as i understand it has 3 dimensions being used for the object name, x, and y position. It doesnt seem the tileset data would fit into the array, perhaps a different configuration or 2 files will be necessary to save a level? Im completely unfamiliar with the dictionary object and its capabilities.

    The goal is to save each level as a separate file and load them all when starting the game. More elements will likely need to be saved as I continue development, so just trying to get an understanding of how to compile complexities into a save. Thank you for reading over this and my ramblings attempting to understand code :) updated the project link it should be accessible now!

  • Oh boy, using the Dictionary plugin is very useful for your case with a level editor!! I'll answer in great detail as I am also working on level editor stuff and it's enjoyable to make and think about! Grab a glass of water and regret ever asking for help!

    Dictionary

    Think of it like: Dictionary is very similar to Instance Variables. Dictionary is a list of "Keys" (Keys are like an Instance Variable's name) and a value that you choose what data you want to save, strings and numbers can be used. So yeah it's just like Instance Variables but with extra power, and keeps all this data in one place.

    So for example, in your project, lets use a Dictionary to store all the bits and pieces of data about the level such as the "Level_Name" and other data maybe like "Version" or "CreatedBy" depending on what you need.

    To store data in a Dictionary:

    1. Add a Dictionary, rename it to what you want like "DictMapData".
    2. Go to Event Sheet and Add new event.
    3. In the new event, add condition as a test like "On SPACE key pressed".
    4. Add action DictMapData>Add Key, then key name to "NameOfLevel", value to "TestMapLol"

    Can then add a Text object as a test, then add one more event to like "On G key pressed", then Set Text to DictMapData.Get("NameOfLevel")

    Now run the game, press SPACE, and yeah, text gets set to "TestMapLol" so we know the Dictionary has stored the name of the level, woo!

    Other Dictionary notes

    You can download this dictionary the same way as you have done for the Array, load the same way. It downloads all that data as 1 file, nice and tidy!

    Add hundreds of keys if you wish, it performs excellently! Could add keys like "Version", "CreatedBy", add more events to set/get data from TextInputs that the player types into and such.

    Could add other cool stuff, for example, with Date plugin added to your project, you could do action for Dictionary: Add key "DateOfLevelCreation" with value Date.Now.

    You can then set a Text object at any time to Date.ToDateString(Dictionary.Get("DateOfLevelCreation")) and this will display the creation date of the map to your players.

    Image files can technically be stored in the dictionary if you ever need that sorta thing (Maybe you use images for an icon of the map, or custom sprites/backgrounds) but I'd say it's preferable to keep images separate, because: In order to store the image, you need to convert the image into a value that can be stored in Dictionary which is either a string or number. There's a way to convert image into a string, known as Base64, by using the Cryptography plugin. But problem is, those strings are HUGE and don't wanna slow down Save/Load and player sees the game lag, or worse, there's so much image data that when you load it in all at once, it crashes the game. Maybe 1 or 2 small images are fine. To be fair, haven't tested it much, maybe its fine to add images to Dictionary, it is probably a good method for a Website-based game if that's what you're goal is.

    Saving big lists of items with an Array

    In a level editor, you'd have things that the player can endlessly spawn. Maybe it's ingame objects, coins, spikes. Maybe your TileMaps if there are more than 1. This is where things get more tricky as you have to deal with Arrays, but overall it will make a lot of sense once you use them long enough.

    Array is more or less a grid of data. 1D being a list, 2D being a grid, 3D being a...3D grid.

    When using the actions in an Array object, it can be a little confusing, like "Push" and such to add values - You can use these if you wish, but I will use an alternative method as I feel it's more "readable", using "Set Size Of Array" and "Set Value At".

    1D

    Basic list of data, an Array with size of 5x1x1 is essentially "A list of 5 bits of data I want to store". As Array's work with index numbers you write data to the Array at X=0, X=1, 2, 3, and 4. Maybe you write a shopping list with this: Set Array X=0 to "Bread", set Array X=1 to "Lemon", etc. Very basic type of Array.

    You might be able to use this for your TileMap objects if it's literally just the TileMap JSON data needed and no other data:

    1. Add new test event like "On A pressed".
    2. Add action Array>Set size to 0x1x1 (this empties the list so we can start adding)
    3. Subevent under "On A Pressed".
    4. On subevent, add "For Each - TileMap".
    5. On subevent, add action Array>SetSize to X= Self.Width+1 , Y=Self.Height, Z=SelfWidth
    6. Add another action Array>Set Value At X, X=Self.Width-1 , to value TileMap.AsJSON

    Done, so say you had 6 TileMap objects, and you press the A key, the result will be the Array reaching size of 6x1x1 , and each list item is the TileMap's JSON string.

    You can then load by making an event: Array>For Each X, then action: Create Object TileMap. Another action: TileMap>Load From JSON and type Array.At(Array.CurX) as CurX gets the Current "For each" index. This loop will check X=0, see the TileMap data, load it in, then the next part of the loop checks X=1, see the TileMap data, load it in, etc.

    2D

    Lets go to 2D Arrays, lets say size is 5x10x1, this can be thought of in two ways: Either "This is a list of 5 "groups" of data with 10 properties", or "This is an X and Y coordinate grid". In the case of saving a list of objects and data, we will think of it like "A list of 5 groups of data with 10 properties".

    A 2D Array is a good path to take. Lets assume we want to store 5 pieces of data per object. Your Array would start at size 0x5x1, as we have no object data stored yet (0), and we have 5 pieces of data we wanna store about the object (5).

    In your mind, or write this down, but you want to "map" each number. As we want to store 5 pieces of data, we need to decide what we want for each index from 0 to 4 (Seems strange it goes to "4" but think of it like index number 0 is actually storing data, so we still have 5 properties, but it just starts at index 0 and ends at index 4). So as a random example, I will plan that Y0 will be for the "NameOfObject", Y1 will be the XPosition, Y2 is YPosition, Y3 is Object's colour, etc.

    Follow similar events to the "1D" example as written above, but instead of "Set at X", you can use "Set at XY", then the X remains as "Self.Width-1", and the Y can manually be typed, lets say 0 because we want to write in the "NameOfObject" data, then set value to "TestObject" or "TileMap" or whatever. CopyPaste this "Set value at XY" action, edit, change the Y to 1, we planned earlier that 1 will mean "XPosition", so we can then set this value to TileMap.X. etc etc etc.

    The loading part is similar to 1D, too, we still only need to do a "For Each X" for the Array, but we can do extra stuff now in this creation event, so could edit the "Create Object TileMap" action to update the position correctly and set the X position to Array.At(Array.CurX,1) and Y position to Array.At(Array.CurX,2). Tada, this makes the TileMap load to it's correct position!

    I will skip 3D Arrays.

    Use both Array and Dictionary for readable and expandable level editor data

    Once you are VERY familiar with all of this, the ultimate wombo combo you could do is a combination of a 2D array AND Dictionary. Will go light on detail:

    You can add many Dictionarys, maybe you add them for each Level Editor object and use them as an alternative to Instance Variables, so each Enemy object gets it's own Dictionary and stores Health, Ammo, Type, Colour, and other customisable pieces of data.

    The benefit of this is: You could have your 2D Array be 0x2x1, and we will plan the Y=0 to be "TypeOfObject" and Y=1 to "DictionaryAsJSON". Then follow the example written in the 2D section above, but simply load this dictionary in for each level editor object with 1 action, and now you have an easy-to-use Dictionary and can get data from Key Names rather than "memorising/reading notes about the Array to remember what each Y index is supposed to mean", or else you may be like "Was index 12 the colour of the object? Was index 33 the angle of the object?"

    Download/Save/Load stuff

    I notice you use "Download" for the Array (and you would then use Download for the Dictionary), which is good for a game that's going to be uploaded onto a website or for Mobile devices. For desktop/EXE/Steam games, the "preferable" way would be using the FileSystem/NWJS/WebView plugin, letting you have a "Save to" window popup and such if needed, and also being able to write files directly to the player's computer without any popups (With "Download" the Dictionary data always goes to the player's C:/Downloads folder, but with these plugins for desktop games, the player can choose the location to save, or you can design you game to automatically save in any location on their computer).

    Hope this helps and good luck!

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • Grab a glass of water and regret ever asking for help!

    Lol

    I will skip 3D Arrays.

    Thank God you had some piety for the poor soul :)))

    Thank you for the response! I guess a better question would be, how to fit the tilemap json data into the array and the downloaded file. The concept of arrays is really confusing to me, but as i understand it has 3 dimensions being used for the object name, x, and y position. It doesnt seem the tileset data would fit into the array, perhaps a different configuration or 2 files will be necessary to save a level? Im completely unfamiliar with the dictionary object and its capabilities.

    The goal is to save each level as a separate file and load them all when starting the game. More elements will likely need to be saved as I continue development, so just trying to get an understanding of how to compile complexities into a save. Thank you for reading over this and my ramblings attempting to understand code :) updated the project link it should be accessible now!

    Let me add to the combo, to give you the final blow :)

    A lot of it is repeated, though I will try to make it more visual, maybe it will be easier to digest.

    The first thing I will recommend to you is to spend some time learning (Dictionaries & Arrays). Take your time and learn how to (Add & Retrieve) data from those plugins. There are plenty of tutorials for that.

    And have a look at the Manual:

    https://www.construct.net/en/make-games/manuals/construct-3/plugin-reference/array?utm_campaign=C3Editor&utm_source=browser&utm_medium=r391&utm_term=PropertiesBar-LinkProperty

    https://www.construct.net/en/make-games/manuals/construct-3/plugin-reference/dictionary?utm_campaign=C3Editor&utm_source=browser&utm_medium=r391&utm_term=PropertiesBar-LinkProperty

    Dictionaries:

    You can learn them in minutes as they are the easiest.

    Use "Add Key": to add a -------> (key & Value)

    Dictionary.get("KeyName"): to retrieve the Key -------> (Value)

    Have a look at the Manual they will show you all the Expressions and Actions.

    Arrays:

    You can customize it to your needs, you can use (1D, 2D or 3D)

    What is the difference between those 3 types?

    It depends on the (Width, Height, Depth)

    The depth is represented by "Z" --------> (Width, Height, Z)

    Width = Total Columns

    Height = Total Raws

    How C3 works to retrieve the data?

    X = Which Columns index Number is

    Y = Which Raw index Number is

    Z = Which dimension is

    1D Array:

    It is when you have a (Height = 1), meaning one Raw.

    So here to retrieve any Column index data you just need the X index number

    For example:

    Here is an Array

    Width = 7

    Height = 1

    The first coulmn will be --------> (X = 0)

    The Last column will be --------> (X = 6)

    If you want to retrieve the value from the first column ------> Array.at(0)

    If you want to retrieve the value from the last column ------> Array.at(6)

    2D Array:

    It is when you have a (Height = 2) or greater, meaning multiple Raws.

    So here to retrieve any data you will need the (X,Y) index numbers.

    -The Top-Left Array cell will be at (0,0)

    -The Top-Right Array cell will be at (6,0)

    -The Bottom-Left Array cell will be at (0,2)

    -The Bottom-Right Array cell will be at (6,2)

    If you want to retrieve the value from the Top-Left------> Array.at(0,0)

    If you want to retrieve the value from the Bottom-Right ------> Array.at(6,2)

    3D Array:

    Is when you add depth, meaning more than one dimension, (Z = 2) or greater

    Each dimension is one Array independent, you can view it as layers:

    (Dimension 1= Layer 1)

    (Dimension 2 = Layer 2)

    Etc...

    As you can see in the picture:

    Array 1--------> will be stored on Dimension1

    Array 2--------> will be stored on Dimension2

    Array 3--------> will be stored on Dimension3

    To retrieve the data now you will need (X,Y,Z) for 3D Arrays.

    If we take the example from the 2D Array Picture Avobe:

    If we want to retrieve the data from:

    -The Bottom-Right Array dimension1 will be at (6,2,1)

    -The Bottom-Right Array dimension2 will be at (6,2,2)

    -The Bottom-Right Array dimension3 will be at (6,2,3)

    Finally:

    How you save the data you will need to figure it out by yourself so you can select a structure that you will understand and feel comfortable with. There is no right or wrong, every one has his favourite way of doing it. You can use Dictionary only or just Arrays, or both. You can use multiple Arrays and dictionaries, the possibilities are endless.

    If you do step one properly then you should be able to figure it out easily.

    Here is just a quick random example, just for this tutorial:

    You say you want to save the Tilemap XY and with, height

    Use the expression ---------> Tilemap.AsJSON

    -That will save you all the data of the tilemap

    -Then for example you decide to use Dictionary to save all the enemies

    -Then you decide to use Dictionary2 to save all the Objects like (Coins, Powerups, etc..)

    Here is one possibility of how it can look like:

    X = Level Numbers:

    X = 0 ----> Level1

    X = 1 ----> Level2

    etc...

    Then you have the whole (Height or column) to store all the data for the levels:

    Example:

    Level1:

    Array.at(0,0) = Tilemap JSON

    Array.at(0,1) = Dictionary Enemies

    Array.at(0,2) = Dictionary Objects

    Level2:

    Array.at(1,0) = Tilemap JSON

    Array.at(1,1) = Dictionary Enemies

    Array.at(1,2) = Dictionary Objects

    Level3:

    Array.at(2,0) = Tilemap JSON

    Array.at(2,1) = Dictionary Enemies

    Array.at(2,2) = Dictionary Objects

    And so on...

  • Lolol, excellent write up with visuals! Just wait until uglypenguin sees all this and just quits game dev for good.

    Honestly though we promise it is easy once you are familiar, but our descriptions and tarek2's visuals are to help comprehend it all.

    Ask away if unsure, also feel free to join the unofficial Construct 3 discord server if you want immediate feedback for little questions at all: discord.gg/construct-community-116497549237551109

  • Oh my goodness, thank you guys so much for the documentation! The visualization REALLY helps. Ill need some time to digest and test things out, hopefully report back with results! :)

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)