4 555 Codepen

Космическая стрелялка, игра на js

Срелялка на jаvascript. Вы соревнуетесь с компьютером в то, кто кого быстрее подстрелит. Осложняют ситуацию летающие астеройды.


HTML

<div class="container">
  <div id="overlay" class="screen-overlay"></div>
  <div id="contenders">
    <svg xmlns="http://www.w3.org/2000/svg" version="1" viewbox="0 0 741 1255" width="67.7" height="67.7" id="player1" class="player-one">
        <path fill="#1560d6" d="M565 728c-6 68-15 130-29 186 88 38 156 106 187 188 12-32 18-65 18-100 0-116-70-217-176-274zM265 1020l8 25h194l9-25H265z"/>
        <path fill="#e83d37" d="M210 937c8 30 17 58 26 83h269c9-25 18-53 26-83H210z"/>
        <path fill="#1560d6" d="M0 1002c0 35 6 68 18 100 31-82 99-150 187-188-14-55-23-118-29-186A314 314 0 0 0 0 1002z"/>
        <path fill="#DFE3E5" d="M571 585c0-125-30-241-67-337a395 395 0 0 1-270 0c-36 94-64 209-64 337a1658 1658 0 0 0 34 329l6 23h321l5-23a1313 1313 0 0 0 35-329z"/>
        <circle fill="#B8BDBF" cx="370" cy="481" r="100"/>
        <path fill="#ead3b0" d="M455 481a85 85 0 1 1-170 0 85 85 0 0 1 170 0z"/>
        <path fill="#1560d6" d="M234 248a394 394 0 0 0 270 0C446 98 370 0 370 0c-9 10-81 104-136 248z"/>
      </svg>
    <svg xmlns="http://www.w3.org/2000/svg" version="1" viewbox="0 0 741 1255" width="67.7" height="67.7" id="player2" class="player-two">
        <path fill="#ED1C24" d="M565 728c-6 68-15 130-29 186 88 38 156 106 187 188 12-32 18-65 18-100 0-116-70-217-176-274zM265 1020l8 25h194l9-25H265z"/>
        <path fill="#8074B5" d="M210 937c8 30 17 58 26 83h269c9-25 18-53 26-83H210z"/>
        <path fill="#ED1C24" d="M0 1002c0 35 6 68 18 100 31-82 99-150 187-188-14-55-23-118-29-186A314 314 0 0 0 0 1002z"/>
        <path fill="#DFE3E5" d="M571 585c0-125-30-241-67-337a395 395 0 0 1-270 0c-36 94-64 209-64 337a1658 1658 0 0 0 34 329l6 23h321l5-23a1313 1313 0 0 0 35-329z"/>
        <circle fill="#B8BDBF" cx="370" cy="481" r="100"/>
        <path fill="#B3E3F4" d="M455 481a85 85 0 1 1-170 0 85 85 0 0 1 170 0z"/>
        <path fill="#ED1C24" d="M234 248a394 394 0 0 0 270 0C446 98 370 0 370 0c-9 10-81 104-136 248z"/>
      </svg>
  </div>
  <div id="popup" class="popup-box">
    <div class='popup-text'>
      <div class="options">
        <button id="playerOne" class="toggle button option-blue">Computer</button>
        <h2 class="vs">VS</h2>
        <button id="playerTwo" class="toggle button option-red">Human</button>
      </div>
      <div class="options-lower">
        <button id="obstacles" class="toggle button option-obstacles">Asteroids: On</button>
        <br/>
        <button id="start" class="start-button">Start</button>
      </div>
    </div>
  </div>
  <!--POPUP END-->
  <div id="results" class="popup-results">
    <div class='popup-text'>
      <h3 class="result"></h3>
      <h3 class="message"></h3>
      <button id="restart" class="start-button">Play Again?</button>
    </div>
  </div>
  <!--RESULTS END-->
  <div class="scoreboard">
    <div>
      <p class="counter p1"><span class="shield_p1">0</span>%</p>
    </div>
    <div>
      <p class="counter p2"><span class="shield_p2">0</span>%</p>
    </div>
  </div>
  <canvas class="gameboard"></canvas>
  <canvas class="canvasPlanet"></canvas>
  <div class="crash">
    <svg class="explosion" version="1" width="512" height="512">
          <path d="M309 5l-77 156-29-31-7 58-170-49 112 114-32 16 50 26-40 88 73-17-7 141 69-129 61 55 6-75 140 50-103-101 131-47-143-35 20-39-50 8-4-189z" fill="#f24501" stroke="#9f0001" stroke-width="10" stroke-linejoin="miter"/>
          <path d="M275 126l-37 86-16-16-3 31-92-21 63 58-16 9 27 12-18 49 38-12v76l34-71 34 28 1-41 76 23-58-51 69-29-78-14 10-22-26 6-8-101z" fill="#fcdd09" stroke="#ff9702" stroke-width="3" stroke-linejoin="miter"/>
        </svg>
  </div>
  <!--CRASH END-->
  <svg xmlns="http://www.w3.org/2000/svg" version="1" id="planet" class="planet-one" viewbox="0 0 1402 1402" width="100%" height="100%">
        <circle class="p1bg" fill="#018FD5" cx="701" cy="701" r="701"/>
        <path class="p1c" fill="#75B84B" d="M232 900c-7-89-111-70-171-145s228-60 264-398c15-141-13-196-51-212A700 700 0 0 0 49 958c63 10 189 19 183-58zM997 312c-22 53-270 127-46 182 79 20 49 113 112 103s-23-106 56-181c19-18 102-81 149-128a705 705 0 0 0-167-163c-4 4-37 30-104 187zM549 239c29 152 441-57 482-157a698 698 0 0 0-696 21c98 41 192 20 214 136zM1355 450c-32 80-126 316-244 294-88-16-246 26-272 152-38 185-18 290 120 239 84-31 187 43 282-71 23-28 84-91 128-152a700 700 0 0 0-14-462zM557 450c-321 18-115 332-99 379 16 46 95 180 172 145s161-287 125-415c-39-134-134-112-198-109zM513 1175c30-241-234-60-304 25a699 699 0 0 0 805 128c72-161-534 109-501-153z"/>
        <path fill="#186DA0" opacity=".2" d="M959 1186A701 701 0 0 1 393 71a701 701 0 1 0 874 1044c-93 45-198 71-308 71z"/>
      </svg>
  <div class="planet-two">
    <svg version="1" viewbox="0 0 1443 1443">
          <circle class="p2bg" fill="#FCEE21" cx="721" cy="721" r="721"/>
          <circle class="p2c" fill="#E0C922" cx="303" cy="408" r="110"/>
          <circle class="p2c" fill="#E0C922" cx="219" cy="715" r="103"/>
          <circle class="p2c" fill="#E0C922" cx="522" cy="619" r="71"/>
          <circle class="p2c" fill="#E0C922" cx="536" cy="864" r="71"/>
          <circle class="p2c" fill="#E0C922" cx="324" cy="942" r="47"/>
          <circle class="p2c" fill="#E0C922" cx="577" cy="359" r="107"/>
          <circle class="p2c" fill="#E0C922" cx="771" cy="164" r="84"/>
          <circle class="p2c" fill="#E0C922" cx="462" cy="183" r="38"/>
          <circle class="p2c" fill="#E0C922" cx="921" cy="607" r="125"/>
          <circle class="p2c" fill="#E0C922" cx="846" cy="957" r="102"/>
          <circle class="p2c" fill="#E0C922" cx="641" cy="1213" r="145"/>
          <circle class="p2c" fill="#E0C922" cx="388" cy="1170" r="55"/>
          <circle class="p2c" fill="#E0C922" cx="715" cy="735" r="42"/>
          <circle class="p2c" fill="#E0C922" cx="1180" cy="916" r="121"/>
          <circle class="p2c" fill="#E0C922" cx="1038" cy="1188" r="57"/>
          <circle class="p2c" fill="#E0C922" cx="1059" cy="346" r="114"/>
          <circle class="p2c" fill="#E0C922" cx="1280" cy="646" r="99"/>
          <path fill="#000" opacity=".15" d="M1030 1209A721 721 0 0 1 457 50a722 722 0 1 0 838 1109c-82 32-171 50-265 50z"/>
        </svg>
  </div>
  <!--PLANET-TWO END-->
  <div class="star">
    <svg id="star" viewBox="0 0 513 513" version="1">
          <path fill="#f5ede7" class="star-body" d="M400 503c-3 0-7-1-10-3l-134-68-134 68a23 23 0 0 1-33-24l23-149L7 219a23 23 0 0 1 12-38l148-25 69-134a23 23 0 0 1 40 0l69 134 148 25a23 23 0 0 1 12 38L400 327l23 149a23 23 0 0 1-23 27z"/>
        </svg>
  </div>
  <!--STAR END-->
  <div class="space"></div>
