Game "Moon War"

Appearance

Main hero

class Hero {
  constructor(position, lifesCount) {
    this.pos = position;
    this.lifesCount = lifesCount;
    this.sprite = new Sprite('../img/hero.png', [0, 0], [58, 58.4], 2, [0, 1, 2, 1]);
    this.down = new Sprite('../img/hero.png', [0, 0], [58, 58.4], 3, [0, 1, 2, 1]);
    this.up = new Sprite('../img/hero.png', [0, 173], [58, 58.4], 3, [0, 1, 2, 1]);
    this.left = new Sprite('../img/hero.png', [0, 58], [58, 58.4], 3, [0, 1, 2, 1]);
    this.right = new Sprite('../img/hero.png', [0, 116.6], [58, 58.4], 3, [0, 1, 2, 1]);
  }
}

export default Hero;

Enemies

class Enemy {
  constructor(pos) {
    this.pos = pos;
  }
}

class EnemyEasy extends Enemy {
  constructor(pos) {
    super(pos);
    this.lifesCount = 1;
    this.sprite = new Sprite('../img/ufo.png',[115, 89], [52, 38.5], 7,[0, 1, 2, 3, 4, 5, 6, 7]);
  }
}

class EnemyBoss extends Enemy {
  constructor(pos) {
    super(pos);
    this.lifesCount = 6;
    this.sprite = new Sprite('../img/enemy-boss.png',[0, 0],[128, 128],6,[0, 1, 2, 3, 4, 3, 2, 1]);
  }
}

export { EnemyEasy, EnemyBoss };

Towers

class Tower {
  constructor(pos) {
    this.pos = pos;
  }
}
class FiringTower extends Tower {
  constructor(pos) {
    super(pos);
    this.lastFire = Date.now();
    this.sprite = new Sprite('../img/tower.png', [31, 0], [48, 118]);
  }
}

class TrapTower extends Tower {
  constructor(pos) {
    super(pos);
    this.sprite = new Sprite('../img/trap-tower.png',[0, 0],[65, 98],6,[0, 1, 2, 3, 2, 1],);
  }
}
export { FiringTower, TrapTower };
class Bullet {
  constructor(pos, angle) {
    this.pos = pos;
    this.angle = angle;
    this.sprite = new Sprite('../img/bullet.png', [0, 0], [24, 24]);
  }
}
export default Bullet;

Bullet

Explosions

class Explosion {
  constructor(pos) {
    this.pos = pos;
  }
}

class EasyExplosion extends Explosion {
  constructor(pos) {
    super(pos);
    this.sprite = new Sprite(
      "../img/ufo.png",
      [30, 196],
      [73, 59],
      15,
      [0, 1, 2, 3, 4, 5, 6, 7],
      null,
      true
    );
  }
}

class BigExplosion extends Explosion {
  constructor(pos) {
    super(pos);
    this.sprite = new Sprite(
      "../img/enemy-boss-explosion.png",
      [0, 0],
      [96, 96],
      15,
      [0, 1, 2, 3, 4, 5],
      null,
      true
    );
  }
}

export { EasyExplosion, BigExplosion };

Bonuses

class Bonus {
  constructor(pos, pathToImage) {
    this.pos = pos;
    this.sprite = new Sprite(
      pathToImage,
      [0, 0],
      [32, 31],
      6,
      [0, 1, 2, 3, 4, 5, 6, 7],
    );
  }
}

export default Bonus;

Increase bullet speed

increase lives count

kill all enemies

Game

state

const gameState = {
  player: new Hero([0, 0], 3),

  playerSpeed: 170,
  bulletSpeed: 100,
  enemySpeed: 100,

  towers: [],
  trapTowers: [],
  bullets: [],
  enemies: [],
  explosions: [],

  bonusesIncreaseScore: [],
  bonusesIncreaseBulletSpeed: [],
  bonusesKillEnemies: [],

  lastTower: 0,
  lastTrapTower: 0,
  gameTime: 0,
  lastTime: new Date(),
  isGameOver: false,
  isPause: false,
  isMuted: false,
  score: 0,

  scoreEl: document.getElementById("score"),
  lifesCountEl: document.getElementById("lifesCount"),
  canvasContext: undefined,
  canvas: undefined,
  terrainPattern: undefined
};

Load resourses

First

init

function

Game loop

Game

loop

function

Update

function

Update bullets

// Update all the bullets
  for (let i = 0; i < gameState.bullets.length; i += 1) {
    const bullet = gameState.bullets[i];

    const pathBulletLenght = dt * gameState.bulletSpeed;
    const sin = Math.sin(bullet.angle);
    const cos = Math.cos(bullet.angle);

    bullet.pos[0] += sin * pathBulletLenght;
    bullet.pos[1] += cos * pathBulletLenght;

    // Remove the bullet if it goes offscreen
    if (
      bullet.pos[1] < 0 ||
      bullet.pos[1] > gameState.canvas.height ||
      bullet.pos[0] > gameState.canvas.width
    ) {
      gameState.bullets.splice(i, 1);
      i -= 1;
    }
  }

Check collizions function

boxCollides function

function collides(x, y, r, b, x2, y2, r2, b2) {
  return !(r <= x2 || x > r2 || b <= y2 || y > b2);
}

function boxCollides(pos, size, pos2, size2) {
  return collides(
    pos[0],
    pos[1],
    pos[0] + size[0],
    pos[1] + size[1],
    pos2[0],
    pos2[1],
    pos2[0] + size2[0],
    pos2[1] + size2[1],
  );
}

Render

function

Render function

function renderEntity(entity) {
  gameState.canvasContext.save();
  gameState.canvasContext.translate(entity.pos[0], entity.pos[1]);
  entity.sprite.render(gameState.canvasContext);
  gameState.canvasContext.restore();
}

function renderEntities(collection) {
  for (let i = 0; i < collection.length; i += 1) {
    renderEntity(collection[i]);
  }
}

Project structure

Webpack config

const path = require('path');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: ['css-loader', 'sass-loader'],
        }),
      },
      {
        test: /\.(png|jp(e*)g|svg)$/,
        use: [{
          loader: 'url-loader',
          options: {
            limit: 8000, 
            name: 'images/[hash]-[name].[ext]',
          },
        }],
      },
    ],
  },
  plugins: [
    new UglifyJsPlugin(),
    new ExtractTextPlugin('style.css'),
  ],
};

Useful link:

Q&A

Made with Slides.com