Football Game with JavaScript [Part 1]

Football Game with JavaScript [Part 1]

Featured on Hashnode

I was on a call with a friend, he was playing a football game and he got mad because the match wasn’t as going as he expected, his bot teammates were not as good as he wanted. I suddenly tried to imagine how hard it must be to create a team controlled by the CPU, so I told him, I’m going to code a little football game for you, and you are going to help me test it.

This is a football game I’m making with JavaScript because sometimes it’s a good idea to combine activities we like, in this case, I like coding and football. What I want with this is to keep learning features I don’t know yet, to have an idea of how lost I am when coding, and most importantly, this is a good way to improve my skills and show off what I know.

Let’s get started.

You can check the GitHub repository by clicking here

You can play the last version of the game by clicking here

Part 1

What do I want to achieve in the first part? First I want the most basic of a football game.

  • First I need to be on a football field.
  • I should be able to move a player.
  • I should be able to see the ball and hit it with my player.
  • The player should score a goal when making the ball pass through the goal box.
  • When scoring a goal reset the positions and sum a point in a score counter.
  • The player and the ball should bounce w/ the limits of the field.

First, I needed to know where to start, I’ve seen that most of the games using JavaScript are made with canvas. That’s how I’m going to do it.

So the first thing I’ve done is to create an html.index file and try to draw a circle with canvas. This would be a circle in the middle of the field dividing each side of it. The first code looked like this, and the result was:

Screenshot_from_2020-12-09_22-13-42.png This is how everything started

This is how everything started. I couldn’t make a circle in the middle of the field. but then I tried a little harder. So I created a folder called football-game and inside I created a script.js file, a style.css file, and an html.index file. After some editing and struggle trying just to make a circle, I finally could draw it in the middle of the field. So after this, I’ve changed the color of the background and draw it a goal gate on the right side, just one, for now, I want the game as simple as possible.

The renderBackground function looks like this.

// This function draws the field and the goal gate
function renderBackground() {
  context.save();
  context.fillStyle = "rgb(165, 196, 125)";
  context.fillRect(0, 0, canvas.width, canvas.height);
  context.strokeStyle = "rgba(255,255,255,0.6)";
  context.beginPath();
  context.arc(canvas.width / 2, canvas.height / 2, 75, 0, Math.PI * 2);
  context.closePath();
  context.lineWidth = 5;
  context.stroke();

// Goal Gate in the right side
  context.beginPath();
  context.moveTo(canvas.width, 200);
  context.lineTo(canvas.width, 400);
  context.strokeStyle = "white";
  context.lineWidth = 50;
  context.stroke();
  context.closePath();
  context.restore();
}

So now I got the background I'm gonna need to create a ball and my player. To do this I created two classes and then two other functions to rendering them. All these functions are executed with a start function that will run as soon as the page loads (just for now) The HTML file by now looks like this:

<canvas id="game" width="900" height="500"></canvas>
<script src="script.js"></script>

And the JavaScript file like this:

var canvas = document.getElementById("game");
var context = canvas.getContext("2d");
var score = document.getElementById("score");
window.requestAnimationFrame =
  window.requestAnimationFrame ||
  window.mozRequestAnimationFrame ||
  window.webkitRequestAnimationFrame ||
  window.msRequestAnimationFrame;
var init = requestAnimationFrame(start);
function start() {
//Render functions
  renderBackground();
  renderPlayers();
  renderBall();
score.innerHTML = "Score: " + player.score;
  requestAnimationFrame(start);
}
class Ball {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    this.size = 10;
  }
}
class Player {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    this.size = 25;
    this.maxSpeed = 3;
  }
}
var player = new Player(300, 300);
var ball = new Ball(600, 300);
// This function draws an orange circle which by now is going to be my player.
function renderPlayer() {
  context.save();
  context.fillStyle = "orange";
  context.beginPath();
  context.arc(player.x, player.y, player.size, 0, Math.PI * 2);
  context.fill();
  context.closePath();
  context.restore();
}
function renderBall() {
  context.save();
  context.beginPath();
  context.fillStyle = "white";
  context.arc(ball.x, ball.y, ball.size, 0, Math.PI * 2);
  context.fill();
  context.closePath();
  context.restore();
}
// This function draws the field and the goal gate
function renderBackground() {
  context.save();
  context.fillStyle = "rgb(165, 196, 125)";
  context.fillRect(0, 0, canvas.width, canvas.height);
  context.strokeStyle = "rgba(255,255,255,0.6)";
  context.beginPath();
  context.arc(canvas.width / 2, canvas.height / 2, 75, 0, Math.PI * 2);
  context.closePath();
  context.lineWidth = 5;
  context.stroke();
// Goal Gate in the right side
  context.beginPath();
  context.moveTo(canvas.width, 150);
  context.lineTo(canvas.width, 350);
  context.strokeStyle = "white";
  context.lineWidth = 30;
  context.stroke();
  context.closePath();
  context.restore();
}