</div>
<div class="hidden-assets">
  <svg xmlns="http://www.w3.org/2000/svg" version="1" viewbox="0 0 741 1255" width="67.7" height="67.7" id="flicker">
      <g>
        <path fill="#F7931E" d="M370 1255c31 0 60-79 83-210H288c23 131 51 210 82 210z"/>
        <path fill="#EDBB0B" d="M370 1145c26 0 50-38 69-100H302c19 62 43 100 68 100z"/>
      </g>
    </svg>
</div>

SCSS

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

:root {
  font-size: calc(1vw + 1vh + 0.5vmin);
}

body {
  background: #475471;
  font-family: Arial, Helvetica, sans-serif;
  color: white;
  height: 100%;
  margin: 0px;
}

.container {
  background-image: -webkit-radial-gradient(
    50% 50%,
    ellipse cover,
    rgba(0, 0, 0, 0.3) 5%,
    rgba(0, 0, 0, 0.7) 100%
  );
  height: 100%;
  overflow: hidden;
  position: absolute;
  width: 100%;
}

.scoreboard {
  display: flex;
  justify-content: space-between;
  width: 100%;
}

.scoreboard div {
  display: inline-block;
  width: 49%;
}
// A lighter shade of blue
p.p1 {
  color: #6a99e4;
}

// A lighter shade of red
p.p2 {
  color: #f1595f;
}

.counter {
  position: relative;
  opacity: 0.8;
  font-size: 2em;
  letter-spacing: 0.25em;
  padding: 0.5em 0 0 1em; // Offset padding to compensate for letter spacing
  text-align: center;
  z-index: 15;
}

.gameboard,
.canvasPlanet {
  width: 100%;
  height: 100%;
  overflow: hidden;
  position: absolute;
  top: 0px;
  left: 0px;
}

.gameboard {
  z-index: 10;
}

.canvasPlanet {
  z-index: 5;
}

.planet-one,
.planet-two {
  filter: blur(0.05vmax);
  height: 10vmin;
  opacity: 0;
  width: 10vmin;
  z-index: 3;
}

.star {
  position: absolute;
  width: 1vmax;
  height: 1vmax;
  filter: blur(0.05vmax);
  left: 50%;
  top: 50%;
  z-index: 1;
}

// Popup Box
.screen-overlay {
  background: linear-gradient(
    110deg,
    #0c4094 0%,
    #0c4094 50%,
    #a51419 50.1%,
    #a51419 100%
  );
  display: none;
  height: 100%;
  left: 0%;
  opacity: 0;
  position: absolute;
  top: 0%;
  width: 100%;
  z-index: 9000;
}

.player-one {
  height: 80vh;
  left: -20%;
  position: absolute;
  top: 0%;
  transform: rotate(200deg);
  width: 80vw;
  z-index: 9200;
}

.player-two {
  height: 80vh;
  left: 40%;
  position: absolute;
  top: 20%;
  transform: rotate(20deg);
  width: 80vw;
  z-index: 9200;
}

.popup-box {
  display: none;
  height: 100%;
  opacity: 1;
  overflow: auto;
  position: absolute;
  width: 100%;
  z-index: 9500;
}

.vs {
  font-size: 5em;
  letter-spacing: 0.1em;
  padding: 0 0 0 0.2em;
}

.toggle {
  width: 10em;
  z-index: 9999;
}

.options {
  align-items: flex-start;
  display: flex;
  justify-content: space-around;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 100%;
  z-index: 9999;
}

.options button {
  position: relative;
}

.options-lower {
  left: 50%;
  position: absolute;
  top: 60%;
  transform: translateX(-50%);
  z-index: 9999;
}

.option-blue {
  background: #1560d6;
}

.option-red {
  background: #ed1c24;
}

.start-button {
  background: #22b857;
  margin-top: 1em;
  z-index: 9999;
}

.popup-results {
  display: none;
  left: 50%;
  opacity: 1;
  overflow: auto;
  padding: 1em;
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 90%;
  z-index: 9999;
}

.popup-text {
  color: white;
  font-size: 1.2em;
  text-align: center;
}

