Weekend Hack - 'Balloon Burst Game' using jQuery

SWASTIK PAREEK   |  24th June, 2015

jQuery is often used on websites to enhance the user experience and to make the page interactive. Recently, I was trying to integrate gravitational equations to the DIV elements of the DOM and ended up the rabbit hole which resulted in this simple game Balloon Burst game. The game is simple! you click on balloons to increase your score from a heap of randomly moving balloons and bombs. High speed balloons gives more points and clicking a bomb will result in GAME OVER! Number of balloons increase with time and you can also configure things like speed etc before staring the game. I thought, why not write about my experience -- below is a rundown of creating the game.

I started with setting up the initial DOM structure and give some styling to it. In the document.ready() function initialize the global variables for configuring the movement.

var marks_factor = 5; // Marks multiplying factor 
var max_limit_items = 40; // Max limit for items to render on page
var max_diameter = 90; // Max limit for balloon diameter
var diameter = 50, // Setting up default value
  max_items = 10,
  probability = 80,
  max_speed_limit = 10,
  min_speed_limit = 3;

To get a random number we will simply use Math.random() function which is predefined in jQuery and to have a random number between a range of values, we will play with this function a little bit 

function getRandomNumber(min, max) { // To generate random speed between between max and min rage of speed for the created balloons

      return Math.floor(Math.random() * (max - min) + min); // Get difference of max and min and select a random number and add the lower bound to get the result

    }

This function will return a random integer between min and max values. Another simple function using Math.random() which will return a random direction string

function getRandomDirection() { // To generate random direction for the created balloons
  var decidingUnit = Math.floor(Math.random() * 100) % 4;
  if (decidingUnit === 0) {
    return 'top-left'; // 45 deg
  } else if (decidingUnit === 1) { 
    return 'top-right';
  } else if (decidingUnit === 2) {
    return 'bottom-left';
  } else if (decidingUnit === 3) {
    return 'bottom-right';
  }
}

createItem() function to create a random number based on the probability variable

var createItems = function() { //Creating a balloon at random positions
  var left = getRandomNumber(0, $(window).width() - diameter); // Random left position
  var top = getRandomNumber(0, $(window).height() - diameter); // Random top position
  var $newObj;
  var speed = getRandomNumber(min_speed_limit, max_speed_limit);
  if (getRandomNumber(0, 100) < probability) {
    $newObj = $('<div>', {
      class: 'ball gravity-enabled',
      style: 'width : ' + diameter + 'px; height: ' + diameter + 'px; top : ' + top + 'px ; left : ' + left + 'px; background-color : rgb(' + getRandomNumber(0, 255) + ', ' + getRandomNumber(0, 255) + ' ,' + getRandomNumber(0, 255) + ');',
      'data-speed': speed
    }); // Creating a DOM object and assigning random css values to it
  } else {
    if ($('.bomb').length < Math.floor(max_items / 5)) { // Render bombs only when screen has less than 20% (1/5) of bombs
      $newObj = $('<div>', {
        class: 'bomb gravity-enabled',
        style: 'width : ' + diameter + 'px; height: ' + diameter + 'px; top : ' + top + 'px ; left : ' + left + 'px',
        'data-speed': speed
      });
    } else {
      $newObj = $('<div>', {
        class: 'ball gravity-enabled',
        style: 'width : ' + diameter + 'px; height: ' + diameter + 'px; top : ' + top + 'px ; left : ' + left + 'px; background-color : rgb(' + getRandomNumber(0, 255) + ', ' + getRandomNumber(0, 255) + ' ,' + getRandomNumber(0, 255) + ');',
        'data-speed': speed
      });
 
    }
  }
  $('body').append($newObj);
  updatePosition($newObj, getRandomDirection(), speed); // binding random speed and direction to the newly created object
};

Considering only 4 directions for now. createItems() function will create a random item (balloon or a bomb according to the probability given by the user). The reason of storing the speed of the div in the markup is to calculate the score when the balloon bursts( click event). Since the newly created element will be a jQuery object, so creating a jQuery object variable using '$'.  That means every time createItem() will get called, a new DIV element will be appended to the body with a random position through css. Note here, balloons need to have position absolute to get rendered at the random positions on the screen. Don't worry about the global variables values that will be fetched from the user from the initial screen. Fetching and setting variables for the functions through input screen-

$('.form-action .action').click(function() { // On click of Start New Game button.
  var complexity = $('.radio-button[type="radio"][name="complexity"]:checked').val();
  if (complexity === 'easy') {
    max_speed_limit = 10;
    min_speed_limit = 3;
    probability = 80;
  } else if (complexity === 'normal') {
    max_speed_limit = 25;
    min_speed_limit = 7;
    probability = 70;
  } else if (complexity === 'expert') {
    max_speed_limit = 40;
    min_speed_limit = 15;
    probability = 55;
  }
  $('.initial-screen').addClass('hidden');
  generateContiniousItems(1000, max_items); // this function will initiate the generation of items after certain time interval. (We will see its implementation later)
});

