Part 4 (Final) – Building a Simple JavaScript Game

To this point we have a hero and we have an enemy… now we need a fight!   We will update the world tick to include a step to evaluate the need to fight

// world tick event
function tickEvent() {
 spawnEnemy();
 fight();
}

Now we need to declare this function and put some interesting elements in here to make the hero battles interesting.  We will provide an initial roll to see who the attacker will be.  It will be more interesting if there is a 50/50 chance of the attacker being the hero or the enemy versus a very predictive back and forth battle.  So let’s code this:

// the battle function
function fight() {
   console.log(' ');
   // enemy present, fight.
   var attacker = {};
   var defender = {};

   if (roll(0,1) == 1) {
     // if roll is 1, then the attacker is the Hero
     attacker = hero;
     defender = mob[0];
   } else {
     // if roll is 0, then the attacker is the Mob
     attacker = mob[0];
     defender = hero;
   }
}

 

Now, the attacker and defender are defined in the function let’s provide a text status and get the 0 to 20 roll for the attacker and the defender:

console.log('[' + attacker.name + '] is attacking ' + defender.name + '...');

var attackerRoll = roll(0,20);
 var defenderRoll = roll(0,20);

console.log ('[' + attacker.name + '] the attacker rolled: ' + attackerRoll);
 console.log ('[' + defender.name + '] the defender rolled: ' + defenderRoll);

 

We know the attackers roll and if it is Zero, they have missed their attack.  We can provide that basic If logic to contain the rest of the damage calculations.

if (attackerRoll == 0) {
   // miss
   console.log('[' + attacker.name + '] missed the Attack!!')
} else {
   
}

 

We can check the rolls now and if the defender roll is higher than the attacker, then the defender was able to block the attack.  This should work out but may produce some long battles.  We will see what happens.

 if (attackerRoll == 0) {
     // miss
     console.log('[' + attacker.name + '] missed the Attack!!')
 } else {
   if (defenderRoll > attackerRoll) {
     console.log('[' + defender.name + '] blocked the Attack!');
   } else {
      // hit for the attacker

   }
}

 

At this point we can see if the attacker has hit the opponent.  Let’s do a simple calculation to create and capture the damage.  We will do this in the  section labelled // hit for the attacker.   If the attacker and defender roll are equal we will add one to the number to ensure there is a small hit to move the fight forward.

var damage = attackerRoll - defenderRoll;
damage ++ // award one point hit if a draw.
console.log('[' + attacker.name + '] hit ' + defender.name + ' for +' + damage + ' damage!');

// issue the damage
if(attacker.name != hero.name) {
   hero.health -= damage;
} else {
   mob[0].health -= damage;
   if(mob[0].health > 0) {
     console.log('[' + mob[0].name + '] health is at ' + mob[0].health + ' of ' + mob[0].maxHealth);
   }
}

 

That should be sufficient for a simple fight that has enough randomness to be interesting.  The outcome of each battle should be fairly random.  This will track the attacks and various damage for the enemy and the hero but there is no check to see if one of them died in the battle.  Presently, this script would tick on for infinity and go deep into the world of negative health.  Let’s correct that with a new function that will be evaluated every world tick to check for death.

// world tick event
function tickEvent() {
 spawnEnemy();
 fight();
 deathCheck();
}
function deathCheck() {
 if(hero.health <= 0) {
   console.log('[' + hero.name + '] our hero has fallen in battle. Game over.');
 }

 if(hero.health > 0 && mob[0].health <= 0) {
  console.log(' ');
  console.log('[' + hero.name + '] has slain the ' + mob[0].name + '!!!');
  console.log(' ');
  console.log("*********************************************************");
  mob.splice(0, 1);
 }
}

That is pretty straight forward, if the hero health is less than or equal to zero then post a game over and if the enemy has the same, we will post a death and remove the enemy from the array with the splice command.  One house keeping item in the logic flow is if the hero has died, we should stop the world tick even.  We can do the same hero health check there or do a game over variable.  For now, I will just check the health:

function worldClock() {
  if (hero.health > 0) {
   tickEvent();
  }
 
  setTimeout(worldClock, world.clockInterval); 
}

 

We should track our hero’s kill count as he moves forward in battle.  Let’s add a place to store the value with the hero:

// our hero
var hero = {
 name: "Foff",
 health: 100,
 crit: 5,
 strength: 10,
 block: 50,
 kills: 0
};

Now we will just increment the kills in the deathCheck function

hero.kills ++;

And we will post the kills along the way so we can track the hero status.  While we are changing the deathCheck function we will put in a reward for a kill to prolong the life of our warrior as he progresses through the game.  For this initial reward, we will give the hero a +25 to his health to make things interesting.  Here is the revised function:

function deathCheck() {
 if(hero.health <= 0) {
 console.log('[' + hero.name + '] our hero has fallen in battle. Game over.');
 console.log('[' + hero.name + '] killed %s before death.', hero.kills);
 }

if(hero.health > 0 && mob[0].health <= 0) {
 console.log(' ');
 console.log('[' + hero.name + '] has slain the ' + mob[0].name + '!!!');
 console.log(' ');
 console.log("*********************************************************");

  console.log('[' + hero.name + '] has gained +25 health for the kill!');
  hero.kills ++;
  console.log('[' + hero.name + '] kills ' + hero.kills);
  hero.health += 25;
  mob.splice(0, 1);
 }
}

 

