text: const Engine = Matter.Engine;
  const World = Matter.World;
  const Bodies = Matter.Bodies;
  const Constraint = Matter.Constraint;
  var engine,
    world,
    backgroundImg,
    waterSound,
    pirateLaughSound,
    backgroundMusic,
    cannonExplosion;
  var canvas, angle, tower, ground, cannon, boat;
  var balls = [];
  var boats = [];
  var score = 0;
  var boatAnimation = [];
  var boatSpritedata, boatSpritesheet;
  
  var brokenBoatAnimation = [];
  var brokenBoatSpritedata, brokenBoatSpritesheet;
  
  var waterSplashAnimation = [];
  var waterSplashSpritedata, waterSplashSpritesheet;
  
  var isGameOver = false;
  
  function preload() {
    backgroundImg = loadImage("./assets/background.gif");
    backgroundMusic = loadSound("./assets/background_music.wav");
    waterSound = loadSound("./assets/cannon_water.wav");
    pirateLaughSound = loadSound("./assets/pirate_laugh.wav");
    cannonExplosion = loadSound("./assets/cannon_explosion.wav");
    towerImage = loadImage("./assets/tower.png");
    boatSpritedata = loadJSON("assets/boat/boat.json");
    boatSpritesheet = loadImage("assets/boat/boat.png");
    brokenBoatSpritedata = loadJSON("assets/boat/broken_boat.json");
    brokenBoatSpritesheet = loadImage("assets/boat/broken_boat.png");
    waterSplashSpritedata = loadJSON("assets/water_splash/water_splash.json");
    waterSplashSpritesheet = loadImage("assets/water_splash/water_splash.png");
  }
  
  function setup() {
    canvas = createCanvas(windowWidth - 200, windowHeight - 150);
    engine = Engine.create();
    world = engine.world;
    angle = -PI / 4;
    ground = new Ground(0, height - 1, width * 2, 1);
    tower = new Tower(width / 2 - 650, height - 290, 250, 580);
    cannon = new Cannon(width / 2 - 600, height / 2 - 220, 120, 40, angle);
  
    var boatFrames = boatSpritedata.frames;
    for (var i = 0; i < boatFrames.length; i++) {
      var pos = boatFrames[i].position;
      var img = boatSpritesheet.get(pos.x, pos.y, pos.w, pos.h);
      boatAnimation.push(img);
    }
  
    var brokenBoatFrames = brokenBoatSpritedata.frames;
    for (var i = 0; i < brokenBoatFrames.length; i++) {
      var pos = brokenBoatFrames[i].position;
      var img = brokenBoatSpritesheet.get(pos.x, pos.y, pos.w, pos.h);
      brokenBoatAnimation.push(img);
    }
  
    var waterSplashFrames = waterSplashSpritedata.frames;
    for (var i = 0; i < waterSplashFrames.length; i++) {
      var pos = waterSplashFrames[i].position;
      var img = waterSplashSpritesheet.get(pos.x, pos.y, pos.w, pos.h);
      waterSplashAnimation.push(img);
    }
  }
  
  function draw() {
    background(189);
    image(backgroundImg, 0, 0, width, height);
  
    if (!backgroundMusic.isPlaying()) {
      backgroundMusic.play();
      backgroundMusic.setVolume(0.1);
    }
  
    Engine.update(engine);
    ground.display();
  
    showBoats();
  
    for (var i = 0; i < balls.length; i++) {
      showCannonBalls(balls[i], i);
      for (var j = 0; j < boats.length; j++) {
        if (balls[i] !== undefined && boats[j] !== undefined) {
          var collision = Matter.SAT.collides(balls[i].body, boats[j].body);
          if (collision.collided) {
            if (!boats[j].isBroken && !balls[i].isSink) {
              score += 5;
              boats[j].remove(j);
              j--;
            }
  
            Matter.World.remove(world, balls[i].body);
            balls.splice(i, 1);
            i--;
          }
        }
      }
    }
  
    cannon.display();
    tower.display();
  
    fill("#6d4c41");
    textSize(40);
    text(`Score:${score}`, width - 200, 50);
    textAlign(CENTER, CENTER);
  }
  
  function keyPressed() {
    if (keyCode === DOWN_ARROW) {
      var cannonBall = new CannonBall(cannon.x, cannon.y);
      cannonBall.trajectory = [];
      Matter.Body.setAngle(cannonBall.body, cannon.angle);
      balls.push(cannonBall);
    }
  }
  
  function showCannonBalls(ball, index) {
    ball.display();
    ball.animate();
    if (ball.body.position.x >= width || ball.body.position.y >= height - 50) {
      if (!ball.isSink) {
        waterSound.play();
        ball.remove(index);
      }
    }
  }
  
  function showBoats() {  
    if (boats.length > 0) {
      if (
        boats.length < 4 &&
        boats[boats.length - 1].body.position.x < width - 300
      ) {
        var positions = [-130, -100, -120, -80];
        var position = random(positions);
        var boat = new Boat(
          width,
          height - 100,
          200,
          200,
          position,
          boatAnimation
        );
  
        boats.push(boat);
      }
  
      for (var i = 0; i < boats.length; i++) {
        Matter.Body.setVelocity(boats[i].body, {
          x: -0.9,
          y: 0
        });
  
        boats[i].display();
        boats[i].animate();
        var collision = Matter.SAT.collides(tower.body, boats[i].body);
        if (collision.collided && !boats[i].isBroken) {
          pirateLaughSound.play();
          isGameOver = true;
          gameOver();
        }
      }
    } else {
      var boat = new Boat(width, height - 100, 200, 200, -100, boatAnimation);
      boats.push(boat);
    }
  }
  
  function keyReleased() {
    if (keyCode === DOWN_ARROW && !isGameOver) {
      cannonExplosion.play();
      balls[balls.length - 1].shoot();
    }
  }
  
  function gameOver() {
    swal(
      {
        title: `Game Over!!!`,
        text: "Thanks for playing!!",
        imageUrl:
          "https://raw.githubusercontent.com/whitehatjr/PiratesInvasion/main/assets/boat.png",
        imageSize: "150x150",
        confirmButtonText: "Play Again"
      },
      function(isConfirm) {
        if (isConfirm) {
          location.reload();
        }
      }
    );
  }
  