javascript – Make two random enemies shoot projectiles every second

Your second code looks better on the surface, but it has a couple problems:

Random sort bias .sort(() => 0.5 - Math.random()) is biased – elements that occur earlier in the array will be chosen at a different frequency than elements that appear later (in most JS implementations, at least). For an extended description of this problem, see this page. If you want to shuffle an array, you’ll probably want to use the fischer-yates shuffle.

Sorting is expensive – given an array of size N, sorting it will take on the order of N(log N) operations. If there are a large number of items in the array, this could be a problem. I bet there won’t be enough in your situation for the performance impact to be noticeable, but it’s still somewhat inelegant to sort when sorting isn’t needed. Choosing two indicies that aren’t the same – what you’re doing in the first code – is the better approach.

So, to clean up your first code:

Abstract away distinct parts of the logic into functions to keep code readable and avoid long functions. That is, it’d be good if your first code could be refactored to something somewhat resembling the following:

let req;
let timer = 0
function animate() {
  req = requestAnimationFrame(animate);
  ctx.clearRect(0, 0, canvas.width, canvas.height); // maybe put this into the function below
  initialGameLogic();
  haveEnemiesShoot();
  otherGameLogic();
  timer++
}

animate();

Do you really need to save the callback ID from requestAnimationFrame? Are you using cancelAnimationFrame somewhere? If so, it’s needed – if you aren’t, you can remove the req variable.

timer name isn’t very precise – it’s not completely obvious what it refers to until you read how it’s used. Consider calling it something like frameNumber instead.

Selecting random indicies This is the big one. A reasonably clean way to approach this that I’d prefer would be to copy the array, then select random indicies and splice them out until the number of projectiles is reached or the array is empty:

const enemiesCopy = (...enemies);
const enemiesToShoot = ();
while (enemiesToShoot.length < 2 && enemiesCopy.length) {
  const (enemy) = enemies.splice(Math.floor(Math.random() * enemiesLength), 1);
  enemiesToShoot.push(enemy);
}
for (const enemy of enemiesToShoot) {
  enemy.shootProjectile();
}

This is easily adaptable to any number of projectiles – just change the 2 to a variable that gets altered as needed.