One thing of interest now that we have covered the death check would be how the hero health is doing after each attack.  A new function will be added to the world tick event and called to post this output.

// world tick event
function tickEvent() {
 spawnEnemy();
 fight();
 deathCheck();
 postHeroHealth();
} 

function postHeroHealth() {
  if (hero.health > 0) {
    console.log('[' + hero.name + '] health is at ' + hero.health);
  }
}

 

Here is our final code that pulls together all of the early battle logic:

var world = {
 clockInterval: 0,
};

// our hero
var hero = {
 name: "Foff",
 health: 100,
 crit: 5,
 strength: 10,
 block: 50,
 kills: 0
};

var orc = {
 name: "Orc", 
 health: 23,
 maxHealth: 23,
 crit: 1,
 strength: 5,
 block: 10
};

// the current mob we are battling
var mob = [];

function worldClock() {
 if (hero.health > 0) {
 tickEvent();
 }
 
 setTimeout(worldClock, world.clockInterval); 
} 

// world tick event
function tickEvent() {
 spawnEnemy();
 fight();
 deathCheck();
 postHeroHealth();
} 

// random roll function for the chance of the game
function roll(min, max){ 
 return Math.floor(Math.random() * (max - min + 1) + min); 
}

// spawn an enemy
function spawnEnemy() {
 if(mob.length == 0) {
 // no enemy, spawn one
 mob.push(new Object(orc));
 mob[0].health = mob[0].maxHealth;

 console.log("*********************************************************");
 console.log(' ');
 console.log("A new enemy " + mob[0].name + " has been spawned...");
 } 
}

// the battle function
function fight() {
 if(mob.length > 0) {
 console.log(' ');
 // enemy present, fight.
 var attacker = {};
 var defender = {};

 if (roll(0,1) == 1) {
 // if roll is 1, then the attacker is the Hero
 attacker = hero;
 defender = mob[0];
 } else {
 // if roll is 0, then the attacker is the Mob
 attacker = mob[0];
 defender = hero;
 }

 console.log('[' + attacker.name + '] is attacking ' + defender.name + '...'); 

 var attackerRoll = roll(0,20);
 var defenderRoll = roll(0,20);

 console.log ('[' + attacker.name + '] the attacker rolled: ' + attackerRoll);
 console.log ('[' + defender.name + '] the defender rolled: ' + defenderRoll);

 if (attackerRoll == 0) {
   // miss
   console.log('[' + attacker.name + '] missed the Attack!!')
 } else {
   if (defenderRoll > attackerRoll) {
     console.log('[' + defender.name + '] blocked the Attack!');
   } else {
     // hit for the attacker
     var damage = attackerRoll - defenderRoll;
     damage ++ // award one point hit if a draw.
     console.log('[' + attacker.name + '] hit ' + defender.name + ' for +' + damage + ' damage!');

     // issue the damage
     if(attacker.name != hero.name) {
       hero.health -= damage;
     } else {
       mob[0].health -= damage;
       if(mob[0].health > 0) {
         console.log('[' + mob[0].name + '] health is at ' + mob[0].health + ' of ' + mob[0].maxHealth);
       }
     }
   }
 }
 }
}

function postHeroHealth() {
 if (hero.health > 0) {
 console.log('[' + hero.name + '] health is at ' + hero.health);
 }
}

function deathCheck() {
 if(hero.health <= 0) {
 console.log('[' + hero.name + '] our hero has fallen in battle. Game over.');
 console.log('[' + hero.name + '] killed %s before death.', hero.kills);
 }

 if(hero.health > 0 && mob[0].health <= 0) {
 console.log(' ');
 console.log('[' + hero.name + '] has slain the ' + mob[0].name + '!!!');
 console.log(' ');
 console.log("*********************************************************");

 console.log('[' + hero.name + '] has gained +25 health for the kill!');
 hero.kills ++;
 console.log('[' + hero.name + '] kills ' + hero.kills);
 hero.health += 25;

 mob.splice(0, 1);
 }
}



// start the world clock ticking along
worldClock();

 

 

That is it!  Now we can have an early battle.  Let’s call node and run our script to see how our hero does in battle.  Here is an abbreviated output of the end of our battle:

...

[Foff] is attacking Orc...
[Foff] the attacker rolled: 0
[Orc] the defender rolled: 15
[Foff] missed the Attack!!
[Foff] health is at 2

[Foff] is attacking Orc...
[Foff] the attacker rolled: 18
[Orc] the defender rolled: 10
[Foff] hit Orc for +9 damage!

[Orc] health is at 3 of 23
[Foff] health is at 2
[Foff] is attacking Orc...
[Foff] the attacker rolled: 5
[Orc] the defender rolled: 13
[Orc] blocked the Attack!

[Foff] health is at 2
[Orc] is attacking Foff...
[Orc] the attacker rolled: 20
[Foff] the defender rolled: 10
[Orc] hit Foff for +11 damage!

[Foff] our hero has fallen in battle.  Game over.
[Foff] killed 92 before death.

 

Not bad!  He slaughtered 92 before his demise!  I may shelve this project for a bit and move on to something else but we have a very simple game that we could continue to expand and adapt to make it even more interesting in the future.  I hope you have liked tracking the progress of this and please send over your recommendations for next steps and modifications that could be made!

Thanks!

 

Advertisements

About b.hedge

i do database stuff and i like to solve business problems with code.
This entry was posted in coding, node js, random and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s