6
\$\begingroup\$

I have completed this simple death battle game with Javascript. Basically, the game will have 2 characters who will be attacking each other until one dies. That's it. Just wondering, how can I refactor my code further to reduce the code repetition in this program?

   var superman = {
        life: 10,
        isAlive: true,
        attack: function () {
            return Math.floor(Math.random() * 3);
        }
    };

    var batman = {
        life: 10,
        isAlive: true,
        attack: function () {
            return Math.floor(Math.random() * 3);
        }
    };

    $('#supermanLife').text(superman.life);
    $('#batmanLife').text(batman.life);

    const playGame = () => {
        init();
        debugger
        fight();
        function fight() {
            setTimeout(function () {
                // while both still alive, figth each other.         
                //while (superman.isAlive && batman.isAlive) {

                var whoAttack = Math.floor(Math.random() * 2);
                if (whoAttack === 0) {
                    // superman attack batman

                    // if attack is zero, enemy avoided attack.
                    if (superman.attack === 0) {

                    } else {
                        batman.life = batman.life - 1;
                    }

                    if (batman.life <= 0)
                        batman.isAlive = false;

                    showHeroLife();
                } else {
                    debugger
                    // batman attack superman
                    // if attack is zero, enemy avoided attack.
                    if (batman.attack === 0) {

                    } else {
                        superman.life = superman.life - 1;
                    }

                    if (superman.life <= 0)
                        superman.isAlive = false;

                    showHeroLife();
                }

                checkEndGame();
                //}
                if (superman.isAlive && batman.isAlive)
                    fight();
            }, 1000);
        }
    }

    const showHeroLife = () => {
        $('#supermanLife').text(superman.life);
        $('#batmanLife').text(batman.life);
    }

    const checkEndGame = () => {
        if (superman.isAlive === false || batman.isAlive === false) {
            console.log('Game Over');

            if (superman.isAlive) {
                $('#gameResult').text('Superman killed Batman with X-Ray laser vision.');
                console.log('Superman win');
                $('#heroBatman').fadeTo(1000, 0.2); // fadeOut
            }
            else {
                $('#gameResult').text('Batman killed Superman with Kryptonite spear.');
                console.log('Batman win');
                $('#heroSuperman').fadeTo(1000, 0.2); // fadeOut
            }
        }
    };

    const init = () => {
        $('#gameResult').text('');

        superman.life = 10;
        superman.isAlive = true;
        $('#heroSuperman').fadeTo(2000, 1);

        batman.life = 10;
        batman.isAlive = true;
        $('#heroBatman').fadeTo(2000, 1);
    };
 div#main {
        max-width: 500;
        margin: 0 auto;
        font-size: 2em;
        text-align: center;
    }

 div#heroContainer {
        margin-top: 20px;
        display: flex;
        justify-content: space-between;
    }

 img.hero {
        height: 200px;
        width: 200px;
        border-radius: 50%;
    }

 button {
        font-size: 2em;
        margin-top: -40px;
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='main'>
    <button onclick="playGame()">Fight!</button>
    <div id='heroContainer'>
        <div id='heroBatman'>
            <img src="Img/batman.jpg" class='hero'>
            <br>Life: <span id='batmanLife'></span>
        </div>

        <div id='heroSuperman'>
            <img src="Img/superman.jpg" class='hero'>
            <br>Life: <span id='supermanLife'></span>
        </div>
    </div>

    <div id='gameResult'></div>
</div>

My source is in my github - ngaisteve1/DeathBattleGameJS

\$\endgroup\$
2
\$\begingroup\$

This would be a great opportunity to explore es6 classes.

  1. create a Fighter class that contains the basic attributes and methods for a fighter/hero
// for example:
class Fighter {
  name = '';
  life = 10;
  get isAlive() {
    this.life > 0;
  }

  constructor({ name = null}) {
    if (!name) {
      throw new Error('A hero needs a name!');
    }

    this.name = name;
  }

  attack() {
    //...
  }
  takeDamage(amount) {
    //...
  }
}

2 . When creating a new game create instances of your fighter / heros.

const batman = new Fighter({ name: 'batman'});
batman.attack() // etc...
  1. Consider that your game function is more like a match, and think how this could be created as a class. Each match class should decribe the lifecycle of the round.

  2. Try to separate out things that affect the DOM and things that are just data. The messages about who got killed for example, are all just text. your match could call a single function with a message and type (if for example you wanted to style different types of messages). A good way to keep things clear would be to have a class, or just an object or group of methods that are only responsible for rendering the view.

    • a another good example is the checkEndGame. This function should only care about changing the state of the game, and not updating the DOM
  3. For readability try avoiding nested conditional statements, the inner block can usually be refactored out to be methods / or functions. Essentially you should divide the game logic, from the "view"

  4. If you start to think about some basic enhancements, such as having random skill and luck settings for your heros that affect the attacks, or amount of damage taken, or for example being able to generate a number of heros for a battle royale, your current approach will begin to become hard to manage.

While all of the above is perfectly possible without classes, it's like a good use case for them, and a nice way to explore them.

Hope that helps.

\$\endgroup\$
  • \$\begingroup\$ Excellent code review. I will try those pointers. Thanks a millions 😊 \$\endgroup\$ – Steve Ngai Jun 30 at 22:01
  • \$\begingroup\$ Any example of how to split view and logic? \$\endgroup\$ – Steve Ngai Jul 1 at 14:01
  • 1
    \$\begingroup\$ I would suggest creating another class, or group of functions, that only take data, and updaate the DOM, ie: renderPlayer(playerName) { //...only touch the DOM in these functions } \$\endgroup\$ – bigmadwolf Jul 11 at 10:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.