8 Enemy movement
This chapter expands the game by introducing enemy asteroids that the player must dodge or shoot, focusing on how to create, position, and move them efficiently on NES hardware. To achieve variety, it emphasizes randomness for both spawn timing and placement, and addresses the challenge of generating convincing pseudo-random sequences within tight 8-bit performance constraints. Seeds for randomness are derived from human input timing (when the player leaves the title screen) using a 16-bit time counter, ensuring that each playthrough feels different as asteroids drift downward and are removed upon reaching the ground.
The implementation adds two random number routines: a lightweight, shift-based generator and a stronger routine that merges two linear sequences (a software take on an LFSR), returning two bytes for broader use. After seeding from the elapsed title-screen time, the game introduces new zero-page variables to manage difficulty level, animation state, a pool of enemy slots, a cooldown to pace spawns, and temporary storage. A setup routine clears enemy data and initializes cooldowns; the spawn routine then counts down, tests a randomness threshold scaled by difficulty, finds a free slot among a fixed number of enemies, computes the base OAM index for that enemy (four sprites per enemy, skipping sprites reserved for the player), initializes tile indices and attributes, places the enemy at the top of the screen, and sets an X position from a masked random value.
Movement is handled by iterating over active enemies each frame: the code calculates the correct OAM offset, reads and increments the Y position to make the asteroid fall, and either updates all four sprites or, if the bottom boundary is reached, hides them and frees the slot. The main loop now polls input, updates the player bullet, spawns enemies according to cooldown and difficulty, and advances enemy motion. When built and run, the result is a playable scene where meteors appear unpredictably across the top and steadily descend to the planet’s surface, establishing a solid foundation for more advanced enemy behaviors introduced later.
Our game so far
Summary
- It is hard to create truly random numbers on 8-bit systems, especially when trying to not take up too much computational time to generate them.
- To make random numbers even more random it is a good idea to introduce an external random factor from the person playing the game.
- Breaking logic up into different functions makes them easier to understand and modify later.
- The enemies in our game will be displayed using up to four separate sprites, so allowing for ten enemies we will use up to 40 of the 64 available sprites for enemies.
- We have only introduced one type of enemy so far; in later chapters, we will add more enemy types and make their movement more complex.
Classic Game Programming on the NES ebook for free