.popup-text p {
  padding: 18px;
}

.popup-text h3 {
  font-size: 4em;
  line-height: 1.2;
  padding: 0.5em;
  text-shadow: 2px 2px 2px #333;
}

.hidden-assets {
  display: none;
}

button {
  background: #f7931e;
  border: 3px solid white;
  color: white;
  cursor: pointer;
  display: inline-block;
  font-size: 22px;
  font-weight: bold;
  margin: 20px 15px 10px;
  outline: none;
  padding: 15px 32px;
  position: relative;
  text-align: center;
  text-decoration: none;
  text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3);
  top: 10px;
  z-index: 9999;
}

button:hover {
  border-color: rgba(0, 0, 0, 0.2);
}

button:active {
  transform: translateY(1px);
}

.crash {
  display: inline-block;
  transform-origin: 50% 50%;
  opacity: 0;
  position: absolute;
  z-index: 15;
}

.explode {
  animation-name: boom;
  animation-duration: 1s;
  animation-iteration-count: 1; // Play the animation once
  animation-fill-mode: both; // Lock the end position of the animation
  animation-timing-function: ease;
  transform-origin: 50% 50%;
  z-index: 50;
}

@keyframes boom {
  0% {
    transform: scale(0.01);
  }
  70% {
    transform: scale(1);
  }
  100% {
    transform: scale(10);
  }
}

JS

// Game parameters
let canvas, centerPoint, ctx, game_mode, playing, player1, player2, start;
// The scoreboard is used to keep track of the health of the players at the top of the screen
const scoreboard = document.querySelector(".scoreboard");
// Each player has a shield score in percent
const shield_p1 = document.querySelector(".shield_p1");
const shield_p2 = document.querySelector(".shield_p2");
// The game over screen has an explosion controlled and sized with two variables
const crash = document.querySelector(".crash");
const explosion = document.querySelector(".explosion");
// The result screen has a customised message and result of the game
const message = document.querySelector(".message");
const result = document.querySelector(".result");
// Each of the planet graphics is dynamically styled and positioned
const planet1 = document.querySelector(".planet-one");
const planet2 = document.querySelector(".planet-two");
// The space variable is where the stars are drawn
const space = document.querySelector(".space");
// On the start screen there are buttons to toggle whether the player is a computer or human
const playerOneToggle = document.querySelector("#playerOne");
const playerTwoToggle = document.querySelector("#playerTwo");
// There is also a toggle button for the asteroids to create variety in the game
const asteroidsToggle = document.querySelector("#obstacles");
// The gutter hides the new asteroids being added to the game so it is best to keep the rocket on screen to avoid being hit
const gutter = 150;
// For the popup boxes there is a background overlay
const overlay = document.getElementById("overlay");
// The popup messages has its own selector so that they can be toggled from the start screen to the end game screen
let popup = document.getElementById("popup");
const contenders = document.getElementById("contenders");
const p1_graphic = document.getElementById("player1");
const p2_graphic = document.getElementById("player2");
// Asteroid parameters group
let asteroids;
let asteroidColor;
// How often new asteroids appear on screen
const asteroidRate = 200;
// The maximum number of asteroids that can be in the game at any given time
let asteroidMax = 5;
// Start the timeout at zero
let asteroidTimeout = 0;
// Define subtle colour differences between the size of the asteroids
const asteroidColors = ["#9F96BC", "#666078", "#494556"];
// The maximum size of the asteroids
const asteroidSizeMax = 30;
// The maximum speed of the asteroids
const asteroidSpeed = 2;
// How big the asteroids should split when they are broken
const splitSize = 10;

// Rocket parameters
const rocketSize = 33;
const rocketWidth = 40;
const rocketArea = 1236.22;
const acceleration = 0.15;
const turnRate = 5;

// Shooting parameters
const shootingRate = 10;
const shootingSpeed = 12;

// Function to handle SVG files
function importSVG(name) {
  const svg = document.getElementById(name);
  let object_svg = new Image();
  const data = new XMLSerializer().serializeToString(svg);
  object_svg.src = "dаta:image/svg+xml;base64," + window.btoa(data); // The btoa() method encodes a string in base-64
  return object_svg;
}

// Import the inline SVG elements
let player1_svg = importSVG("player1");
let player2_svg = importSVG("player2");
let flicker_svg = importSVG("flicker");

// Set the size of the explosion early on because the size changes with the animation cause a bug
const explosionSize = {
  width: (explosion.getBoundingClientRect().width / 2).toFixed(),
  height: (explosion.getBoundingClientRect().height / 2).toFixed()
};

// Popup UI handling
function openPopup() {
  start = popup.querySelector(".start-button");
  start.addEventListener("click", startGame);
  contenders.style.display = "block";
  popup.style.display = "block";
  overlay.style.display = "block";
  contenders.style.opacity = "1";
  popup.style.opacity = "1";
  overlay.style.opacity = "0.6";
}

function closePopup() {
  start.removeEventListener("click", startGame);
  overlay.style.opacity = "0";
  popup.style.opacity = "0";
  contenders.style.opacity = "0";
  popup.style.display = "none";
  overlay.style.display = "none";
  contenders.style.display = "none";
}

// The following function creates a tesseract effect to keep the game objects roughly on screen
function tesseractMove() {
  // If on the right side of the screen then come back on the left side
  if (this.x > canvas.width + gutter) {
    this.x = 0 - gutter / 2 + this.vx;
  } else if (this.x < 0 - gutter) {
    // Or if they go off the left side then they come back on the right
    this.x = canvas.width + gutter / 2 + this.vx;
  } else {
    // Otherwise just update the x position with the velocity
    this.x += this.vx;
  }
  // If on the bottom side of the screen then come back on the top side
  if (this.y > canvas.height + gutter) {
    this.y = 0 - gutter / 2 + this.vy;
  } else if (this.y < 0 - gutter) {
    // Or if they go off the top side then they come back on the bottom
    this.y = canvas.height + gutter / 2 + this.vy;
  } else {
    // Otherwise just update the y position with the velocity
    this.y += this.vy;
  }
}

// Function to check whether two positions intersect other by returning a distance
function checkBoundary(dot1, dot2) {
  const x1 = dot1[0],
    y1 = dot1[1],
    x2 = dot2[0],
    y2 = dot2[1];
  return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
}

// Math functions
function rad(angle) {
  return angle * Math.PI / 180;
}