This is what I can see when this code is running.

Screenshot from 2020-12-10 05-26-19.png

This is the game at the moment, I need to make the player and the ball to move.

This is the game at the moment, I need to make the player and the ball to move. Not much yet, but it’s something. I have the field, I have a ball, and I got to have a player.

What I need now is the player to be able to move. To perform this I declare the first variables with the names of the side I want it to move; up, down, right, and left. Then I’m going to need to update the player class adding some more information such as acceleration, deceleration, speed, and something important is the Xvel and Yvel, they’re data variables created to remember how quickly an object is going in the X direction and the Y direction.

class Ball {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    this.xVel = 0;
    this.yVel = 0;
    this.decel = 0.035;
    this.size = 10;
  }
}
class Player {
  constructor(x, y) {
    this.x = x;
    this.y = y;
    this.size = 25;
    this.xVel = 0;
    this.yVel = 0;
    this.score = 0;
    this.accel = 0.55;
    this.decel = 0.55;
    this.maxSpeed = 3;
  }
}

With this information and a little math, I can create the player moves, by declaring these two functions, keyboardMoves, and movePlayer. I’m going to use document.onkeyup and document.onkeydown to make the player keep moving when any arrow button is constantly pressed.

var up = false;
var down = false;
var right = false;
var left = false;
function keyboardMoves() {
  if (up) {
    if (player.yVel > -player.maxSpeed) {
      player.yVel -= player.accel;
    } else {
      player.yVel = -player.maxSpeed;
    }
  } else {
    if (player.yVel < 0) {
      player.yVel += player.decel;
      if (player.yVel > 0) player.yVel = 0;
    }
  }
  if (down) {
    if (player.yVel < player.maxSpeed) {
      player.yVel += player.accel;
    } else {
      player.yVel = player.maxSpeed;
    }
  } else {
    if (player.yVel > 0) {
      player.yVel -= player.decel;
      if (player.yVel < 0) player.yVel = 0;
    }
  }
  if (left) {
    if (player.xVel > -player.maxSpeed) {
      player.xVel -= player.accel;
    } else {
      player.xVel = -player.maxSpeed;
    }
  } else {
    if (player.xVel < 0) {
      player.xVel += player.decel;
      if (player.xVel > 0) player.xVel = 0;
    }
  }
  if (right) {
    if (player.xVel < player.maxSpeed) {
      player.xVel += player.accel;
    } else {
      player.xVel = player.maxSpeed;
    }
  } else {
    if (player.xVel > 0) {
      player.xVel -= player.decel;
      if (player.xVel < 0) player.xVel = 0;
    }
  }
}
document.onkeyup = function (e) {
  if (e.keyCode === 38) {
    up = false;
  }
  if (e.keyCode === 37) {
    left = false;
  }
  if (e.keyCode === 40) {
    down = false;
  }
  if (e.keyCode === 39) {
    right = false;
  }
};
document.onkeydown = function (e) {
  if (e.keyCode === 38) {
    up = true;
  }
  if (e.keyCode === 37) {
    left = true;
  }
  if (e.keyCode === 40) {
    down = true;
  }
  if (e.keyCode === 39) {
    right = true;
  }
};
function movePlayer() {
  player.x += player.xVel;
  player.y += player.yVel;
}

Then I do something similar with the ball, the difference is that I won’t control the ball, I just make it move when it’s pushed and if it touches any field limit it’ll bounce.

function moveBall() {
  if (ball.xVel !== 0) {
    if (ball.xVel > 0) {
      ball.xVel -= ball.decel;
      if (ball.xVel < 0) ball.xVel = 0;
    } else {
      ball.xVel += ball.decel;
      if (ball.xVel > 0) ball.xVel = 0;
    }
  }
  if (ball.yVel !== 0) {
    if (ball.yVel > 0) {
      ball.yVel -= ball.decel;
      if (ball.yVel < 0) ball.yVel = 0;
    } else {
      ball.yVel += ball.decel;
      if (ball.yVel > 0) ball.yVel = 0;
    }
  }
  ball.x += ball.xVel;
  ball.y += ball.yVel;
}

Now, I’ll create a new function. The reset function, which is loaded when any team scores a goal, resets the positions of the player and the positions of the ball.

