Time for action – Moving the ball with JavaScript Interval

We will use the function to create a timer. The timer moves the ball a little bit every 30 milliseconds. We are going to also change the direction of the ball movement once it hits the playground edge. Let's make the ball move now:

  1. We will use our last example, listening to multiple keyboard inputs, as the starting point.
  2. Open the js/pingpong.js file in the text editor.
  3. In the existing pingpong.playground object, we change to the following code that adds height and width to the playground.
    playground: {
      offsetTop: $("#playground").offset().top,
      height: parseInt($("#playground").height()),
      width: parseInt($("#playground").width()),
    },
  4. We are now moving the ball, and we need to store the ball's status globally. We will put the ball-related variable inside the pingpong object:
    var pingpong = {
      //existing data
      ball: {
        speed: 5,
        x: 150,
        y: 100,
        directionX: 1,
        directionY: 1
      }
    }
  5. We define a gameloop function and move the ball on each game loop iteration:
    function gameloop() {
      moveBall();
    }
  6. We define the functions to check whether the ball is hitting the four boundary walls of the playground:
    function ballHitsTopBottom() {
      var y = pingpong.ball.y + pingpong.ball.speed * pingpong.ball.directionY;
      return y < 0 || y > pingpong.playground.height;
    }
    function ballHitsRightWall() {
      return pingpong.ball.x + pingpong.ball.speed * pingpong.ball.directionX > pingpong.playground.width;
    }
    function ballHitsLeftWall() {
      return pingpong.ball.x + pingpong.ball.speed * pingpong.ball.directionX < 0;
    }
  7. Then, we define two functions that reset the game after either player wins.
    function playerAWin() {
      // reset the ball;
      pingpong.ball.x = 250;
      pingpong.ball.y = 100;
    
      // update the ball location variables;
      pingpong.ball.directionX = -1;
    }
    function playerBWin() {
      // reset the ball;
      pingpong.ball.x = 150;
      pingpong.ball.y = 100;
    
      pingpong.ball.directionX = 1;
    }
  8. It is time to define the moveBall function. The function checks the boundaries of the playground, changes the direction of the ball when it hits the boundaries, and sets the new ball position after all these calculations. Let's put the following moveBall function definition in the JavaScript file:
    function moveBall() {  
      // reference useful varaibles
      var ball = pingpong.ball;
    
      // check playground top/bottom boundary
      if (ballHitsTopBottom()) {
        // reverse direction
        ball.directionY *= -1;
      }
      // check right
      if (ballHitsRightWall()) {
        playerAWin();
      }
      // check left
      if (ballHitsLeftWall()) {
        playerBWin();
      }
    
      // check paddles here
    
      // update the ball position data
        ball.x += ball.speed * ball.directionX;
        ball.y += ball.speed * ball.directionY;
    }
  9. We have calculated the ball's movement. Next, we want to render the view to update the ball's position based on the data. To do this, define a new renderBall function with the following code.
    function renderBall() {
      var ball = pingpong.ball;
      $("#ball").css({
        "left" : ball.x + ball.speed * ball.directionX,
        "top" : ball.y + ball.speed * ball.directionY
      });
    }
  10. Now, we need to update the render function to render the ball's update based on the updated game data:
    function render() {
      renderBall();
      renderPaddles();
      window.requestAnimationFrame(render);
    }
  11. The following lines of code is the new init function where we added a gameloop logic with the setInterval function:
    function init() {
      // set interval to call gameloop logic in 30 FPS
      pingpong.timer = setInterval(gameloop, 1000/30);
    
      // view rendering
      window.requestAnimationFrame(render);
    
      // inputs
      handleMouseInputs();
    }
  12. We have prepared the code to move the ball every 33.3 milliseconds. Save all the files and open index.html in the web browser to test it. The paddles work just as in the last example, and the ball should be moving around the playground.

What just happened?

We just successfully made the ball move around the playground. We have a loop to run routine game logic 30 times per second. Inside that game loop, we moved the ball five pixels at a time. You can try the game and view the code in progress at http://makzan.net/html5-games/pingpong-wip-step6/.

There are three properties of the ball: speed, and the x and y directions. Speed defines how many pixels the ball moves in each step. The direction X/Y is either 1 or -1. We move the ball using the following equation:

new_ball_x = ball_x_position + speed * direction_x
new_ball_y = ball_y_position + speed * direction_y

The direction value is multiplied by the movement. When the direction is 1, the ball moves to the positive direction of the axis. When the direction is -1, the ball moves to the negative direction. By toggling the x and y directions, we can move the ball in four directions.

We compare the ball's X and Y values with the four edges of the playground DIV element. This checks whether the ball's next position is beyond the boundary, and then, we toggle the direction between 1 and -1 to create the bouncing effect.

Creating a JavaScript timer with the setInterval function

We have a timer to loop and move the ball periodically. This can be done by the setInterval function in JavaScript.

Here is the general definition of the setInterval function:

setInterval(expression, milliseconds)

The setInterval takes two required arguments. Additional arguments are passed into the function as parameters:

Understanding the game loop

We have a timer to execute some game-related code every 33.3 milliseconds, so this code is executed 30 times per second. This frequency is known as frames per second, or FPS. In game development, this timer is called the game loop.

There are several common things that we will execute inside a game loop:

  • Processing user input, which we just did
  • Updating game objects' status, including position and appearance
  • Checking game over

What is actually executing in the game loop differs in different types of games, but the purpose is the same. The game loop is executed periodically to calculate the game data.

Separating the data and the view logic

We have separated the data and the view logic. We used setInterval for data and requestAnimationFrame for view rendering. The data focuses on all the game data calculation, including an object's dimension and position based on the calculation. The view logic focuses on updating the interface based on the keep-updating game data.

In our render function, the view updates the CSS of the DOM elements. Imagine later if we are rendering the game in the Canvas, or using any other techniques, that our view rendering logic can use a specific method to render the view based on the same game data. The game data's calculation is independent to the techniques we use to render the game interface.