What is the best data structure for crafting and how to create it?

0 favourites
From the Asset Store
Template for maintaining an inventory with crafting possibilities. Completely documented in text and video.
  • I'm still getting used to working with JSON, Arrays etc so I'm kinda figuring it out as I go along, but I'll try and answer what I can!

    In terms of the For Each loops, you can nest them like this:

    Which in an incredibly basic example would pull out the data like so:

    So you could in theory compare each entry in the components list with some ingredients stored in an array and see if they match the recipe.

    In terms of bringing count into it, it would depend on how you've set up the 'inventory' section of your crafting system. In the one I've built, I use a dictionary to track how many of a given item I have, so again you could check the value stored in count against the number stored for an item in the dictionary and if you've got enough, then subtract the count from the dictionary value.

    I'm still trying to build out my own crafting system, so I'm going to try some of these ideas myself and I'll let you know how I get on.

    Sorry I can't be of more help!

  • I'm still getting used to working with JSON, Arrays etc so I'm kinda figuring it out as I go along, but I'll try and answer what I can!

    In terms of the For Each loops, you can nest them like this:

    See now that answers one of my big questions, how do I access the components list. I didn't know that I needed a nested For Each loop. I kept trying to use the For Each loop with "recipes/components" or "recipes.components" and neither worked. So that is interesting.

    If you don't mind a tangent question (but is definitely related); do you know the overhead of using AJAX to load a project file, do stuff with it (like checking the components listed inside and loading that file into a dictionary) then clear and load another file and so on and so forth for like 10-15 files? T

    Reason I am asking is because this is my current setup, I have a Dictionary File for each recipe, I load into a dictionary with AJAX then use the KeyCount to check if it is correct, if so, I start comparing components. Rinse and repeat for every recipe (which means every Dictionary file in the project since each recipe = a file).

    If the overhead is big, then what you just presented might actually work better -- one big JSON file that I load chunks off into a dictionary and use the dictionary's KeyCount, still won't solve the loop over the JSON 3-4 times to get what I want, but at least if AJAX has a big overhead, I saved that.

  • Afraid I know nothing of overheads - at that point I'd usually try and create mini versions of what I was trying to test and compare the two.

    Usually I just chuck everything into as few files as possible so I only have to fetch the file once when the game/project loads. I've never tried looking at multiple files at runtime!

  • Afraid I know nothing of overheads - at that point I'd usually try and create mini versions of what I was trying to test and compare the two.

    Usually I just chuck everything into as few files as possible so I only have to fetch the file once when the game/project loads. I've never tried looking at multiple files at runtime!

    It is more sensible to put all the recipes in a crafting system into one file or if the system has different categories (potions, weapons, armor, etc...) it would be each a file. But right now if they are all in one file I can't tell which recipe is which. Apparently in JSON you can't tell the For Each to stop when you found something and the System > Stop Loop action doesn't work with it. So it seems you can work with the entire lump of data not chunk it and work on pieces of it. Could be wrong though.

  • So, Kyatric and I have had a bit more of a think about this, and if you're still interested, this blog briefly outlines the project he came up with. It also contains a download link for the project.

    At some point, I plan to turn it all into a tutorial, but that's a looong way off!

  • Feeling this was right up my alley I took a stab at it using the provided recipes JSON exemple.

    I use an array to store the currently owned components. "Crafting" recipes in this exemple simply remove the components, but in real use case you'd add it to your inventory of course !

    drive.google.com/file/d/1F1jzwfNWpln8CbLtyPz5jnK6pyh9uwJm/view

  • So, Kyatric and I have had a bit more of a think about this, and if you're still interested, this blog briefly outlines the project he came up with. It also contains a download link for the project.

    At some point, I plan to turn it all into a tutorial, but that's a looong way off!

    Oh, thanks a lot Laura_D and Kyatric that definitely looks interesting and is what I wanted to do at first. I read your blog and checked the .c3p file. I can't say I understand it all -- specially the part where you're checking if the recipe exists or not. But I think I have a good overall gist of how this is done.

    I'll see if I can attempt to replicate this.

  • Feeling this was right up my alley I took a stab at it using the provided recipes JSON exemple.

    I use an array to store the currently owned components. "Crafting" recipes in this exemple simply remove the components, but in real use case you'd add it to your inventory of course !

    https://drive.google.com/file/d/1F1jzwfNWpln8CbLtyPz5jnK6pyh9uwJm/view?usp=sharing

    Thanks for the .c3p. I have been reading over it and a few things went over my head, if you don't mind a few questions:

    1- The function "getRecipeIndex", is this the function that checks what kind of recipe is the player targeting? If that is the case, could you explain what is the second condition (the JSON one)? I don't understand what that does at all.

    2- Is there a reason why you're using For loops instead of For Each loops on the JSON object? Specifically in the "possibleRecipeCraftCount" function. Is it because then you can use the Stop Loop action?

    3- In "possibleRecipeCraftCount" does this line "JSON.Get("recipes." & recipeIndex & ".components." & loopindex("components") & ".name"" means Get the key that is recipes.recipeIndex.components.loopindexcomponents.name? How is that constructed? Like in my mind say first index of the loop this would mean "recipes.0.components.0components.wormwood" But I am not sure how that works in JSON. Could you explain this in plain English, please?

    4- I am guessing this line here "recipeAvailability = -1 ? 0 : recipeAvailability" is similar to C#'s terenary operator? Does this mean if recipeAvailability equals -1 then set it to 0 and if not, leave it as is?

    Thanks

  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • Here are some answers to your questions :

    1- This function only returns the index of a specific recipe name inside the JSON. It's useful to build the JSON Path to other properties of a given recipe, namely the components and the quantity needed.

    2- That's precisely it. The "stop loop" system action cannot stop loops other than system loops. It's useful to stop iterating through the JSON if you already found what you wanted. It can optimize speed a bit, given a much bigger JSON file and components list. However it also has the drawback of making the syntax a little bit harder to read and write.

    3- loopindex("components") means the loopindex of the "components" system loop. However, it is not needed since there is only one active loop at that point. I used nested loops at first, but changed it afterward. I could have removed the ("components") part and used JSON.Get("recipes." & recipeIndex & ".components." & loopindex & ".name") instead. For the first component of the first recipe, it translates to "recipes.0.components.0.name" and returns "Wormwood". The same statement would be written "recipes[0].components[0].name" in normal javascript. C3 use a peculiar syntax to access an array's items.

    4- That's right. I could have used an "else event" and used 2 actions instead of one but a ternary operator was more concise and still readable. C3 format for the ternary operator is indeed the same as C# or Javascript.

  • Here are some answers to your questions :

    1- This function only returns the index of a specific recipe name inside the JSON. It's useful to build the JSON Path to other properties of a given recipe, namely the components and the quantity needed.

    I see. I am trying to replicate chunks of what you did in my project to understand what you've done and wrap my head around it but I am failing quite a bit. So one thing I am doing is the below:

    https://i.imgur.com/MEVWcPs.png

    I am using the same sample JSON file as you. But when I run the layout, I get the DebugText changed to "00" only. So I am not sure what does this do and what am I getting even since the JSON has no 0s.

    2- That's precisely it. The "stop loop" system action cannot stop loops other than system loops. It's useful to stop iterating through the JSON if you already found what you wanted. It can optimize speed a bit, given a much bigger JSON file and components list. However it also has the drawback of making the syntax a little bit harder to read and write.

    Would you say in that case, XML would work better? If yes, does XML have the same functionality as the JSON in C3? I am asking because I did try this with XML at first (since I can understand XML a bit better) but I hit the same exact wall.

    3- loopindex("components") means the loopindex of the "components" system loop. However, it is not needed since there is only one active loop at that point. I used nested loops at first, but changed it afterward. I could have removed the ("components") part and used JSON.Get("recipes." & recipeIndex & ".components." & loopindex & ".name") instead. For the first component of the first recipe, it translates to "recipes.0.components.0.name" and returns "Wormwood". The same statement would be written "recipes[0].components[0].name" in normal javascript. C3 use a peculiar syntax to access an array's items.

    Oh! OK, I am not familiar with JS but that looks a lot like C# anyway and it does make MUCH more sense to me. Would you say it would be less of a headache if I try to write this one thing (searching for the correct component) in JS and attach it as a script instead? Because seriously I didn't have this much trouble working with JSON/XML in Unity with C# and I am very confused why it is so convoluted in C3.

  • I see. I am trying to replicate chunks of what you did in my project to understand what you've done and wrap my head around it but I am failing quite a bit. So one thing I am doing is the below:

    The Get expression of the JSON object can only return string or numeric values. The expression you written actually returns an object and C3 can't deal with that so it defaults to 0. You can however use GetAsBeautifiedString or GetAsCompactString to get objects in JSON format.

    Would you say in that case, XML would work better?

    It's pretty much the same I would say. Altough XPath is probably easier, it has the same caveats in terms of iterating. If you use "for each node" for a particular XPath, you can't use "stop loop" and that's a bummer.

    Personally, I'm partial to JSON, simply for that fact that I find it more concise.

    Would you say it would be less of a headache if I try to write this one thing (searching for the correct component) in JS and attach it as a script instead?

    Indeed, if you feel confortable with scripting, you could replicate what I did in a much less convulated manner.

    The JSON plugins expose an API that makes it easier to do interactions between event sheets and scripts, if you go that way.

    construct.net/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/json

  • > I see. I am trying to replicate chunks of what you did in my project to understand what you've done and wrap my head around it but I am failing quite a bit. So one thing I am doing is the below:

    The Get expression of the JSON object can only return string or numeric values. The expression you written actually returns an object and C3 can't deal with that so it defaults to 0. You can however use GetAsBeautifiedString or GetAsCompactString to get objects in JSON format.

    > Would you say in that case, XML would work better?

    It's pretty much the same I would say. Altough XPath is probably easier, it has the same caveats in terms of iterating. If you use "for each node" for a particular XPath, you can't use "stop loop" and that's a bummer.

    Personally, I'm partial to JSON, simply for that fact that I find it more concise.

    > Would you say it would be less of a headache if I try to write this one thing (searching for the correct component) in JS and attach it as a script instead?

    Indeed, if you feel confortable with scripting, you could replicate what I did in a much less convulated manner.

    The JSON plugins expose an API that makes it easier to do interactions between event sheets and scripts, if you go that way.

    https://www.construct.net/fr/make-games/manuals/construct-3/scripting/scripting-reference/plugin-interfaces/json

    Thank you very much for your answers, this is very helpful. I'll give your recommendations a try and stay with JSON for a bit longer. If things get hairy, I'll see if I can try XML in hopes I could replicate the same logic but with something easier to write :)

  • https://i.imgur.com/MEVWcPs.png

    I am using the same sample JSON file as you. But when I run the layout, I get the DebugText changed to "00" only. So I am not sure what does this do and what am I getting even since the JSON has no 0s.

    The path you are using is not correct

    JSON2.get(".recipes" & loopindex) probably will work

    It depends on the content of your json file though.

    You might want to check back on the JSON example provided with Construct, it is pretty simple to understand how you are supposed to create your structure.

    editor.construct.net

    And check back on the example provided by Laura, it should make more sense.

    The issue here doesn't seem to be with scripting or events, but with the actual structure of your JSON file.

    Post it, it will be easier to establish the correct events in regards to how you established your file.

    In my experience XML is not simpler.

  • Thought I'd have a go at this.

    The events simplify nicely by having a dictionary for the inventory and an instance of a recipe dictionary for each recipe.

    dropbox.com/s/cw1xuiiymjqq6oq/crafting_test2.capx

    JSON and XML are a pain to write imo. With the above example you can just create the recipes with events fairly cleanly, or just load and parse a plain text file to populate it.

    #recipe Blinding Flash Potion
    2 wormwood
    5 sulfer
    
    #recipe Potion of Sweet and Savory
    5 salt
    5 sugar

    I could get behind writing recipes like that all day long. No quotes or matching brackets.

  • >

    > https://i.imgur.com/MEVWcPs.png

    >

    > I am using the same sample JSON file as you. But when I run the layout, I get the DebugText changed to "00" only. So I am not sure what does this do and what am I getting even since the JSON has no 0s.

    The path you are using is not correct

    JSON2.get(".recipes" & loopindex) probably will work

    It depends on the content of your json file though.

    Interesting. Thank you for pointing that out. Does this mean that the parent "JSON part" (like the parent header) must have a "." before it? I thought it didn't need that, since it is at the very top.

    You might want to check back on the JSON example provided with Construct, it is pretty simple to understand how you are supposed to create your structure.

    https://editor.construct.net/#open=json

    Oh, I did. I looked at that for hours really, but it doesn't help in understanding how to divide a JSON and search based on sub-sub entries with a list. I wish there were more advanced examples that go in depth of how to use JSON and XML.

    And check back on the example provided by Laura, it should make more sense.

    The issue here doesn't seem to be with scripting or events, but with the actual structure of your JSON file.

    Post it, it will be easier to establish the correct events in regards to how you established your file.

    In my experience XML is not simpler.

    The JSON is fine, I posted it before here:

    https://www.construct.net/en/forum/construct-3/how-do-i-8/best-data-structure-crafting-154650#forumPost1020452

    I think you used it in the example .c3p you worked with Laura on. I've also used it to print out the information inside and it worked. Now the structure may not be C3's "optimum one" (if there is such a thing) but I use JSON validator when I write JSON since I personally can't write it properly without one :D.

    Thought I'd have a go at this.

    The events simplify nicely by having a dictionary for the inventory and an instance of a recipe dictionary for each recipe.

    https://www.dropbox.com/s/cw1xuiiymjqq6oq/crafting_test2.capx?dl=1

    JSON and XML are a pain to write imo. With the above example you can just create the recipes with events fairly cleanly, or just load and parse a plain text file to populate it.

    #recipe Blinding Flash Potion
    2 wormwood
    5 sulfer
    
    #recipe Potion of Sweet and Savory
    5 salt
    5 sugar

    I could get behind writing recipes like that all day long. No quotes or matching brackets.

    Thank you very much for trying this. I am using a similar approach at the moment (conceptually); I have a dictionary file for every recipe and one dictionary object that I load the file into the dictionary, check if it is this one or not. If it is not, I move to the next file. Which gets rather hectic fast events wise. This is interesting though. Could I ask you to ELI5 this part please?

    https://i.imgur.com/pt88uw6.png

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