1

I am working on a game using javascript/html. I have many buttons, all of them are using the same function but with different values inside them.

I have 32 buttons which means 32 functions, those functions do exactly the same thing, except that they use different variables/values.

I was thinking about using objects/arrays, and put a function inside an object then reuse it changing its variables but I dont know if thats possible, or if it's a good idea.

I am still new at this. Those buttons are used to "attack" a monster, each of them is different i.e. "stats/health/damage".

My buttons are called "attack1/attack2/" and functions "attack1/attack2". Everytime I want to add a monster, I copy whole function and change its values which is not hard, but considering I want to change damage formula I need to change all 32 functions which isn't what I want to do.

I already created an object where I store all monsters data using arrays.

Lastly, I am not a native English speaker, sorry if you can't understand me. Let me know if there is any way I can help you understand it better.

Thanks

var monsterStats = {
killed: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0],

hp: [10, 30, 70, 130, 190, 280, 380, 500, 700, 900, 1300, 1600, 2200, 2600,
3000, 4000, 5000, 7000, 9000, 12000, 15000, 18000, 22000, 28000, 34000, 40000,
48000, 570000, 65000, 72000, 80000, 88000],

maxHp: [10, 30, 70, 130, 190, 280, 380, 500, 700, 900, 1300, 1600, 2200,
2600, 3000, 4000, 5000, 7000, 9000, 12000, 15000, 18000, 22000, 28000, 34000,
40000, 48000, 570000, 65000, 72000, 80000, 88000],

def: [0, 2, 4, 6, 9, 13, 18, 25, 30, 38, 45, 53, 65, 75, 88, 95, 120, 140,
170, 200, 220, 250, 300, 400, 500, 700, 1000, 1200, 2000, 2500, 3000],

minDmg: [2, 2, 4, 6, 9, 13, 18, 25, 32, 40, 50, 60, 75, 86, 96, 105, 140,
160, 200, 230, 260, 290, 350, 420, 500, 900, 1200, 1700, 2500, 3200, 4500,
6000],

maxDmg: [3, 5, 7, 10, 14, 19, 23, 30, 37, 45, 58, 67, 80, 92, 100, 110,
160, 185, 215, 250, 275, 320, 380, 550, 700, 1200, 1500, 2200, 3000, 4000,
5500, 8000],

baseExp:[5, 10, 30, 50, 90, 140, 190, 260, 340, 450, 560, 700, 810, 940,
1060, 1200, 1600, 2150, 2600, 3400, 5000, 7000, 10000, 15000, 23000, 35000,
70000, 120000, 180000, 290000, 430000, 680000, 1000000]

};