// Define a new rocket with a token and a role
function Rocket(token, role) {
  // Give the rocket an ID based on the token of its creation
  this.id = token;
  // Starting position for player one is on the left of the screen
  if (token == "one") {
    this.x = canvas.width / 4;
  } else {
    // The other player starts on the right hand side of the screen
    this.x = canvas.width / 4 * 3;
  }
  // Both players start in the middle of the y axis
  this.y = centerPoint.y;

  // Starting velocity is 0 on both axis
  this.vx = 0;
  this.vy = 0;

  // Rocket controls
  this.thruster = false;
  this.rotateLeft = false;
  this.rotateRight = false;
  this.fire = false;
  // Set the SVG to use
  if (token == "one") {
    this.svg = player1_svg;
    this.score = shield_p1;
  } else {
    this.svg = player2_svg;
    this.score = shield_p2;
  }

  // Set rocket dependent timeouts
  this.shotTimeout = shootingRate;
  this.flameTimeout = 0;
  // Starting health for the rockets is 100% and the game ends when one rocket reaches zero
  this.health = 100;
  // Set the direction for the rocket to be facing this needs to match the SVG direction to avoid a display bug on Safari (90 is towards the top of the screen)
  if (token == "one") {
    // Player one faces the bottom of the screen to match the start screen graphic
    this.direction = 270;
  } else {
    this.direction = 90;
  }

  // Store all rocket's shots in an array
  this.shots = [];

  // Rocket methods
  this.getPoints = getRocketPoints;
  this.update = updateRocket;
  this.move = tesseractMove;
  this.render = renderRocket;
}

// Define the Enemy object which is a computer controlled Rocket
function Enemy(token, role) {
  // The enemy takes all the parameters of the Rocket
  Rocket.call(this, token, role);
  // The enemy also has a "sworn enemy" which is the oposing player and is defined in the start game function
  this.swornEnemy = "";
  // New direction to calculate how much the Enemy should turn
  this.newDirection = 0;
  // Result of the difference between the direction and the new direction
  this.angleDiff = 0;
  // New position to define where the Enemy should aim at
  this.newPosition = {
    x: 0,
    y: 0
  };
  // Set an interval for how often the Enemy should be searching
  this.searchInterval = 0;
  // Check if the Enemy has found its target
  this.targetFound = false;
  // Set an interval for how often the Enemy moves
  this.moveInterval = 0;
  // Set an interval for how often the Enemy should panic
  this.panicInterval = 50;
  // Set the proximity for how close the Enemy is to its target
  this.proximity = 0;
  // Check if the Enemy is "safe" and out of the proximity of other game objects
  this.safe = true;
  // Store the closest target to the Enemy
  this.closestTarget = "";
  // Track the distance of the closest target
  this.closestDistance = 0;
  // Create a random reaction if the target is too close
  this.fightOrFlight = 0;
}

// Setup the Enemy prototype
Enemy.prototype = Object.create(Rocket.prototype);
Object.defineProperty(Enemy.prototype, "constructor", {
  value: Enemy,
  enumerable: false,
  writable: true
});

// Give the enemy player a set of functions which creates a behaviour
Enemy.prototype.behaviour = function() {
  // Keep the direction within 360 degrees
  if (this.direction > 360) {
    this.direction -= 360;
  } else if (this.direction < 0) {
    this.direction += 360;
  }
  // If the enemy is "safe" then give it a fight or flight instinct
  if (this.safe) {
    this.fightOrFlight = randomise(2);
  }
  // Set a function to create random numbers to make less predictable behaviour
  function randomise(max) {
    return Math.floor(Math.random() * max);
  }
  // Function to set a new position for the enemy to target and move to
  const randomPosition = function() {
    this.newPosition.x = randomise(canvas.width);
    this.newPosition.y = randomise(canvas.height);
  }.bind(this);

  // Set function to find the angle of the target from the enemy's rocket's position
  const findAngle = function(target) {
    const dx = this.x - target.x;
    const dy = this.y - target.y;
    let angle = Math.atan2(dy, dx);
    if (this.safe) {
      this.newPosition.x = this.x - dx;
      this.newPosition.y = this.y - dy;
    }
    // Set the newDirection based on the calculated angle of the given target
    this.newDirection = 180 - angle * (180 / Math.PI);
    // The enemy needs to work out the quickest way to turn to face the target
    this.angleDiff = this.newDirection - this.direction;
    if (this.angleDiff < -180) {
      this.angleDiff = this.angleDiff + 360;
    } else if (this.angleDiff > 180) {
      this.angleDiff = this.angleDiff - 360;
    }
    this.angleDiff = this.angleDiff.toFixed();
  }.bind(this);
  // Set a function to turn the rocket to face the target
  const turnToFace = function(target) {
    if (this.targetFound) {
      return;
    } else if (this.angleDiff > 5) {
      this.rotateLeft = true;
      this.rotateRight = false;
      return;
    } else if (this.angleDiff < 5) {
      this.rotateLeft = false;
      this.rotateRight = true;
      return;
    } else {
      this.targetFound = true;
      this.rotateLeft = false;
      this.rotateRight = false;
      return;
    }
  }.bind(this);
  // Try to mimic human behaviour so only shoot if the target is in range
  const shootIfInRange = function() {
    if (this.angleDiff < 7 && this.angleDiff > -7) {
      this.fire = true;
    } else {
      this.fire = false;
    }
  }.bind(this);
  // Vary the thruster usage
  const move = function() {
    if (this.moveInterval <= 0) {
      if (this.thruster == false) {
        this.thruster = true;
        this.moveInterval = randomise(12) + 6;
      } else {
        this.thruster = false;
        this.moveInterval = randomise(30) + 80;
      }
    } else {
      this.moveInterval--;
    }
  }.bind(this);
  // Set the attack function in bursts
  const attack = function(target) {
    if (this.searchInterval <= 0) {
      this.targetFound = false;
      this.fire = false;
      this.searchInterval = randomise(30) + 35;
    } else {
      this.searchInterval--;
    }
    // First find the angle
    findAngle(target);
    // Then shoot if in range
    if (this.targetFound) {
      shootIfInRange();
      // Don't move towards the target
      this.thruster = false;
    } else {
      // Otherwise move towards the target
      turnToFace(target);
      this.thruster = true;
    }
    move();
  }.bind(this);

  // Find a new direction
  const changeDirection = function() {
    randomPosition();
    this.safe = false;
  }.bind(this);

  // Define a flee function
  const flee = function() {
    // If the enemy was "safe" then it should change direction!
    if (this.safe) {
      // To help change direction there should be a new position
      changeDirection();
      // The enemy needs to use the thruster to flee
      this.thruster = true;
    }
    // The enemy should then find out what the new angle is
    findAngle(this.newPosition);
    // The enemy turns to face the new direction and moves towards it
    turnToFace(this.newPosition);
    move();
    // The panic interval gives the chance to find a new position if the enemy doesn't feel like it can find a "safe" position
    if (this.panicInterval <= 0) {
      // Setting safe to true will cause the algoritm to find a new position on the next iteration
      this.safe = true;
      // Then the panic interval should be reset to a new randomised value
      this.panicInterval = randomise(60) + 30;
    } else {
      // Otherwise the panic interval is just counting down to zero
      this.panicInterval--;
    }
  }.bind(this);
  // Define an ability for the Enemy to find the closest target
  const findClosest = function(target) {
    // The following calculates the distance between the target and the Enemy
    let dist_x = this.x - target.x;
    let dist_y = this.y - target.y;
    this.proximity = Math.sqrt(dist_x * dist_x + dist_y * dist_y);
  }.bind(this);
  // While checking for the closest distance we need to set the distance which is the closest
  const setClosest = function() {
    this.closestDistance = this.proximity;
  }.bind(this);
  // First option should always be the sworn enemy
  findClosest(this.swornEnemy);
  // Set this as a default value
  this.closestTarget = this.swornEnemy;
  // Set the distance
  setClosest();
  // Make similar checks on the other objects in the game
  if (obstacles) {
    for (let i = 0; i < asteroids.length; i++) {
      findClosest(asteroids[i]);
      if (this.proximity < this.closestDistance) {
        this.closestTarget = asteroids[i];
        setClosest();
      }
    }
  }
  // Define what the Enemy should do with the variables it has calculated
  if (this.closestDistance < 150) {
    this.fire = true;
    // If too close to the target then it should consider to attack or flee
    if (this.fightOrFlight === 0) {
      attack(this.closestTarget);
    } else {
      flee();
    }
    // From a bit further away the more likely option could be to flee
  } else if (this.closestDistance < 300 || !this.safe) {
    flee();
    // Fire in case things get in the way
    this.fire = true;
    // If the Enemy feels safe then it will attack
  } else if (this.safe) {
    // Switch off the fire option
    this.fire = false;
    attack(this.closestTarget);
    // If there is some distance between the Enemy and the target then it can consider itself "safe" and attack from a distance
  } else if (this.closestDistance > 500) {
    this.safe = true;
    this.fire = false;
    this.thruster = false;
    attack(this.closestTarget);
  }
};

