[Vuejs]-Initiate random class from Class Array in JavaScript

0👍

I think you have missed length call on the array:

...Math.random()*this.possibleEnemies.length)]

Note: Modified the answer based on the modified question 🙂

The following example shows the random creation of an object using plain Javascript. Please check your Vue specific imports and other stuff.

class Slime {
    constructor() {
        console.log('Creating Slime');
    }
    printName() {
        console.log('Slime');
    }
}
class Abc {
    constructor() {
        console.log('Creating Abc');
    }
    printName() {
        console.log('Abc');
    }
}
class Xyz {
    constructor() {
        console.log('Creating Xyz');
    }
    printName() {
        console.log('Xyz');
    }
}
possibleEnemies = [Slime, Abc, Xyz];
let enemy = new possibleEnemies[Math.floor(Math.random() * possibleEnemies.length)]();
console.log("enemy: " + enemy);
enemy.printName();

0👍

Here’s a little refactoring of your code. Since the minimum/maximum health, etc. of a type of enemy should probably not be an instance property, I’ve moved them into a separate enemyConfigs mapping, and the base Enemy constructor takes care of rolling the stats for each enemy as it’s constructed. The neat trick here is that the per-enemy-class configurations are partial; anything you don’t define there is taken from the base enemy configuration.

(It’s unfortunate that there’s apparently no typescript-safe way to override statics in an inheritance hierarchy; otherwise I would’ve done that instead of a separate mapping per enemy type.)

Oh, and spawning enemies from the list of classes works just fine . . .

type MinMax = [number, number];

interface EnemyConfig {
  gold: MinMax;
  health: MinMax;
  attackSpeed: MinMax;
  damage: MinMax;
}

const baseEnemyConfig: EnemyConfig = {
  gold: [0, 0],
  health: [1, 1],
  attackSpeed: [0, 0],
  damage: [0, 0],
};

function initializeNumber([min, max]: MinMax): number {
  return min + Math.floor(Math.random() * (max - min));
}

class Enemy {
  public gold: number;
  public health: number;
  public maxHealth: number;
  public attackSpeed: number;
  public damage: number;

  constructor(config?: Partial<EnemyConfig>) {
    const fullConfig = { ...baseEnemyConfig, ...config };
    this.gold = initializeNumber(fullConfig.gold);
    this.health = this.maxHealth = initializeNumber(fullConfig.health);
    this.attackSpeed = initializeNumber(fullConfig.attackSpeed);
    this.damage = initializeNumber(fullConfig.damage);
  }

  public makeNoise(): string {
    return "...";
  }
}

const enemyConfigs: Record<string, Partial<EnemyConfig>> = {
  Goblin: {
    gold: [1, 3],
    health: [3, 6],
    // ... etc
  },
  Titan: {
    gold: [200, 300],
    health: [100, 300],
  },
};

class Goblin extends Enemy {
  constructor() {
    super(enemyConfigs.Goblin);
  }

  public makeNoise() {
    return "Gob!";
  }
}
class Titan extends Enemy {
  constructor() {
    super(enemyConfigs.Titan);
  }

  public makeNoise() {
    return "Titan toot!";
  }
}

const enemyClasses = [Goblin, Titan];

function spawnEnemies(n: number): Array<Enemy> {
  const enemies = [];
  for (let i = 0; i < n; i++) {
    const cls =
      enemyClasses[Math.floor(Math.random() * enemyClasses.length)];
    const enemy = new cls();
    enemies.push(enemy);
  }
  return enemies;
}

const enemies = spawnEnemies(10);

enemies.forEach((enemy) => {
  console.log(enemy.makeNoise(), enemy.health, enemy.gold);
});

This prints out e.g.

[LOG]: "Gob!",  3,  2 
[LOG]: "Titan toot!",  208,  246 
[LOG]: "Gob!",  5,  1 
[LOG]: "Titan toot!",  206,  254 
[LOG]: "Gob!",  3,  1 
[LOG]: "Titan toot!",  210,  262 
[LOG]: "Titan toot!",  168,  229 
[LOG]: "Gob!",  5,  2 
[LOG]: "Gob!",  5,  2 
[LOG]: "Titan toot!",  207,  236 

You can find this on the TypeScript playground too.

Leave a comment