function attack(number) {
if (monsterStats.hp[0] >= 1) {
    var damage = Math.floor(Math.random() * (maxdamage - mindamage + 1)) +
        mindamage;
    damage = Math.floor(damage - monsterStats.def[0] * 1.2);
    if (damage > 1) {
        monsterStats.hp[0] -= damage;
        document.getElementById("hp1").innerHTML = monsterStats.hp[0];
        Log("You deal " + damage + " <span style=\"color:blue\">damage</span>");
    } else Log("<span style=\"color:blue\">Enemy block your attack! </span>");
    var dmg = Math.floor(Math.random() * (monsterStats.maxDmg[0] - monsterStats.minDmg[0] + 1)) + monsterStats.minDmg[0];
    dmg = Math.floor(dmg - defense * 1.2);
    if (dmg > 1) {
        health = health - dmg;
        document.getElementById("health").innerHTML = health;
        Log("Enemy hit you for " + dmg + " <span style=\"color:red\">damage</span>");
    } else Log("<span style=\"color:green\">You blocked enemy attack! </span>");
    if (health < 1) {
        monsterStats.hp[0] = monsterStats.maxHp[0];
        health = maxhealth;
        document.getElementById("hp1").innerHTML = monsterStats.hp[0];
        document.getElementById("health").innerHTML = health;
        Log("<span style=\"color:blue\">You have lost!</span>");
    }
    if (monsterStats.hp[0] < 1) {
        monsterStats.killed[0] = monsterStats.killed[0] + 1;
        monsterStats.hp[0] = monsterStats.maxHp[0];
        document.getElementById("hp1").innerHTML = monsterStats.hp[0];
        document.getElementById("kills1").innerHTML = monsterStats.killed[0];
        var expgain = monsterStats.baseExp[0] / (level / 5);
        if (experience < maxexperience) {
            experience = Math.floor(experience + expgain);
            if (experience >= maxexperience) {
                level += 1;
                stats += 2;
                experience = experience - maxexperience;
                maxexperience = Math.floor(maxexperience * 1.2);
                Log("You leveled up! Your current level is: " + level);
                document.getElementById("maxexperience").innerHTML = maxexperience;
                document.getElementById("level").innerHTML = level;
                document.getElementById("stats").innerHTML = stats;
                document.getElementById("experience").innerHTML = experience;
            } else Log("You gain: " + Math.floor(expgain) + "experience!");
            document.getElementById("experience").innerHTML = experience;
        }
        var goldLog = 0;
        var golddrop = Math.floor((Math.random() * 100) + 1);
        if (golddrop > 95) {
            golddrop = Math.floor((Math.random() * 20) + 1);
            gold = gold + golddrop;
            Log("You loot: " + golddrop + "gold!");
            document.getElementById("gold").innerHTML = gold;
        } else if (golddrop >= 75) {
            golddrop = Math.floor((Math.random() * 10) + 1);
            gold = gold + golddrop;
            Log("You loot: " + golddrop + "gold!");
            document.getElementById("gold").innerHTML = gold;
        } else if (golddrop >= 60) {
            golddrop = Math.floor((Math.random() * 5) + 1);
            gold = gold + golddrop;
            Log("You loot: " + golddrop + "gold!");
            document.getElementById("gold").innerHTML = gold;
        }
        "This is <span style=\"color:red\">RED</span> text.";
        var itemdrop = Math.floor((Math.random() * 100) + 1);
        if (itemdrop < 33) {
            var fusiondrop = Math.floor((Math.random() * 100) + 1);
            if (fusiondrop < 70) {
                common = common + 1;
                Log("You loot:<span style=\"color:grey\">Common</span> Fusion stone!");
                document.getElementById("common").innerHTML = common;
            } else if (fusiondrop <= 100) {
                rare = rare + 1;
                Log("You loot:<span style=\"color:blue\">Rare</span> Fusion stone!");
                document.getElementById("rare").innerHTML = rare;
            }
        } else if (itemdrop < 66) {
            var expdrop = Math.floor((Math.random() * 100) + 1);
            if (expdrop < 70) {
                commonexp = commonexp + 1;
                Log("You loot:<span style=\"color:grey\">Common</span> Exp orb!");
                document.getElementById("commonexp").innerHTML = commonexp;
            } else if (expdrop <= 100) {
                rareexp = rareexp + 1;
                Log("You loot:<span style=\"color:blue\">Rare</span> Exp orb!");
                document.getElementById("rareexp").innerHTML = rareexp;
            }
        } else {
            var golddrop = Math.floor((Math.random() * 100) + 1);
            if (golddrop < 70) {
                commongold = commongold + 1;
                Log("You loot:<span style=\"color:grey\">Common</span> Gold orb!");
                document.getElementById("commongold").innerHTML = commongold;
            } else if (golddrop <= 100) {
                raregold = raregold + 1;
                Log("You loot:<span style=\"color:blue\">Rare</span> Gold orb!");
                document.getElementById("raregold").innerHTML = raregold;
            }
        }
    }
}

}

Thats a part of the code, I use this code 32 times.

4
  • This is what function arguments are for. Commented Jan 2, 2015 at 7:50
  • Exactly what @Barmar said. Instead of using attack1() and attack2(), you can simplify it to attack(1); and attack(2); Commented Jan 2, 2015 at 7:51
  • 2
    You can have a single function named attack(id), when user clicks button1, call the function by passing the appropriate id, attack(1). Let the code inside the attack function create a monster and add it to the global array, array.push(monster). Having said this, please post the relevant code, what you have tried, so that it can be corrected and improved.. Commented Jan 2, 2015 at 7:52
  • Hey, thanks for answers, I put the code in my question. I am not sure why I would use array.push(monster). Let me know if my code help you understand my problem. Commented Jan 2, 2015 at 8:11

3 Answers 3

2

I think you're looking for something like this:

function createAttack1(damage) {
    return function() {
        ... Your attack1 logic using 'damage'
    }
}

Then you can use this to hook up your buttons:

button1.addEventListener("click", createAttack1(5));
button2.addEventListener("click", createAttack1(10));
button3.addEventListener("click", createAttack1(15));

This allows you to reuse the same core logic, while having different stats without all the copy/paste you've been doing.

Sign up to request clarification or add additional context in comments.

9 Comments

