Creating Enemies

The space pirates are vicious, diving in and firing randomly. Our player needs to be alert and quick to survive. The programming for the enemy needs to handle spawning, flying about, and firing. We can borrow some concepts from player.ts, but most of them will require new code. Open up enemy.ts and create a new function updateEnemyState with the same signature as updatePlayerState. The first thing in this function is to determine whether we should spawn a new enemy ship:

 // Enemy appears, moves down 1/3 of the map, then turns
 // Spawn a new enemy ship if needed
 if​ (gameState.enemy.x <= -config.enemy.width ||
  gameState.enemy.x > config.canvas.width ||
  !gameState.enemy.alive
 ) {
 let​ xStart = randInt(
  config.enemy.width,
  config.canvas.width - config.enemy.width
  );
  gameState.enemy.alive = ​true​;
  gameState.enemy.y = -config.enemy.height;
  gameState.enemy.x = xStart;
  gameState.enemy.dy = config.enemy.speed;
  gameState.enemy.dx = 0;
 }

If the enemy has moved offscreen, or they’ve been hit by the player, we should create a new enemy just off the upper edge of the screen. This one’s alive and coming for revenge. The dy property is initially set, causing the pirate to move downward along the y axis. There’s no lateral movement in the first phase, so dx is set to 0.

Joe asks:
Joe asks:
What does the d stand for?

The d in dx/dy stands for “change”. It comes from the mathematical symbol delta, which indicates a change in something. In most canvas contexts, it’s a convention used to represent “this object is moving along an axis at this speed.”

Now that the enemy has spawned, it’s time to move them toward the player. The enemy ship should move down the top third of the screen, then turn to a side and escape.

 // Once 1/3 point is reached, turn to a side
 if​ (gameState.enemy.y >= config.canvas.height / 3 &&
  gameState.enemy.dx === 0
 ) {
 let​ leftOrRight = Math.random() > 0.5;
  gameState.enemy.dy = 0;
  gameState.enemy.dx = config.enemy.speed * (leftOrRight ? 1 : -1);
 }

Finally, we need to update the x/y coordinates of the enemy ship; otherwise it’ll just hang offscreen for eternity:

 gameState.enemy.x += gameState.enemy.dx;
 gameState.enemy.y += gameState.enemy.dy;
 return​ gameState;

You’ll also want to add a function to update the lasers property on the enemy. This works the same way as the lasers from the player’s ship.

 function​ updateEnemyLasers(gameState: GameState): GameState {
  gameState.enemy.lasers
  .forEach(l => l.y += config.laser.speed);
 return​ gameState;
 }

Enemy laser firing presents a different design problem. We’re less worried about the current state of the keyboard and more about creating an engaging challenge. We can reuse triggerEvery, but need to pass in a new set of criteria. We’ll skip the condition parameter—whenever the pirates have an opportunity to fire, they will. Instead, we create a random time interval and fire a laser whenever that time is up:

 let​ nextEnemyFire = () => randInt(500, 1500);
 function​ fireEnemyLaser(gameState: GameState): GameState {
 let​ availableLaser = gameState.enemy.lasers.find(l =>
  l.y > config.canvas.height + config.laser.height
  );
 if​ (!availableLaser) { ​return​ gameState; }
 let​ offset = (config.enemy.width / 2) - (config.laser.width / 2);
  availableLaser.x = gameState.enemy.x + offset;
  availableLaser.y = gameState.enemy.y + config.enemy.height;
 return​ gameState;
 }

Now that all this state manipulation is set up, we’ll attach it to the Rx backbone with the same update/render pattern as the player ship:

 export​ ​function​ updateEnemies(obs: Observable<GameState>) {
 return​ obs
  .pipe(
  map(updateEnemyState),
  map(updateEnemyLasers),
  triggerEvery(fireEnemyLaser, nextEnemyFire)
  );
 }
 
 export​ ​function​ renderEnemies(state: GameState) {
  ctx.drawImage(enemyImg, state.enemy.x, state.enemy.y);
 }

Now we’ve got a rousing space battle on our hands—player and pirate fighting back and forth in a desperate battle for survival! Except both will easily survive—we haven’t programmed in any sort of collision detection or destruction mechanics. Time to fix that.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.139.86.18