// Calculate the position of the rocket
function getRocketPoints() {
  // Store the points in an array to loop over later
  let points = [];
  // Define the left and right sides based on the direction
  let leftSide = rad(this.direction - rocketWidth);
  let rightSide = rad(this.direction + rocketWidth);
  // Simplify the rocket's shape to a triangle
  // Rocket top point
  points.push([
    this.x + rocketSize * Math.cos(rad(this.direction)),
    this.y - rocketSize * Math.sin(rad(this.direction))
  ]);
  // Rocket left point
  points.push([
    this.x - rocketSize * Math.cos(leftSide),
    this.y + rocketSize * Math.sin(leftSide)
  ]);
  // Rocket right point
  points.push([
    this.x - rocketSize * Math.cos(rightSide),
    this.y + rocketSize * Math.sin(rightSide)
  ]);
  // Return the array of points
  return points;
}

// Update the effects on the rocket
function updateRocket() {
  // If pushing the up key then apply the thruster
  if (this.thruster) {
    this.vx += acceleration * Math.cos(rad(this.direction));
    this.vy -= acceleration * Math.sin(rad(this.direction));
  }
  // Left rotates the rocket anti-clockwise
  if (this.rotateLeft) {
    this.direction += turnRate;
  }
  // Right rotates the rocket clockwise
  if (this.rotateRight) {
    this.direction -= turnRate;
  }
  // If the rocket is firing with the spacebar
  if (this.fire) {
    // Limit the shots being fired with a timeout
    if (this.shotTimeout >= shootingRate) {
      // Get the points for the rocket to work out where the rocket is firing from
      let position = this.getPoints();
      // Add a new shot taking into account the direction the shot is being fired and who fired the shot
      this.shots.push(
        new Shot(position[0][0], position[0][1], this.direction, this.id)
      );
      // Reset the timeout
      this.shotTimeout = 0;
    } else {
      // Otherwise increase the timeout
      this.shotTimeout++;
    }
    // If not firing
  } else {
    // Reset shot timeout directly
    this.shotTimeout = shootingRate;
  }
  // Loop through all the shots and update them all
  for (let i = 0; i < this.shots.length; i++) {
    this.shots[i].update(i);
    if (this.shots[i].hit == true) {
      // Remove shots that have hit a game object
      this.shots.splice(i, 1);
    }
  }

  // If the rocket is moving then slow this motion slightly
  if (this.vx != 0) {
    // Reduce X velocity
    this.vx -= 0.01 * this.vx;
  }
  if (this.vy != 0) {
    // Reduce Y velocity
    this.vy -= 0.01 * this.vy;
  }
  // Move the rocket
  this.move();
}
// Try to prevent collisions by using the rockets' shields to repel each other
function collisionPrevention() {
  // Calculate the distance between the plater and enemy
  let dist_x = player1.x - player2.x;
  let dist_y = player1.y - player2.y;
  // Get the repel distance
  let repel = Math.sqrt(dist_x * dist_x + dist_y * dist_y);
  // If the rockets are too close to each other
  if (repel < 40) {
    // Set new repel variables for x and y
    let repelX = dist_x / repel;
    let repelY = dist_y / repel;
    // Apply this to both rockets
    player1.vx += repelX * 5;
    player1.vy += repelY * 5;
    player2.vx -= repelX * 5;
    player2.vy -= repelY * 5;
    // Reduce the health of both rockets as a consequence of the impact on the shield
    player1.health -= 5;
    player2.health -= 5;
  }
}