Hey, I am new with javascript, could you show me, how would you add "monster2" to the function? and how would you change actual values inside that function? Let's take part of my function monsterStats.hp[0] -= damage; How can I change hp[0] and use hp[1] instead?
This is a good article to read: developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures Once you understand the closure/wrapper concept, you should be able to do what you want.
I have a question, addEventListener you add "creatureAttack1(5)...What if I have "function creatureAttack1(myObject.kills[], myObject.hp[]) is something like that possible? so I can change addEventListener and change all values at the same time?
Yes. You can have as many parameters as you'd like. As others have mentioned, I'd recommend changing how you store the monster data. You have kills[32], hp[32], etc. representing the 32 monsters. You have the data stored in column format, which is more difficult to understand and manage. Change the data to a row format where you have an array of monster objects: monsters.push({killed: 0, hp: 10, maxHp: 10, ... }); This way, you can simply pass around a monster data object. It'll make things easier when hooking up your buttons as well.
so instead of var = {monster:[1, 2, 3, 4], hp:[10, 20, 30, 40]} (1 first monster i.e. "first button" and instead store each monster in single object? like var monster1 = {kill:0, hp:10, maxhp:10}, var monster2 = {kill:0, hp:20, maxhp:20} something like that? but then, how would I make a function argument? if I use different objects, I cant make "function creatureAttack1(monster1 object) what about monster 2 then? etc and that button1.addEventListener, "button1" is button id? and "click" is just some kind of function which means i click a button?
|
0

Let say you create an array of Monster "objects" like this:

var Monsters = {
    "foo": {"name":"Foo the foot", "hp":125, "power":3},
    "bar": {"name":"Barbarian the bar", "hp":25, "power":9001}
};

You may as well write your button markup so each one can be related to one monster. For example:

<button rel="attack" data-monster_id="foo">Attack</button>
<button rel="attack" data-monster_id="bar">Attack</button>

Now, you may link them with something like that:

var btns = document.querySelectorAll('button[rel="attack"]');
for (var i=0; i<btns.length; i++) {
    this.addEventListener('click', function(){
        attack(this.dataset.monster_id);
    }, false);
}

Finally, let assume an attack method that would go like this:

function attack(id) {
    Monsters[id].hp -= currentDamage;
    // whatever consequences the attack may have
}

Hope this gives you the idea and good luck with your game :)

3 Comments

Hey, I will consider using this, if I figure out how this code works completely before I make some mistakes in my code. Thanks for an answer.
From my previous experiences, fast is slow and slow is fast. I mean, if you really take your time to create your architecture, it will go just fine and you won't regret it when the time is right for your code to get bigger. A common mistake is trying to do everything at the same time, with a code that is so short that it cannot be expanded.
Hey, I understand that :) That's why I decided to change it while there isn't much of the code, at least not as much as I want to add later.
0

Not sure what you mean, but I think using event delegation may help to reuse a function. In the snippet example, a data-* attribute is used to store a score with a button. Furthermore event delegation enables you to create new buttons without having to assign new handlers.

document.querySelector('#testbuttons').addEventListener('click', testdemo);
document.querySelector('#testcreate').addEventListener('click', newbttn);

// handler for all buttons within div#testbutton
function testdemo(e) {
  var from = e.target || e.srcElement
     ,score = from.getAttribute('data-score')
     ,kills = JSON.parse(from.getAttribute('data-kills'));
  if (!score) { return true; }
  Helpers.log2Screen('score clicked button: ', score, 
                     ', kills: <code>[', kills, ']</code>',
                      {clear: true});
}

function newbttn() {
  var score = Math.floor(1+Math.random()*200);
  document.querySelector('#testbuttons').innerHTML +=
    '<br><button data-score="'+score+'" data-kills="[]">button '+score+'</button>';
  Helpers.log2Screen('Created new button with score ', score, {clear: true});
}
button {
  margin-top: 3px;
}
<!-- a few helpers -->
<script src="http://kooiinc.github.io/JSHelpers/Helpers-min.js"></script>

<div id="result"><p>Awaiting action ...</p></div>
<div id="testbuttons">
  <button data-score="12" data-kills="[2,5,3]">bttn 12</button><br>
  <button data-score="122" data-kills="[0,2,8]">bttn 122</button>
</div>

<button id="testcreate">create new button</button>

8 Comments

Hey, thanks for the answer, but I am new to this, and your code is too complicated to me :/ I understand some of it, but I have no idea how I would actually use it with my code. Still thanks for an answer.
After reading it few times, I understand how it works, more or less, but in my case my buttons are spread all over the html page, so I am not sure If I can put them inside "div id ="testbuttons". In that case I would have to create more "querySelectors" which means more functions right? Still that would allow me to use much less code, I will consider using your method, if any other wont work for me, thanks again. Or actually, I can use the same div id in different places right? Then that could possibly work for me but I need a way to change function variables depending on a button I press.
If you can't use event delegation, the other half of the idea - storing stuff within the button element using data-* attributes - may still enable you to reuse just one function. See developer.mozilla.org/en-US/docs/Web/Guide/HTML/…
Thanks for the link, I wil check it out.
By the way, you can assign the event handling to document.body if the buttons are scattered over the page. The method testdemo in the snippet doesn't prevent that, it only runs if a data-score attribute is found.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.