In part two of building our game, we’re going to give our blue block or ship the ability to shoot lasers. But first we have to make a couple of changes in our code from part one in order to make the game easier to build and control the game’s elements. Right now, the play area and the ship are two separate elements in the body tag, but we’re going to change this so that the ship div is inside the playArea div. So, here’s our old block of code setting up the game:
1 2 3 4 5 6 7 8 9 10 | document.body.appendChild(playArea); playArea.classList.add('playArea'); document.body.appendChild(ship); ship.classList.add('ship'); shipPos.x = (playArea.offsetWidth / 2 + playArea.offsetLeft) - (ship.offsetWidth / 2); shipPos.y = (playArea.offsetHeight + playArea.offsetTop) - (ship.offsetHeight * 2); playArea.leftBoundary = playArea.offsetLeft + 10; playArea.rightBoundary = (playArea.offsetLeft + playArea.offsetWidth - 10) - ship.offsetWidth; playArea.topBoundary = playArea.offsetTop + 10; playArea.bottomBoundary = (playArea.offsetTop + playArea.offsetHeight - 10) - ship.offsetHeight; |
Change it to this:
1 2 3 4 5 6 7 8 9 10 | document.body.appendChild(playArea); playArea.classList.add('playArea'); playArea.appendChild(ship); ship.classList.add('ship'); shipPos.x = (playArea.offsetWidth / 2) - (ship.offsetWidth / 2); shipPos.y = playArea.offsetHeight - (ship.offsetHeight * 2); playArea.leftBoundary = 0; playArea.rightBoundary = playArea.offsetWidth - ship.offsetWidth - 20; playArea.topBoundary = 0; playArea.bottomBoundary = playArea.offsetHeight - ship.offsetHeight - 20; |
The main changes are, instead of document.body.appendChild(ship), we have playArea.appendChild(ship) which puts the ship div inside the playArea div. Next, we change how we set the boundaries of the play area because now that the ship div is inside, we don’t need to get the offsetLeft and offsetTop any more. But for this to work the way we want, we still need to update the CSS:
1 2 3 4 5 6 7 8 9 10 | .playArea { width:800px; height:500px; background:#000; border:10px solid #333; margin:30px auto 0; box-shadow:5px 5px 10px #444; position:relative; overflow:hidden; } |
Setting the position to relative allows us to absolutely position elements inside the playArea div and setting overflow to hidden allows us to have elements move past the borders and not be seen anymore. Now, let’s add those lasers. First, we need some CSS:
1 2 3 4 5 6 | .laser { width:4px; height:20px; background:red; position:absolute; } |
Pretty much the same as our ship class, except laser shaped. Next we need to add some variables to our JavaScript, add these to the end of the list of variables at the top of the code:
1 2 3 | lasers = [], laserSpeed = 4, max_lasers = 5 |
First, we have an array to store our lasers in, so we can loop through it to update our lasers’ positions. Next, laserSpeed is self-explanatory, we set it up here so that it’s easier to change than if we had set it further down in the code. Also, this way we could alter it in game if we want to.
We set it so when the player presses the x key, the ship will fire a laser. Why x? Because the spacebar can be loud and annoying and x is always cool. Add this code to the bottom of the keyDown function:
1 2 3 4 5 6 7 8 9 10 | if (e.keyCode === 88) { if (lasers.length < max_lasers) { var laser = Laser(); lasers.push([laser, shipPos.y]); playArea.appendChild(lasers[lasers.length - 1][0]); lasers[lasers.length - 1][0].classList.add('laser'); lasers[lasers.length - 1][0].style.top = lasers[lasers.length - 1][1] + 'px'; lasers[lasers.length - 1][0].style.left = shipPos.x + 25 + 'px'; } } |
So, if x, which has the keyCode of 88, is pressed and if the total amount of lasers in the lasers array is less than max_lasers, then we call a function called Laser, which we’ll write next. Then we push the variable laser into our lasers array along with the ship’s y position. Next, the laser is added to the playArea div using appendChild. Then we add the class of laser to that div and set it’s top and left position.
You might be wondering why it says lasers[lasers.length - 1]. Remember that a JavaScript array starts at zero, so the first element of an array is lasers[0]. So, if we want to get the newest element in the array, it will be the last one, but if our array has one element and we put lasers.length, that will equal one and give us lasers[1]. But that would give us the second element which doesn’t exist in this example, we want lasers[0], so lasers[lasers.length - 1] will always give us the one we want in this situation.
Now we need to write that Laser function:
1 2 3 | function Laser() { return document.createElement('div'); } |
Yes, it’s that simple and we could just put:
1 | var laser = document.createElement('div'); |
But let’s say later on we need something else to happen when a div is fired, this will be the place to do it. Also, it helps to keep the code organized. Now, if you run the game, the lasers will be added but they’ll just sit there and that doesn’t make a very good offensive weapon. Now we need a function to move the lasers:
1 2 3 4 5 6 | function moveLasers() { for (var i = 0; i < lasers.length; i++) { lasers[i][1] -= laserSpeed; lasers[i][0].style.top = lasers[i][1] + 'px'; } } |
This function just runs a for loop that cycles through all the elements in the lasers array and moves them up the playArea at whatever laserSpeed is set to. Of course, to make this work, we need to call it in the loop function:
1 2 3 4 5 | function loop() { moveShip(); moveLasers(); setTimeout(loop, 1000/60); } |
This works but we have one problem, when a laser goes past the top of the playArea, it keeps going forever and once five lasers are fired, the player can’t fire any more. We need to add something to our moveLasers function to check if a laser has left the viewable area.
1 2 3 4 5 6 7 8 9 10 | function moveLasers() { for (var i = 0; i < lasers.length; i++) { lasers[i][1] -= laserSpeed; lasers[i][0].style.top = lasers[i][1] + 'px'; if (parseInt(lasers[i][0].style.top) < playArea.topBoundary) { playArea.removeChild(lasers[i][0]); lasers.splice(i, 1); } } } |
All we need is an if statement that checks if the laser has passed the top of the playArea and if it has, it removes it from both the DOM and from the lasers array which allows the player to shoot another laser.
That’s it. Now we have a ship that looks like a blue square, for now, that shoots lasers that look like red rectangles, for now. You can check out the demo here. In part 3, we’ll add some enemies to shoot at or else this will be one of the most boring games of all time.