// Function to render the appearence of the rocket
function renderRocket() {
  // Get the points of the rocket
  let points = this.getPoints();
  // Calculate the angle it is facing
  let angle = rad((this.direction + 270) * -1);
  // The following between "save" and "restore" is used to position the SVG image in the right place and angle
  ctx.save();
  ctx.translate(points[0][0], points[0][1]);
  ctx.rotate(angle);
  ctx.translate(-33.85, 0);
  ctx.drawImage(this.svg, 0, 0);
  // Adding in the addition of the rocket's thruster if it is active
  if (this.thruster) {
    // First reset the timeout if the thruster key is pushed
    this.flameTimeout = 12;
  }
  // If the timeout is above zero then add the flicker svg
  if (this.flameTimeout > 0) {
    ctx.drawImage(flicker_svg, 0, 0);
    this.flameTimeout--;
  }
  ctx.restore();
  // Loop through all the shots
  for (let i = 0; i < this.shots.length; i++) {
    // And display the shot on the screen
    this.shots[i].render();
  }
}

// For a little variation let the asteroid color depend on the size
function sizeColor(size) {
  if (size > 30) {
    return 2;
  } else if (size > 20) {
    return 1;
  } else {
    return 0;
  }
}

// Define a new Asteroid
function Asteroid(x, y, size, vx, vy) {
  // Position on the x and y axis
  this.x = x;
  this.y = y;
  this.size = size;
  this.radius = size * 2 + 5;
  this.vx = vx;
  this.vy = vy;

  // Store the position of the points on the asteroid
  this.points = [];
  for (let i = 0; i < size; i++) {
    // Calculate random sizes to create an asteroid-like jagged edge
    let dist = Math.random() * 15 - 5 + this.radius;
    // Distrubute the points around the whole circumference of the asteroid
    let angle = i * 360 / size;
    // Add the randomly calculated point to the array
    this.points.push([
      dist * Math.cos(rad(angle)),
      dist * Math.sin(rad(angle))
    ]);
  }

  //Define the color of the asteroid based on the size
  this.color = sizeColor(this.size);

  // Define the methods of the asteroid
  this.explode = explodeAsteroid;
  this.update = updateAsteroid;
  this.move = tesseractMove;
  this.render = renderAsteroid;
}

// Define what happens when the asteroid is blasted by a shot from the rocket
function explodeAsteroid() {
  // Reduce the size by the predefined split size variable
  if (this.size - splitSize >= splitSize - 1) {
    // This leaves two new asteroids, the first being the reduced size of the original
    asteroids.push(
      new Asteroid(this.x, this.y, this.size - splitSize, this.vx, this.vy)
    );
    // The second asteroid is the broken off piece
    asteroids.push(
      new Asteroid(
        this.x,
        this.y,
        splitSize,
        Math.random() * 4 - 2,
        Math.random() * 4 - 2
      )
    );
  }
}

// Update the affects of the asteroid
function updateAsteroid(num) {
  // Set the asteroid's position in an array to check for collisions
  const asteroid_xy = [this.x, this.y];
  // Define a function to check the proximity of the game's active rockets
  function checkProximity(target) {
    // Avoid checking asteroids that have already been removed
    if (asteroids[num] === undefined) {
      return;
    }
    // Need to load in the rocket points to check for collisions
    let rocketPoints = target.getPoints();
    // Check all the rocket's points for collisions
    for (let i = 0; i < rocketPoints.length; i++) {
      // Check whether the rocket has crashed into the asteroid
      let proximityToRocket = checkBoundary(asteroid_xy, [
        rocketPoints[i][0],
        rocketPoints[i][1]
      ]);
      // If the proximity is less than the radius then there has been a collision and reduce the health based on the radius of the asteroid
      if (proximityToRocket < asteroids[num].radius) {
        target.health -= (asteroids[num].radius / 4).toFixed();
        asteroids[num].explode();
        asteroids.splice(num, 1);
        return;
      }
    }
  }

  // Need to check the proximity of both of the players with the asteroids
  checkProximity(player1);
  checkProximity(player2);
  // Don't check an asteroid if it was removed
  if (asteroids[num] === undefined) {
    return;
  } else {
    // Move the asteroids
    asteroids[num].move();
  }
}

// Define the appearance of the asteroids
function renderAsteroid() {
  ctx.beginPath();
  ctx.moveTo(this.x + this.points[0][0], this.y + this.points[0][1]);
  for (let i = this.size - 1; i >= 0; i -= 1) {
    ctx.lineTo(this.x + this.points[i][0], this.y + this.points[i][1]);
  }
  ctx.fillStyle = asteroidColor;
  ctx.fill();
}

// Define a new shot being made in the game
function Shot(x, y, direction, owner) {
  this.x = x;
  this.y = y;
  this.vx = shootingSpeed * Math.cos(rad(direction));
  this.vy = -shootingSpeed * Math.sin(rad(direction));
  this.hit = false;
  this.owner = owner;
  // Define player based shot colours
  if (owner == "one") {
    this.color = "#5ecb84";
  } else {
    this.color = "#EDBB0B";
  }
  // Shot methods
  this.update = updateShot;
  this.render = renderShot;
}

// Update the game affects on the shot
function updateShot(slug) {
  // If the shot goes off screen then just count it as a hit for it to be easily removed from the game
  if (
    this.x > canvas.width + gutter ||
    this.x < 0 - gutter ||
    this.y > canvas.height + gutter ||
    this.y < 0 - gutter
  ) {
    this.hit = true;
  }
  // If the shot hasn't hit anything so far
  if (!this.hit) {
    function checkProximity(target, slug) {
      // Need the rocket to check for collisions
      const points = target.getPoints();
      // Rocket co-ordinates for calculating the areas
      const aX = points[0][0];
      const aY = points[0][1];
      const bX = points[2][0];
      const bY = points[2][1];
      const cX = points[1][0];
      const cY = points[1][1];
      // Shot co-ordinates
      const sX = slug.x;
      const sY = slug.y;
      // Calculate the combined areas of the shot and the target
      const area1 = Math.abs(
        (sX * (bY - cY) + bX * (cY - sY) + cX * (sY - bY)) / 2
      ); // SBC
      const area2 = Math.abs(
        (aX * (sY - cY) + sX * (cY - aY) + cX * (aY - sY)) / 2
      ); // ASC
      const area3 = Math.abs(
        (aX * (bY - sY) + bX * (sY - aY) + sX * (aY - bY)) / 2
      ); // ABS
      const area = (area1 + area2 + area3).toFixed(2);
      // If the rocket area is the same as the area calculated above then the shot has hit the target
      if (rocketArea == area) {
        slug.hit = true;
        target.health--;
      }
    }
    // Only check for collisions with the oposing player
    if (this.owner == "one") {
      checkProximity(player2, this);
    } else {
      checkProximity(player1, this);
    }
  }
  // If the shot still hasn't hit anything and obstacles were enabled
  if (!this.hit && obstacles) {
    // Check all the asteroids for collisions
    for (let i = 0; i < asteroids.length; i++) {
      let proximityToAsteroid = checkBoundary(
        [asteroids[i].x, asteroids[i].y],
        [this.x, this.y]
      );
      // Check whether the proximity is less than the asteroid's radius
      if (proximityToAsteroid <= asteroids[i].radius) {
        // Explode the asteroid which was hit, this creates two smaller asteroids
        asteroids[i].explode();
        // Remove the asteroid from the game
        asteroids.splice(i, 1);
        // The shot has hit something and will be removed from the game
        this.hit = true;
      }
    }
  }
  // Now remove the shot from the game if it has hit something
  if (this.hit == true) {
    return;
  } else {
    // Otherwise move the shot according to the velocity
    this.x += this.vx;
    this.y += this.vy;
  }
}

