Remastered version of the incredible Asteroids (1979) retro space-game.
You can download the latest version for your x64/ARM (Windows, macOS, Linux) system!
|
|
|
# Install/update dependencies
make sync
# Run from source
make run
# Run tests
make test
# Build macOS app bundle (ARM64 on Apple Silicon)
make build
# Open built app
make openmake buildgenerates a macOS.icnsicon fromsprites/ship.png(build-icon) and passes it to PyInstaller.make testrunspytestin headless pygame mode.- Cleanup helpers:
make cleanremovesbuild/,dist/, andasteroids.specmake distcleanalso removes all__pycache__/directories
- Test runner:
pytest(headless pygame setup viatests/conftest.py). - Local run:
make test(oruv run --group dev pytest). - CI:
.github/workflows/tests.ymlruns tests on pushes tomainand on pull requests.
Releases are manual via GitHub Actions (workflow_dispatch) using .github/workflows/release.yml.
- Run from branch:
mainonly. - Inputs:
release_strategy(auto | major | minor | patch),prerelease,dry_run. - SemVer for
auto:majoron breaking changes,minoronfeat:,patchonfix:,perf:, orrefactor:. - Real release runs update
pyproject.tomlandCHANGELOG.md, then create/push the release tag. - Real release runs also build and upload PyInstaller archives for
macos-arm64,macos-x64,windows-x64, andlinux-x64. - Build pipeline derives app icons from
sprites/ship.png(titlebar icon in windowed mode and packaged binary icon). - macOS artifacts are unsigned and may require manual “Open Anyway” in system settings.
game/
config/ # Game constants and tuning knobs
core/ # Shared base types (e.g. CircleShape)
entities/ # Player, asteroids, shots
systems/ # Spawners and game systems
render/ # Texture/sprite helpers
utils/ # Logging and diagnostics
main.py # Entry point
images/ # UI/background/loading art
sprites/ # Art assets
This codebase is organized around a small game loop plus modular gameplay/rendering components.
main.py:- Owns the top-level state machine (
menu,playing,game_over). - Runs startup bootstrapping (
StartupScreen) and prewarms heavy render assets. - Processes input events and core gameplay rules (damage, collisions, transitions).
- Creates and resets game sessions (sprite groups + runtime state like health).
- Owns the top-level state machine (
game/config/constants.py:- Single source of truth for tunables: physics, timings, screen size, assets, UI layout.
- Changing gameplay feel should usually start here.
game/core/circleshape.py:- Base class for circular world objects.
- Provides shared data (
position,velocity,radius) and behavior (collides_with,wrap_around_screen).
game/entities/player.py(Player):- Handles movement, rotation, acceleration, shooting, cooldowns, and invulnerability visuals.
- Extends
CircleShape.
game/entities/asteroid.py(Asteroid):- Asteroid movement and split behavior.
- Uses sprite textures generated by
game/render/asteroid_texture.py. - Extends
CircleShape.
game/entities/shot.py(Shot):- Projectile lifetime, movement, wrap behavior, and directional sprite rendering.
- Extends
CircleShape.
game/entities/explosion.py(Explosion):- Visual effect entity for asteroid hits (GIF frames when available, procedural fallback otherwise).
game/systems/asteroidfield.py(AsteroidField):- Spawning system that periodically injects asteroids into the world.
game/render/renderer.py(GameRenderer):- Centralized rendering and presentation layer.
- Loads/caches backgrounds, menu option images, border frame, fonts.
- Draws each scene and presents the fixed-size game surface centered inside the display.
game/render/startup.py(StartupScreen):- Handles launch-time loading screen rendering.
- Displays
images/loading.pnginside the same centered viewport composition used by gameplay. - Enforces minimum loading-screen duration and keeps the window responsive while assets warm up.
game/render/asteroid_texture.py:- Loads asteroid sprite variants, selects by size class, scales/caches textures.
game/utils/logger.py:- Lightweight structured logging for game state and gameplay events.
+----------------------+
| main.py |
| boot + loop + states |
+----------+-----------+
|
+-------------------+---------------------------+
| | |
+---------v---------+ +-------v--------+ +--------v--------+
| StartupScreen | | Game Session | | GameRenderer |
| loading image + | | pygame groups +| | draw scenes + |
| min startup time | | runtime state | | present display |
+-------------------+ +-------+--------+ +--------+--------+
| |
+-------+--------+ +-------+------------------+
| | | |
+----v-----+ +------v-------+ | backgrounds/border/ |
| updatable| | drawable | | menu assets + viewport |
| sprites | | sprites | | composition |
+----+-----+ +------+-------+ +---------------------------+
| |
+-------------------------v----------------v-------------------------+
| entities: Player, Asteroid, Shot, Explosion |
| base behavior from CircleShape (position/velocity/radius, |
| collision checks, wrap-around) |
+-------------------------+------------------------------------------+
|
+----v-------------------+
| systems: AsteroidField |
| (spawning/timing) |
+------------------------+
- Startup phase:
StartupScreendraws the loading image and frame while renderer/texture resources are initialized.- A minimum startup duration prevents quick-load flicker on fast machines.
- Simulation updates on a fixed loop cadence (
clock.tick(60)target). - Entities are grouped by
pygame.sprite.Grouproles:updatable: receivesupdate(dt).drawable: receivesdraw(surface).- Specialized groups (
asteroids,shots,explosions) support game rules and collision checks.
- Add a scoring system
- Implement multiple lives and respawning
- Add an explosion effect for the asteroids
- Add acceleration to the player movement
- Make the objects wrap around the screen instead of disappearing
- Add a background image
- Create different weapon types
- Make the asteroids lumpy instead of perfectly round
- Make the ship have a triangular hit box instead of a circular one
- Add a shield power-up
- Add a speed power-up
- Add bombs that can be dropped
- Add collision broad-phase (spatial hash/grid) to avoid nested asteroid-shot checks each frame.
- Invalidate and rebuild sprite transform caches after display mode changes (F11) to avoid render artifacts.
- Replace the session dictionary with a typed dataclass (
GameSession) for safer state access and easier refactors. - Add an
AssetManagerfor centralized loading/pre-scaling and consistent asset error handling. - Split the loop into fixed-timestep update and variable render for stable gameplay under frame drops.
- [x ] Add tests for critical behavior: state transitions, health/invulnerability flow, and wraparound.



