So I'm making a 2d shoot'em up game as a way of learning canvas, and larger-scale programming than what I'm accustomed to. I'm a purely front-end web dev, I can't say I'm very experienced in this.Anyway the way I spawn my enemies is like this : at xyz gameTime, a spawner object is pushed into the game. This spawner object add various enemies in various configurations, using that type of interface, I hope the code is self explanatory:state.enemies.push(enemies[this.enemyType].add({  pos: [this.pos[0], this.pos[1]],  angle: this.angle,  rotation: this.enemyRotation,  path: this.path}));But I'm not here for game design review so let me talk about what I want advice on.basically you can see my enemy module here: https://github.com/acezard/aceforceone/blob/develop/src/entities/enemies.jsLet me explain it bit by bit.This is the global config object that manages only the default settings of every enemy type. That is, it doesn't contain any vector/rotation/position infos, because these settings are injected at enemy creation. // Config Objectvar enemyConfig = {  redBomber: {    url: 'assets/images/enemy-xs-1.svg',    pos: [0, 0],    size: [75, 53],    speed: 100,    hitpoints: 10,    ROF: 100,    score: 100,    burst: {      amount: 3,      delay: 1000,      counter: 3    },  },  scout: {    url: 'assets/images/scout.png',    pos: [0, 0],    size: [50, 44],    speed: 500,    hitpoints: 2,    score: 50  },  rotatingPlat: {    url: 'assets/images/platpart.png',    pos: [0, 0],    size: [150, 44],    speed: 30,    hitpoints: 100,    ROF: 200,    score: 250,    burst: {      amount: 1000,      delay: 1000,      counter: 1000    },  },  rogueLeader: {    url: 'assets/images/rogueleader.svg',    pos: [0, 0],    size: [200, 89],    speed: 100,    hitpoints: 60,    score: 300,    ROF: 500,  },  drone: {    url: 'assets/images/drone.svg',    pos: [0, 0],    size: [50, 62],    speed: 300,    hitpoints: 5,    score: 75  },};Next we have a global enemy constructor, managing every enemy type as a base. It contains a mix of the default settings shown above, and the what I call active settings, that is, arguments different for every enemy entity even if they are of the same type (like position). This constructor also have the basic methods and a blank shoot method, because each enemy type has his own implementation (doesn't seem right?).// Base enemy constructorvar EnemyEntity = function(settingsDefault, settingsActive) {  // Default  this.active = true;  this.speed = settingsDefault.speed;  this.hitpoints = settingsDefault.hitpoints;  this.lastFire = Date.now();  this.score = settingsDefault.score;  this.ROF = settingsDefault.ROF || null;  this.maxHitpoints = settingsDefault.hitpoints;  this.rotating = settingsDefault.rotating || null;  if (settingsDefault.burst) {    this.burst = {      amount: settingsDefault.burst.amount,      delay: settingsDefault.burst.delay,      counter: settingsDefault.burst.counter    };  }  this.sprite = new Sprite({    url: settingsDefault.url,    pos: settingsDefault.pos,    size: settingsDefault.size,    rotated: true  });  // Active  this.angle = settingsActive.angle;  this.pos = settingsActive.pos;  this.radians = settingsActive.angle * Math.PI / 180;  this.vector = [Math.cos(this.radians) * this.speed, Math.sin(this.radians) * this.speed];  this.rotation = settingsActive.rotation || 0;  this.path = settingsActive.path || null;};// Update methodEnemyEntity.prototype.shoot = function() {};EnemyEntity.prototype.update = function(dt) {  if (this.outOfBounds()) {    this.active = false;    return;  }  if (this.path == angular) {    paths.angular(this);  }  this.pos[0] += this.vector[0] * dt;  this.pos[1] += this.vector[1] * dt;};EnemyEntity.prototype.outOfBounds = function() {  return this.pos[1] > canvas.height || this.pos[0] < 0 || this.pos[0] > canvas.width;};// Draw methodEnemyEntity.prototype.render = function() {    canvas.ctx.save();    canvas.ctx.translate(this.pos[0], this.pos[1]);    canvas.ctx.translate(this.sprite.size[0] / 2, this.sprite.size[1] / 2);    canvas.ctx.rotate(Math.PI / 180 * this.rotation);    this.sprite.render(canvas.ctx);    canvas.ctx.restore();};This part is another constructor, used to create enemy factories. Basically its only role is to share an ADD method, used by every enemy factory.// Factory constructorvar EnemyFactory = function() {};EnemyFactory.prototype.add = function(settings) {   return new this.type(settings);};Now this is an example of what a specific enemy factory looks like. I put two so you can see how much WET code this is. Basically, we first create a constructor, by calling the EnemyEntity constructor with this, and with the active settings. We also get enemyentity methods with calling it as a prototype. The shoot function is different for each enemy.Then we have the enemy factory per se, basically it's constructed from the EnemyFactory constructor, and giving the specific Enemy constructor as a type, so we then can use myEnemy.add(activeSettings);// RedBombervar RedBomber = function(settings) {  EnemyEntity.call(this, enemyConfig.redBomber, settings);};RedBomber.prototype = Object.create(EnemyEntity.prototype);RedBomber.prototype.shoot = function() {  var now = Date.now();  // If the enemy can shoot  if (this.pos[1] > 0 && this.burst.counter && now - this.lastFire > this.ROF) {    var x = this.pos[0] + this.sprite.size[0] / 2;    var y = this.pos[1] + this.sprite.size[1] / 2;    state.ebullets.push(weapons.red.addMissile({x: x, y: y, angle: 90}));    state.ebullets.push(weapons.red.addMissile({x: x, y: y, angle: 80}));    state.ebullets.push(weapons.red.addMissile({x: x, y: y, angle: 100}));    this.burst.counter--;    this.lastFire = now;    return;  } else  if (!this.burst.counter && now - this.lastFire > this.burst.delay) {    this.burst.counter = this.burst.amount;  }};function RedBomberFactory () {};RedBomberFactory.prototype = new EnemyFactory();RedBomberFactory.prototype.type = RedBomber;var redBomber = new RedBomberFactory();// Rogue Leadervar RogueLeader = function(settings) {  EnemyEntity.call(this, enemyConfig.rogueLeader, settings);};RogueLeader.prototype = Object.create(EnemyEntity.prototype);RogueLeader.prototype.shoot = function() {  var now = Date.now();  // If the enemy can shoot  if (this.pos[1] > 0 && now - this.lastFire > this.ROF) {    var x = this.pos[0];    var y = this.pos[1];    state.ebullets.push(weapons.redRay.addMissile({x: x + this.sprite.size[0] * 0.3, y: y + this.sprite.size[1] * 0.6, angle: this.rotation - 90}));    state.ebullets.push(weapons.redRay.addMissile({x: x + this.sprite.size[0] * 0.7, y: y + this.sprite.size[1] * 0.6, angle: this.rotation - 90}));    this.lastFire = now;  }};function RogueLeaderFactory () {};RogueLeaderFactory.prototype = new EnemyFactory();RogueLeaderFactory.prototype.type = RogueLeader;var rogueLeader = new RogueLeaderFactory();Then we exports our factory functionsmodule.exports = {  redBomber: redBomber,  scout: scout,  rotatingPlat: rotatingPlat,  rogueLeader: rogueLeader,  drone: drone};What's the problem then ? As you can see there is a lot of repetition in my code, every new enemy type adds a LOT of code, but I only really need the shoot method. Though I'm not sure right now how I could manage that better and ask for your advice. Any other consideration of the code is of course much appreciated
2d game enemy entities factories, probably in need of refactoring
javascript;object oriented;game;constructor;factory method