// Define how the shot looks on screen
function renderShot() {
  ctx.strokeStyle = this.color;
  ctx.lineWidth = 5;
  ctx.beginPath();
  ctx.moveTo(this.x, this.y);
  ctx.lineTo(this.x + this.vx, this.y + this.vy);
  ctx.stroke();
}

// Show the shield health of both players but only update it if there has been a change
function renderScore(target) {
  let count = target.score.innerHTML;
  if (playing && target.health < count) {
    target.score.innerHTML = target.health;
  }
}

// Define a function which is checking for the end of the game
function checkGameStatus() {
  // First check if both players have been destroyed
  if (player1.health <= 0 && player2.health <= 0) {
    gameOver("tie");
    // Check player 1's health
  } else if (player1.health <= 0) {
    gameOver(player1);
    // Check player 2's health
  } else if (player2.health <= 0) {
    gameOver(player2);
  }
}

// Handling the random position of the background planet
function placePlanet(planet) {
  let x = Math.floor(Math.random() * canvas.width);
  let y = Math.floor(Math.random() * canvas.height);
  // Vary the scale to keep the background interesting
  let scale = 0.5 + Math.random() * 2;
  let transform = "translate(" + x + "px, " + y + "px) scale(" + scale + ")";
  planet.style.transform = transform;
}

// Deciding where things should go
function placeElements() {
  // Changing the opacity is to prevent a visual bug
  planet1.style.opacity = 0;
  planet2.style.opacity = 0;
  space.style.opacity = 0;
  // Calculate the new solar system layout
  placePlanet(planet1);
  placePlanet(planet2);
  createStars();
  // Make the elements visible again
  planet1.style.opacity = 1;
  planet2.style.opacity = 1;
  space.style.opacity = 1;
}

// Fill the background with randomly positioned stars
function createStars() {
  let heightMax = window.innerHeight - 4,
    widthMax = window.innerWidth - 4;
  space.innerHTML = "";

  for (let i = 0; i < 50; i++) {
    const star =
      '\n <div style="left:' +
      Math.floor(Math.random() * widthMax) +
      "px; top:" +
      Math.floor(Math.random() * heightMax) +
      "px; height:" +
      Math.ceil(Math.random() * 100) / 100 +
      "vmax; width:" +
      Math.ceil(Math.random() * 100) / 100 +
      'vmax;" class="star star' +
      i +
      '"><svg viewBox="0 0 513 513"><use xlink:href="#star"/></svg></div>';
    space.insertAdjacentHTML("beforeend", star);
  }
}

// Calculate the sizes for the game which are dependent on the window size
function calculateSizes() {
  canvas = document.querySelector("canvas");
  ctx = canvas.getContext("2d");
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  centerPoint = {
    x: canvas.width / 2,
    y: canvas.height / 2
  };
  // Hide the score counter for the start of the game
  scoreboard.style.opacity = 0;
}

// Variables relating to the start screen toggles
let playerOne = true;
let playerTwo = false;
let obstacles = true;

// Inverse the option
function toggleOption(option) {
  return !option;
}

// Switch the player from computer to human
function switchPlayer(target) {
  if (target) {
    return "Computer";
  } else {
    return "Human";
  }
}

// Switch the obstacles on or off
function switchObstacles() {
  if (obstacles) {
    return "Asteroids: On";
  } else {
    return "Asteroids: Off";
  }
}

// Button event listeners
playerOneToggle.addEventListener("click", function() {
  playerOne = toggleOption(playerOne);
  this.textContent = switchPlayer(playerOne);
});

playerTwoToggle.addEventListener("click", function() {
  playerTwo = toggleOption(playerTwo);
  this.textContent = switchPlayer(playerTwo);
});
asteroidsToggle.addEventListener("click", function() {
  obstacles = toggleOption(obstacles);
  this.textContent = switchObstacles();
});

