Okay, let's create a basic side-scrolling shooter game inspired by Defender, all within a single HTML file.
This sets up a basic game where you control a green ship, shoot yellow bullets at red enemies scrolling from the right. Use the arrow keys to move and the spacebar to shoot. If an enemy hits your ship, the game ends.
Okay, let's upgrade the visuals with pixel art for the player, enemies, and bullets, including a thruster effect for the player and a simple explosion effect.
This will make the code significantly longer, as we need to define the pixel data and a function to draw it.
Now the game uses pixel art defined directly in the code. The PIXEL_SCALE
variable controls how large these "pixels" appear on the screen. We've added:
drawPixelArt
function to render this data.explosions
array and related functions to show a brief animation when enemies are destroyed or the player crashes.image-rendering: pixelated
in CSS and ctx.imageSmoothingEnabled = false
in JS for sharp pixels.*_Okay, let's add a scrolling 8-bit pixel art space background with stars and planets.
We'll define the background pixel data, add new colors, and implement scrolling logic.
The background now features procedurally generated stars and a couple of simple planets. It scrolls horizontally at a constant speed, creating a parallax effect relative to the enemies and player. The clearCanvas
function is removed as the background drawing now covers the entire canvas each frame.
You are absolutely right! My apologies. By optimizing drawPixelArt
to skip drawing the background color (index 0) for performance, I inadvertently caused ghosting because the background wasn't explicitly clearing the areas where sprites used to be.
Let's fix drawPixelArt
to draw the background color (index 0) when rendering the background itself. This will effectively clear the canvas each frame before drawing other elements.
The key change is in the drawPixelArt
function:
isBackground
boolean parameter (defaulting to false
).if (colorIndex !== undefined && colors[colorIndex] && (colorIndex !== 0 || isBackground))
drawPixelArt
for the background in drawBackground
, we now pass true
as the last argument: drawPixelArt(pixelArt.background, ..., true);
This ensures that when the background is drawn, it does draw the space color (index 0), effectively clearing the canvas and preventing ghost images of the sprites from the previous frame. All other sprites (player, enemies, bullets, explosions) still skip drawing their transparent parts (index 0) by default.
Okay, let's add more enemy variety and give the player and enemies a visual refresh with more detailed pixel art.
We'll introduce:
Key changes:
player
, enemy_cruiser
, enemy_scout
, enemy_waver
) and updated bullet
and thruster
/explosion
slightly.ENEMY_TYPES
Object: Defined properties (speed, score, art reference, specific behavior parameters like wave amplitude/frequency) for each enemy type.spawnEnemy
): Randomly selects an enemy type, retrieves its art and properties, calculates its dimensions, and stores relevant info (like initialY
for wavers) in the enemy object.updateEnemies
): Includes specific logic for the 'WAVER' type to modify its y
position based on a sine wave.checkCollisions
): Uses the score
value stored in the specific enemy object when awarding points. Also added an explosion for the enemy when it collides with the player.width
, height
) are now calculated and stored per-enemy in spawnEnemy
based on their specific art, making the system more flexible for varying sprite sizes.You should now see a redesigned player ship and encounter red cruisers, fast purple scouts, and vertically oscillating cyan wavers.*
Okay, let's give the enemy ships more distinct shapes and refined color schemes to make them look more like unique spacecraft.
I'll redesign the Cruiser, Scout, and Waver with more detail.
Changes made:
enemy_cruiser
, enemy_scout
, and enemy_waver
in pixelArt
with new designs.colors
object to accommodate the new enemy designs, remapping indices as needed (e.g., bullet is now 13, white star is 16).pixelArt
.The enemies should now have more distinct visual identities.*_
Okay, adding lives, levels, bosses, and unique boss attacks significantly increases the complexity. We'll implement:
This will make the code considerably longer.
Summary of Major Additions:
playerLives
variable, updateLivesDisplay
, playerHit
function handles damage and invulnerability, game over condition changed.♥
) are used for lives.gamePhase
('PLAYING', 'BOSS_FIGHT', 'LEVEL_TRANSITION', 'GAME_OVER') to control game flow.checkLevelUp
triggers the boss fight based on score (SCORE_PER_LEVEL
).boss_level1
) and colors.boss
object holds state (health, position, attack pattern, etc.).spawnBoss
, updateBoss
, drawBoss
functions.bossBullets
array and corresponding update/draw functions.executeBossAttack
implements Spread Shot, Targeted Burst (simplified), and Spiral Shot based on boss.currentAttackPattern
.LEVEL_TRANSITION
phase) after defeating the boss before the next level starts.checkCollisions
to handle player bullets vs boss, player vs boss bullets, and player vs boss body.This is a substantial update. You now have lives, a level structure leading to a boss fight with distinct attack patterns, and a proper game over sequence._
Okay, this is a major upgrade! We'll enhance Boss 1's attacks, add Boss 2 and Boss 3 with unique art and attack patterns, and integrate the level progression.
Enhancements & Additions:
This will make the code significantly longer, especially the pixelArt
, colors
, BOSS_CONFIG
, and executeBossAttack
sections.
Key Changes Overview:
BOSS_CONFIG
: Centralized configuration for each boss (health, score, speed, art names, attack timings, bullet types).updateBossHealthBar
.spawnBoss
: Now takes the level
and uses BOSS_CONFIG
to set up the correct boss.executeBossAttack
: Massively expanded with if (level === ...)
blocks and switch(patternIndex)
for each boss's unique attacks. Implemented logic for the new patterns (homing, streams, sweeps, spawns, orbs, curtains).updateBossBullets
: Added logic for 'homing' bullet type and 'lifetime' property.spawnEnemy
: Modified to allow forcing a type and position, used by Boss 3's spawn attack.GAME_WON
phase.MAX_LEVEL
and triggering the GAME_WON
state.This version is significantly more complex but provides a much richer experience with varied boss encounters.*