function reset() {
  player = new Player(300, 300);
  ball = new Ball(600, 300);
  up = false;
  down = false;
  left = false;
  right = false;
}

So now, I needed the ball to move when the player touches it. To perform this, the ball shall bounce when it collides with the player.

I need to get. The distance between the two objects so if they’re more than close they collide. I added a collide and a getDistance function which would detect when the ball is close enough to my player.

function collide(cir1, cir2) {
  var dx = (cir1.x - cir2.x) / cir1.size;
  var dy = (cir1.y - cir2.y) / cir1.size;
  cir2.xVel = -dx;
  cir2.yVel = -dy;
  cir1.xVel = dx;
  cir1.yVel = dy;
}
function getDistance(x1, y1, x2, y2) {
  return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
}
function playerball_Collision() {
  var player_ball_distance =
    getDistance(player.x, player.y, ball.x, ball.y) -
    player.size -
    ball.size;
  if (player_ball_distance < 0) {
    collide(ball, player);
  }
}

With this, I can check when the player collapses with the limits of the field.

function playerBounds() {
  if (player.x + player.size > canvas.width) {
    player.x = canvas.width - player.size;
    player.xVel *= -0.5;
  }
  if (player.x - player.size < 0) {
    player.x = 0 + player.size;
    player.xVel *= -0.5;
  }
  if (player.y + player.size > canvas.height) {
    player.y = canvas.height - player.size;
    player.yVel *= -0.5;
  }
  if (player.y - player.size < 0) {
    player.y = 0 + player.size;
    player.yVel *= -0.5;
  }
}

Now, the same but with the ball.

function ballBounds() {
  if (ball.x - ball.size < 0) {
    ball.x = 0 + ball.size;
    ball.xVel *= -1.5;
  }
  if (ball.y + ball.size > canvas.height) {
    ball.y = canvas.height - ball.size;
    ball.yVel *= -1.5;
  }
  if (ball.y - ball.size < 0) {
    ball.y = 0 + ball.size;
    ball.yVel *= -1.5;
  }
}

Inside the function ballBounds that tells me what to do when the ball touches a field limit, what if the ball touches the goal gate?

So, if the ball touches a goal gate that means a goal. How do I tell my function that? With a little math I tell function with an if statement that: if (the ball is between 150 and 350), means a goal, and the player gets one point, then the function reset is called, this will make the player and the ball go back to their initial position.

So I add this piece of code to the ballBounds function

if (ball.x + ball.size > canvas.width) {
    if (ball.y > 150 && ball.y < 350) {
      reset();
      return;
    }
    ball.x = canvas.width - ball.size;
    ball.xVel *= -1.5;
  }

Image.jpg

If the player scores a goal I need to update the goal counter. In order to save the score of my player, I’m going to save it in a variable

let myteamscore = 0; //Player starts with 0 points

And update the ballBounce function with this information telling it that when the ball touches that line it’s a goal and we need to update the counter variable. Now the whole ballBounds function looks like this:

function ballBounds() {

  // for the x (axis) parts of the field
    //if it's the goal gate this means a point for the blue team
  if (ball.x + ball.size > canvas.width) {
    if (ball.y > 150 && ball.y < 350) {
      myteamscore++;
      reset();
      return;
    }
    //if it's not a goal gate then just bounce
    ball.x = canvas.width - ball.size;
    ball.xVel *= -1.5;
  }
  if (ball.x - ball.size < 0) {
    ball.x = 0 + ball.size;
    ball.xVel *= -1.5;
  }

// for the y (axis) parts of the field
if (ball.y + ball.size > canvas.height) {
    ball.y = canvas.height - ball.size;
    ball.yVel *= -1.5;
  }
  if (ball.y - ball.size < 0) {
    ball.y = 0 + ball.size;
    ball.yVel *= -1.5;
  }
}

Now, to display this I’ll do it with document.getElementById

var score = document.getElementById("score");

In the HTML file I need to add this:

<div id="score"></div>

Now I have to add this to the start function which is going to tell me the updated goal counter in the HTML file.

score.innerHTML = "Score: " + myteamscore;

Finally, I need to update the function start() with the new features. This is a very important function because it loads all the other functions.

function start() {
  //Render functions
  renderBackground();
  renderPlayer();
  renderBall();
  //Moves functions
  movePlayer();
  moveBall();
  keyboardMoves();
  //Bounce functions
  playerBounds();
  ballBounds();
  playerball_Collision();
  score.innerHTML = "Score: " + player.score;
  requestAnimationFrame(start);
}

And the result of the first part is this:

Playable result of the first part

End of the first part.

Here is a link to the second part