// Define if the player takes the Rocket or Enemy object
function setPlayer(toggle, number) {
  // Checking if the toggle is true which means that it is computer controlled and takes the Enemy class
  if (toggle == true) {
    return new Enemy(number, "computer");
  } else {
    // If not true then the player is human
    return new Rocket(number, "human");
  }
}
// Define the changes to be made at the start of the game
function startGame() {
  // Setup the background
  placeElements();
  // Empty the arrays of asteroids
  asteroids = [];
  // Create the players for the new game
  player1 = setPlayer(playerOne, "one");
  player2 = setPlayer(playerTwo, "two");
  // Define the sworn enemy of the players if they are controlled by the computer
  if (playerOne == true) {
    player1.swornEnemy = player2;
  }
  if (playerTwo == true) {
    player2.swornEnemy = player1;
  }
  // Reset the scoreboard
  shield_p1.innerHTML = player1.health;
  shield_p2.innerHTML = player2.health;
  scoreboard.style.opacity = 1;
  // Hide the explosion
  crash.style.opacity = 0;
  explosion.classList.remove("explode");
  // Close the popup UI
  closePopup();
  // Reset the result and message
  result.innerHTML = "";
  message.innerHTML = "";
  // Set playing to true to start the game!
  playing = true;
  // Set the interval to make the game work
  game_mode = setInterval(function() {
    if (playing) {
      // Clear the canvas
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      // Add new asteroids based on a timeout and if toggled on at the start screen
      if (obstacles) {
        if (
          asteroidTimeout >= asteroidRate &&
          asteroids.length <= asteroidMax
        ) {
          // Choose a side at random
          let side = Math.floor(Math.random() * 2);
          if (side == 0) {
            // Place the asteroid at the left side
            asteroids.push(
              new Asteroid(
                -gutter,
                Math.random() * canvas.height,
                Math.floor(Math.random() * asteroidSizeMax) + 10,
                Math.random() * asteroidSpeed,
                Math.random() * (asteroidSpeed * 2) - asteroidSpeed
              )
            );
          } else if (side == 1) {
            // Place the asteroid at the right side
            asteroids.push(
              new Asteroid(
                canvas.width + gutter,
                Math.random() * canvas.height,
                Math.floor(Math.random() * asteroidSizeMax) + 10,
                Math.random() * -asteroidSpeed,
                Math.random() * (asteroidSpeed * 2) - asteroidSpeed
              )
            );
          }
          // Reset the timeout
          asteroidTimeout = 0;
        } else {
          // If a new asteroid isn't being made then increase the timeout
          asteroidTimeout++;
        }
      }
      // Check for computer controlled players and apply the behaviour algorithm
      if (playerOne == true) {
        player1.behaviour();
      }
      if (playerTwo == true) {
        player2.behaviour();
      }
      // Calculate the player position
      player1.update();
      // Calculate the enemy's position
      player2.update();
      // Check for potential collisions
      collisionPrevention();
      // Loop over the asteroids array and update them all if the obstacles are toggled on
      if (obstacles) {
        for (let i = 0; i < asteroids.length; i++) {
          // Calculate the asteroids' positions
          asteroids[i].update(i);
        }
      }
      // Render the player's position
      player1.render();
      // Render the enemy's position
      player2.render();
      // Loop through and render the asteroids in order of colour to optimize canvas capabilities
      if (obstacles) {
        for (let i = 0; i < asteroidColors.length; i++) {
          asteroidColor = asteroidColors[i];
          for (let j = 0; j < asteroids.length; j++) {
            if (asteroids[j].color == i) {
              // Render the asteroids if the colour matches
              asteroids[j].render();
            }
          }
        }
      }
      // Render the score for both players
      renderScore(player1);
      renderScore(player2);
      // Check for potential game over condition
      checkGameStatus();
    }
    // If the game ends during the updates then make sure that everything gets rendered first before clearing the interval
    if (!playing) {
      clearInterval(game_mode);
    }
  }, 1000 / 60);
}

// Define what happens at the end of the game
function gameOver(target) {
  p1_graphic.style.opacity = 0;
  p2_graphic.style.opacity = 0;
  // Stop the game from being played
  playing = false;
  // If the window was resized
  if (target == "resized") {
    result.innerHTML = "The game is using your screen size.";
    message.innerHTML = "Don't resize the screen during the game.";
  } else if (target == "tie") {
    // If the game was a tie.
    result.innerHTML = "TIE!";
    message.innerHTML = "Both rockets exploded, try again?";
  } else if (target == player1) {
    // If player1 caused the game to end
    p2_graphic.style.opacity = 1;
    result.innerHTML = "Red Rocket Is Victorious!";
  } else if (target == player2) {
    // If player2 caused the game to end
    p1_graphic.style.opacity = 1;
    result.innerHTML = "Blue Rocket Is Victorious!";
  }
  // Set the explosion for the middle of the screen it it was a tie
  if (target == "tie") {
    target = centerPoint;
  }
  // Define the place for the end game graphic to be displayed using the target that caused the game to end
  const x = target.x - explosionSize.width;
  const y = target.y - explosionSize.height;
  // For variation add some rotation to the graphic
  degrees = Math.floor(Math.random() * 360);
  // Compile the transform properties
  const transform =
    "translate(" + x + "px, " + y + "px) rotate(" + degrees + "deg)";
  // Sednd the transform to the container for the graphic
  crash.style.transform = transform;
  // Make the graphic visible
  crash.style.opacity = 1;
  // Add the class that triggers the end game animation
  explosion.classList.add("explode");
  // Make sure that the results popup screen is selected
  popup = document.getElementById("results");
  // Show the popup UI to the player
  openPopup();
}

// Define what to do when the page loads
document.addEventListener("DOMContentLoaded", function(event) {
  // Define the sizes based on the user's window
  calculateSizes();
  // Place the background elements
  placeElements();
  // Open the popup UI for the player
  openPopup();
  // Define keyboard functions
  window.addEventListener(
    "keydown",
    function(event) {
      // If player two is not a computer
      if (playerTwo == false) {
        switch (event.code) {
          case "ArrowUp":
            // Apply Thruster
            player2.thruster = true;
            break;
          case "ArrowLeft":
            // Rotate Left
            player2.rotateLeft = true;
            break;
          case "ArrowRight":
            // Rotate Right
            player2.rotateRight = true;
            break;
          case "Space":
            // Start firing
            player2.fire = true;
            break;
        }
      }
      // If player one is not a computer
      if (playerOne == false) {
        switch (event.code) {
          case "KeyW":
            player1.thruster = true;
            break;
          case "KeyA":
            // Stop rotating Left
            player1.rotateLeft = true;
            break;
          case "KeyD":
            // Stop rotating Right
            player1.rotateRight = true;
            break;
          case "KeyZ":
            // Stop firing
            player1.fire = true;
            break;
        }
      }
    },
    true
  );

  window.addEventListener(
    "keyup",
    function(event) {
      // If player two is not a computer
      if (playerTwo == false) {
        switch (event.code) {
          case "ArrowUp":
            // Apply Thruster
            player2.thruster = false;
            break;
          case "ArrowLeft":
            // Rotate Left
            player2.rotateLeft = false;
            break;
          case "ArrowRight":
            // Rotate Right
            player2.rotateRight = false;
            break;
          case "Space":
            // Start firing
            player2.fire = false;
            break;
        }
      }
      //if player one is not a computer
      if (playerOne == false) {
        switch (event.code) {
          case "KeyW":
            player1.thruster = false;
            break;
          case "KeyA":
            // Stop rotating Left
            player1.rotateLeft = false;
            break;
          case "KeyD":
            // Stop rotating Right
            player1.rotateRight = false;
            break;
          case "KeyZ":
            // Stop firing
            player1.fire = false;
            break;
        }
      }
    },
    true
  );

  // If the window is resized
  window.addEventListener("resize", function(event) {
    // Calculate the new sizes
    calculateSizes();
    // If the game is being played then it should be reset
    if (playing) {
      gameOver("resized");
    }
  });
});

Комментарии

  • Facebook
  • Вконтакте

Похожие статьи