4

So after reading massively into JS the past few days (I'm just starting with it) I have come upon 3 viable options for my project, which is a game btw. There will be about 200 items in my game, with a total of about 30 stats/properties. But since the program has to know that a Sword doesn't give Spell damage than I have to give each item all those 30 properties even if 90% will be 0. So here is what I came up with, any advice is greatly appreciated:

var prop, obj = { Item1: "Boots", Item2: "Gloves", Item3: "Sword", Item4: "Cape" };

// Pretty sure I'd have to remake this somehow to put properties in there, this might not be as useable

function Item(hp, mp, dmg, spd, luk) {
    this.hp = hp;
    this.mp = mp;
    this.dmg = dmg;
    this.spd = spd;
    this.luk = luk;
}
var BigSword = new Item(0, 0, 50, 20, 10)

//I think this might be my best option so there are as few variables as possible? or does that not matter as much? I figured with this option whenever I update totalHp and totalMp and totalDmg etc in the updating function I can create a local variable called theItem = BigSword and then just do theItem.hp, theItem.mp and that way it doesn't have to search much for the variable and should run relatively faster? Sorry for the newbie question but does JS even have local variables in functions? As in if I do var theItem = whatever, then theItem will be null outside the function?

itemNames = [ "Boots", "Gloves", "Sword", "Cape" ];
itemHp = [ 0, 0, 0, 50 ];
itemMp = [ 0, 30, 0, 0 ];
itemDmg = [ 0, 0, 50, 0 ];
itemSpd = [ 50, 0, 0, 0];

//This is the other option that I came up with, a little uglier but if it's faster or better to just use arrays I don't mind that much.

But please keep in mind, like I said, 200~ish total items, each item will have around 30 properties. What do you think?

Thanks a lot for reading and for any information provided, it's greatly appreciated! Thanks in advance

Hate Names
  • 1,596
  • 1
  • 13
  • 20
  • 1
    The performance hit is what you should be focusing on, look at how many arrays you would have to access to get the values. – epascarello May 31 '13 at 01:28
  • That is actually pretty obvious when you put it like that. I guess I was so focused on learning as much as JS as possible that I forgot to think logically lol. Very good, and obvious, point. – Hate Names May 31 '13 at 01:36

3 Answers3

4

Your best bet is to have a constructor, as you have in your first example. However, I'd change a few things. First of all, for the constructor, you're simply passing in a lot of numbers. This is bad, because it's very easy to forget the order in which your numbers go. A better way to go would be to pass in an object to your constructor, so you can label each property:

function Item(props) {
    this.hp = props.hp;
    this.mp = props.mp;
    this.dmg = props.dmg;
    this.spd = props.spd;
    this.luk = props.luk;
}

var BigSword = new Item({
    hp: 0, 
    mp: 0, 5
    dmg: 0, 
    spd: 20, 
    luk: 10
});

This is nice, but still a pain, because you have all sorts of different items, and as you said, you'd have to define 30 properties for each item, which gets both messy and time-consuming. At this point you get into the realm of more complex object oriented stuff. From here you have basically two options: inheritance and construction.

Inheritance

Using object inheritance to properly define objects is one probably the more common of the two, and is fairly straightforward. In essence, you have a "class" of object, and then sub-classes of each class. So you might have Magical Items and Non-Magical Items as two classes. If you had a magic belt, perhaps, you'd want to make it inherit the properties of the Magical Item class. On the other hand, if you had a basic un-charmed sword, you'd want to make it inherit from the Non-Magical Item class.

But say you have magical scrolls and magical potions. Those are both magical items, right? So you'd want to make a class called Potions and a class called Scrolls, which both inherit from the Magical Item class. Then you might have certain types of potions. Healing potions, maybe--"Magical Potion of Heal Allies" and "Magical Potion Of Heal Self". So you'd need different classes for those--and so on and so forth.

Inheritance in Javascript can be done a number of different ways and it's possible to get very in-depth, so I'm not going to discuss it in my post. Here are a few useful links to get you started with inheritance, though, if you want to go that route:

Composition

Composition is a concept that borrows heavily from other loosely-typed languages, such as Python, which employs it quite extensively. The basic idea behind composition is that you have a base object class, and whenever you need a certain specific type of object, you add behaviors, or members, to that base class. This isn't quite as well-known as inheritance, but it's definitely the one I prefer.

In Javascript, it works by having a base constructor, Item, and then having other constructors which add the necessary behaviors to your Item. Let's take a look at the example I used for composition--creating a Magical Potion of Heal Allies. You have several distinct properties here: Magical Item, Potion, Healing. With inheritance you'd do something like Item -> Magical -> Potion -> Healing Potions -> Allies. However, with composition, you can add several behaviors to a base Item class, without having to set up a huge prototype chain: Affect Allies, Potion, Healing.

Since composition is a bit simpler than inheritance (and, I'll admit it, I'm biased) I'll set up a quick example in psuedo-code:

// base item class
function Item(props) {
    this.someProperty = props.someProperty;
    this.someOtherProperty = props.someOtherProperty;
}

// potion behavior
function Potion(props) {
    this.amount = props.amount; // IDK what amount means, just some random potion property
    this.color = "green";
}

// healing behavior
function Healing(props) {
    this.amountToHeal = props.amountToHeal;
    this.cooldown = props.cooldown;
}

// behavior to affect allies
function AffectAllies(props) {
    this.allies = props.allies;
    for(ally in this.allies) {
        this.allies[ally].affect(props.affact);
    }
}

// at this point we have the various behaviors set up and we can create the Magical Potion of Heal Allies constructor:

function MassHealingPotion(props) {
    var self = this;

    this.amount = props.amount;
    this.potion = new Potion(props);
    this.effect = new Healing(props);
    this.AffectAllies = new AffectAllies({
        affect: function(ally) {
            self.potion.affect;
        },

        allies: player.allies;
    });
}

// you can now create a mass healing potion:
var potion = new MassHealingPotion({
    weight: 50,
    someProp: "someValue",
    someOtherProp: "someOtherValue"
    // and so on and so forth with whatever properties you want the potion to have
});

Well, that turned out a bit longer than I expected and probably contains proportionally more errors than I'd like, but I hope that conveys the basic idea of composition.

Now, simpler object creation isn't even the best part of composition, which is that you can re-use different behaviors. Consider you have a magical sword that whenever you make an attack it heals your allies. All you have to do is give it the Healing member and the AffectAllies member and boom--magical sword of heal buddies. With inheritance, you'd have to create a Swords class in the Magical Items class (and then you'd have two different Swords classes-one for Non Magical Swords and the other for Magical Swords! Ew!), then extend that with Healing Swords, and so on and so forth.

You can go either way, inheritance or object composition. Both are equally effective for what you want to achieve.

But what about performance?

200 items with 30 properties a piece? Not a problem. Stick them all in one giant array/object, boil 'em, mash 'em, stick 'em in a stew. The browser don't care. Your best bet is probably an object, though:

var itemList = {
    bigSword: new BigSword(...);
    smallSword: new SmallSword(...);
}
Elliot Bonneville
  • 51,872
  • 23
  • 96
  • 123
  • Wow..I can't thank you enough for taking the time to write in so much detail explaining everything to me. You are the most awesome person ever =D. Thank you so much, really, can't thank you enough. This is really helpful, thank you so much! – Hate Names May 31 '13 at 01:50
  • It helps so much that I wish I could upvote you 100 times. I really can't thank you enough, this is beyond amazing. Thank you a million times for taking the time to write all that!! – Hate Names May 31 '13 at 02:03
2

I would prefer Objects. I would start with a simple, generic "Item" and then build specific items by "inherit" from the generic one with prototyping.

That probably may reduce code redundancy and increase maintainability dramatically.

Speedwise I don't have a clue but I think iterating through 200*30 array values isn't also that fast.

Axel Amthor
  • 10,980
  • 1
  • 25
  • 44
  • Thank you very much for your post and input. Sorry for the delayed reply, I wanted to read into prototyping so I don't reply with no knowledge about the it. Here is a very interesting post which explains prototyping more in case others are interested: http://stackoverflow.com/questions/4650513/why-is-javascript-prototyping . Thank you very much for your help! – Hate Names May 31 '13 at 01:42
2

You need to do a serious design effort first. If you just start coding (as many developers do), you will only get so far and realise your design has a fundamental flaw and the application needs to be rewritten. That doesn't matter in the early stages, but once you've written a few hundred lines of code it gets quite tedious.

By all means write code to prototype things, but all you should expect to get from it are design hints, the code should be thrown away.

Your items list (or catalogue) should be an object with methods to add, remove and update items. Each player (character, avatar, whatever) then just needs a list of their items and their state. There should be a global update damage or health or whatever function that gets items of a specific type and applies them to players of a specific type (e.g. weapons damage enemies, food revives the player and friends, etc.).

Only once you know all the players and items and their attributes and actions, you can start to design the interfaces and methods, and finally write some code.

Keep your eye on the objective, which should be to develop an engaging game, not to just write a few thousand lines of code.

RobG
  • 142,382
  • 31
  • 172
  • 209
  • Makes a lot of sense. Thanks for giving me advice on what steps I should take first. You are definitely right that doing this first will save me so much later, thanks again. – Hate Names May 31 '13 at 01:53