How do I use prototypes in JSON?

0 favourites
  • 7 posts
  • Hello there!

    I wonder how objects can inherit/copy other objects keys/values.

    I watched some videos and read through some explanation pages about prototypes, constructors and stuff, but found it a bit confusing.

    Some of them say don't do that. Don't use this. Since ES6 this is obsolete. This is old. Even though you can still do this, you should do that instead etc. etc. .

    Maybe someone can explain this to me how it can be done before I spend another 5 hours finding the up-to-datest or best way to inherit one objects properties into another ones.

    What I'm trying to do is as follows: I want to have objects that are "templates" for other objects.

    Let's have an example. An RPG.

    There could be a template with the key weapons, one with the key armors, spells and one with the key items.

    This are just fantasy values but the JSON could look like this:

    {
    	"templates": {
    		"rarities": {
    			"colors": {
    				"common": "80,80,80",
    				"rare": "0,0,80",
    				"epic": "90,0,80"
    			}
    		},
    		"weapons": {
    			"color": "100,0,0",
    			"name": {
    				"x": 25,
    				"y": 5,
    				"font_size": 16,
    				"font_style": "bold"
    			},
    			"text": {
    				"x": 10,
    				"y": 50,
    				"font_size": 12,
    				"font_style": ""
    			},
    			"picture": {
    				"x": 0,
    				"y": 20,
    				"width": 50,
    				"height": 50
    			},
    			"attack": {
    				"x": 40,
    				"y": 5,
    				"font_size": 18,
    				"font_style": "bold",
    				"icon": "sword"
    			}
    		},
    		"spells": {
    			"color": "0,0,100",
    			"name": {
    				"x": 25,
    				"y": 5,
    				"font_size": 16,
    				"font_style": "bold"
    			},
    			"text": {
    				"x": 10,
    				"y": 120,
    				"font_size": 12,
    				"font_style": "italic"
    			},
    			"picture": {
    				"x": 0,
    				"y": 20,
    				"width": 50,
    				"height": 100
    			},
    			"cost": {
    				"x": 40,
    				"y": 5,
    				"font_size": 18,
    				"font_style": "bold",
    				"icon": "mana"
    			}
    		}
    	}
    }

    Now if I create new weapons in the JSON I do not want to always define where the x and y positions of the weapons name should be or where it's picture should be etc. .

    {
    	"items": {
    		"weapons": {
    			"1": {
    				"name": "Axe",
    				"text": "Great for cutting trees.",
    				"attack": 5,
    				"rarity": "common"
    			},
    			"2": {
    				"name": "Rusty Sword",
    				"text": "Not a great sword at all.",
    				"attack": 7,
    				"rarity": "common"
    			},
    			"3": {
    				"name": "Rusty Greatsword",
    				"text": "A greatsword which is not a great sword either.",
    				"attack": 10,
    				"rarity": "common"
    			}
    		}
    	}
    }
    

    1) How can I inherit the templates properties? Is there a way how I can have all of the entries under the key "weapons" have the properties of the weapons template or do I have to "link" the weapon template to each of the weapons individually?

    Oh and bonus question:

    2) Should I instead of an ID as the key name use the weapons name as the key name? Or an array?

    {
    	"weapons":{
    		"Axe": {
    			"text": "Great for cutting trees.",
    			"attack": 5,
    			"rarity": "common"
    		},
    		"Rusty Sword": {
    			"text": "Not a great sword at all.",
    			"attack": 7,
    			"rarity": "common"
    		},
    		"Rusty Greatsword": {
    			"text": "A greatsword which is not a great sword either.",
    			"attack": 10,
    			"rarity": "common"	
    		}
    	}
    }
    

    Thanks for reading and thank you for explaining it to me. :D

  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • Been meaning to respond to this, but just could not write a comprehensive answer.

    The short answer is that there is no built in method to do this with the JSON plugin.

    Any solutions would need to be through Javascript scripting and even then it wouldn't be trivial. Definitely possible, but not obvious.

    What you are describing is basically this

    stackoverflow.com/questions/27936772/how-to-deep-merge-instead-of-shallow-merge

    I think it would be much easier to have a file with the common properties for items, that everything will use, and also properties which refer to specific "classes" of items. Something like this:

    {
    	item: {
    		common: {
    			"a": "common-prop-1",
    			"b": "common-prop-2",
    			"c": "common-prop-3"
    		},
    		classes: {
    			"axe": {
    				"a": "axe-prop-1",
    				"b": "axe-prop-2",
    				"c": "axe-prop-3"
    			},
    			"sword": {
    				"a": "sword-prop-1",
    				"b": "sword-prop-2",
    				"c": "sword-prop-3"
    			},
    			"bow": {
    				"a": "bow-prop-1",
    				"b": "bow-prop-2",
    				"c": "bow-prop-3"
    			}
    		}
    	}
    }
    

    Then have another file with the specific items, which have their own unique properties and an ID to the common properties for the class of item. Something like this.

    {
    	items: {
    		"hand-axe": {
    			"a": "hand-axe-prop-1",
    			"b": "hand-axe-prop-2",
    			"class": "axe"
    		},
    
    		"great-axe": {
    			"a": "great-axe-prop-1",
    			"b": "great-axe-prop-2",
    			"class": "axe"
    		},
    
    		"excellent-axe": {
    			"a": "excellent-axe-prop-1",
    			"b": "excellent-axe-prop-2",
    			"class": "axe"
    		}
    	}
    }
    

    So when you want to look up information for an item, first you look up in the specific file, then you look at what is the "class" of the item, and use that to do another look up in the first file. The common properties don't need a specific lookup, you could just get them because you known before hand every item will have them.

    This could also be arranged in a single file, this was just an example.

  • What about classes though? I don't think there's a problem with classes, they should work fine for that purpose.

    class Weapon {
     constructor(whatever) {
     this.x = 25;
     this.y = 5;
     this.whatever = whatever;
    
     }
    }
    
    var object = new Weapon("whatever")
    
    
  • DiegoM Many thanks for the detailed reply! Your way of organizing the common properties and classes looks way better.

    I'm not sure if deep merge is what I wanted to do. Basically I do not know how I can set an object to have a prototype to lookup for default values.

    This is what I meant. There are many different ways listed and I'm not sure which one to choose.

    An important detail that I forgot to mention is that I need to be able to manipulate the objects prototypes at runtime.

    Explanation:

    The player will be able to create new items and he can create them from templates that he created beforehand.

    For example let's say he creates a new item called Allmighty Wizard Staff. Because he already created a template staff before he now defines that the Allmighty Wizard Staff uses this template. So when he creates 30 more staffs he doesn't need to define all the default values again.

    Now I want the app to be able to set the Allmighty Wizard Staffs prototype to staff.

    WackyToaster Could this be achieved with classes?

    Or does this mean that I should use Object.setPrototypeOf()?

    Thanks for helping me!

  • I'm self-taught and I can only comment on things I have used before, and I have never used prototypes. Tbh I don't even know what it does :D

    If I understand your usecase correctly I think it can be done with classes, but I have no idea if it should be done with classes.

    No harm done in trying it out. Make up a small test-case, sink an hour or two into it and see if you get stuck somewhere.

  • Not really sure exactly how you plan to save and load all the data, but as far as creating inheritances in Javascript, just go with classes.

    Prototype inheritance (and everything surrounding it) is legacy at this point. Classes will do the same (and a few extra things) and are much easier on the eye.

    One thing to note is that, even though prototypes are legacy, they are fully supported, so you can use them if the opportunity arises. If you are still figuring things out though, just go with classes they will likely cover 99% of the cases.

    Depending on your needs you might be able to get away with something easier though.

    If your data objects don't have nested properties (properties which are objects or arrays with more data in them), you can rather easily use Object.assing to create a new object with the properties from a list objects.

    Object.assign(
    // the new empty object were all the properties will be applied
    {}, 
    // The first source object to copy properties from
    {
    	x: 0,
    	y: 1,
    	name: "foo"
    },
    // The second source object to copy properties from
    {
    	name: "bar"
    	damage: 5
    }
    // As many source objects as needed can be added
    );
    

    Something like that, will create a new object that looks like this:

    {
    	x: 0,
    	y: 1,
    	name: "bar",
    	damage: 5
    }
    

    The properties of the first source object are copied into the target (first empty object), then the properties of the second source objects are applied onto it, any existing properties are overwritten and new ones are added.

    Using this approach you can allow the player to select a base item, then a specific one, merge them and the result becomes the new item.

  • Not really sure exactly how you plan to save and load all the data

    I will save to and load them from Mongodb using the Realm Web SDK.

    Depending on your needs you might be able to get away with something easier though.

    If your data objects don't have nested properties (properties which are objects or arrays with more data in them), you can rather easily use Object.assing to create a new object with the properties from a list objects.

    I think I will need nested objects. One of the templates could look like this:

    {
    	templates: {
    		"weapons": {
    			"background_color": "100,0,0",
    			"name": {
    				"x": 25,
    				"y": 5,
    				"font_size": 16,
    				"font_style": "bold"
    			},
    			"picture": {
    				"x": 5,
    				"y": 20,
    				"width": 50,
    				"height": 50
    			},
    			"text": {
    				"x": 10,
    				"y": 100,
    				"font_size": 10,
    			}
    		}
    	}
    }

    I do not know beforehand how many of these properties a template will have because the player can insert more than one text or more pictures in the items.

    Using this approach you can allow the player to select a base item, then a specific one, merge them and the result becomes the new item.

    This sounds like what I'm trying to do. Too bad .assign doesn't work with nested objects. It looks clean and simple without 2 huge code blocks just to link an object to another one.

    Thank you again for the example! I looked into classes. They seem to be almost the same thing as Prototypes. Maybe better readable.

    Now I wonder if I'm overcomplicating things and if I really need this. Or if I should just store the templates as a JSON in a document inside Mongodb and just create all the text objects, sprites etc. from the selected template and then just let the player be able to edit from there.

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