So far so good ! Items creation function has been created, the DOM has been created and variables has been fetched. Now the main challenge comes ! How to update the positions of all the objects simultaneously and dynamically and have a rebound effect when balloon touches the screen boundaries. JQuery doesn't support classes and OOPS so we cannot create objects instances of class. Then ? In jQuery we can declare a function (here updatePosition() ) once and call it with different parameters thereby creating a new unique instance for each function call. That mean for every newly created item updatePosition() function will have a different instance with different parameters. The function should take three parameters viz. the newly created object as a parameter (to update its css), a random direction and random speed.

    We have to update the position in specific time intervals so this fact is clear that position should be updated using setTimeInterval() function. The speed logic can be induced to the div elements using two methods.

    • Having dynamic time interval and fixed distance update factor The random speed of the div can be set by having speed variable as a time interval parameter. In this case the magnitude of positioning factor will be static but the time interval will be different for different div elements.
    • Having dynamic distance update factor and fixed time interval The random speed of the div will be set by having static time interval for each element and speed variable as the distance update factor for each of them. In this case time interval will not change but the magnitude of positioning factor will differ. 

    Both approach are right but in first approach the maximum speed is limited from coding end as the max speed according to it will be when the time interval will be 1ms, whereas in second approach the magnitude of positioning factor can exceed to any positive number. So we will use second approach here.

    According to the second approach  -

    var updatePosition = function($obj, direction, speed) {
      var down_direc, up_direc, left_direc, right_direc, speedUnit;
      // Setting up the local variables for setting up the left right directions
      // Splitting up the variables to smaller ones to enhance the code readbility
      if (direction === 'top-left') {
        down_direc = false;
        up_direc = true;
        right_direc = false;
        left_direc = true;
      } else if (direction === 'top-right') {
        down_direc = false;
        up_direc = true;
        right_direc = true;
        left_direc = false;
      } else if (direction === 'bottom-right') {
        down_direc = true;
        up_direc = false;
        right_direc = true;
        left_direc = false;
      } else if (direction === 'bottom-left') {
        down_direc = true;
        up_direc = false;
        right_direc = false;
        left_direc = true;
      } else {
        down_direc = false;
        up_direc = true;
        right_direc = false;
        left_direc = true;
      }
      // Conditioning and massaging the speed variable to have sensible speed 
      speedUnit = speed / 10;
      // Setting up the boundaries for rebound effect
      var max_bottom_limit = $(window).height() - $obj.height(); // (-) because boundary collision will occur when lower part of the balloon touches the window boundary
      var max_left_limit = $(window).width() - $obj.width(); // (-) because boundary collision will occur when right part of the balloon touches the window boundary
     
      var init_left = $obj.offset().left; // Getting the current position of the div element
      var init_top = $obj.offset().top;
      setInterval(function() { // Main logic
        $obj.css({
          top: init_top, // Updating the position of the div element (starts from the second iteration)
          left: init_left,
        });
        if (down_direc) { // If the ball vertical movement is down
          if (init_top < max_bottom_limit) { 
            init_top = init_top + speedUnit; // Update the top position 
            if (init_top >= max_bottom_limit) { // If the element bottom position exceeds the max lower boundary limit 
              init_top = max_bottom_limit; //set the element position to the max bottom boundary limit  
            }
          }
          if (init_top === max_bottom_limit) { // If the element has reached to the bottom of the page update the direction variables.
            down_direc = false; // Direction to top
            up_direc = true;
          }
        }
        if (up_direc) { // If the ball vertical movement is up
          if (init_top > 0) { 
            init_top = init_top - speedUnit;  // Update the top position 
            if (init_top <= 0) {  // If the element bottom position exceeds the max upper boundary limit 
              init_top = 0; //set the element position to the upper max boundary limit  
            }
          }
          if (init_top === 0) {  // If the element has reached to the bottom of the page update the direction variables.
            down_direc = true; // Direction to bottom
            up_direc = false;
          }
        }
        if (right_direc) { // If the ball horizontal movement is right
          if (init_left < max_left_limit) {
            init_left = init_left + speedUnit; // Update the left position 
            if (init_left >= max_left_limit) { // If the element left position exceeds the max right boundary limit 
              init_left = max_left_limit; //set the element position to the max right boundary limit 
            }
          }
          if (init_left === max_left_limit) { // If the element has reached to the bottom of the page update the direction variables.
            right_direc = false; // Direction to left
            left_direc = true;
          }
        }
        if (left_direc) { // If the ball horizontal movement is left
          if (init_left > 0) { 
            init_left = init_left - speedUnit; // Update the left position
            if (init_left <= 0) { // If the element left position exceeds the max left boundary limit 
              init_left = 0;  //set the element position to the max left boundary limit
            }
          }
          if (init_left === 0) {
            right_direc = true; // Direction to right
            left_direc = false;
          }
        }
      }, 1); // Updating the position on every ms
    };

    The function will update the position of the passed jQuery object through 'init_left' and 'init_top' variables in every 1ms. This will generate the animation effect and on having these values greater than the boundary values the directions are changed. This logic will update left and top both position simultaneously.

    Not that hard! Right? You can add new implementations to this project by cloning or forking the code base from https://github.com/swastikpareek/jq_ballon_game or you can create your own jQuery effects or create your own custom game. In this way you will get to learn about new features and new functions in jQuery.

    Start your Digital

    Transformation journey

    Consultancy | Design | Drupal