Compare commits
6 commits
ad2037a7a5
...
53938f22b5
| Author | SHA1 | Date | |
|---|---|---|---|
| 53938f22b5 | |||
| db9f7714b1 | |||
| 38c68e6d58 | |||
| 9e6d53867a | |||
| eaff717054 | |||
| 98b74a7ae2 |
64 changed files with 923 additions and 82 deletions
|
|
@ -1 +0,0 @@
|
|||
CLAUDE.md
|
||||
74
TODO.md
74
TODO.md
|
|
@ -1,74 +0,0 @@
|
|||
# TODO
|
||||
|
||||
**1. Core Gameplay Loop & State Management**
|
||||
|
||||
* [x] **GAL-1: Player Lives**
|
||||
* [x] GAL-2: Add a `PlayerLives` resource.
|
||||
* [x] GAL-3: Decrement lives on collision.
|
||||
* [x] GAL-4: Implement player destruction and respawn with temporary invincibility.
|
||||
* [x] **GAL-5: Game Over State**
|
||||
* [x] GAL-6: Use Bevy's `States` (`Playing`, `GameOver`).
|
||||
* [x] GAL-7: Transition to `GameOver` when lives reach zero.
|
||||
* [x] GAL-8: Display a "Game Over" message.
|
||||
* [x] **GAL-9: Scoring**
|
||||
* [x] GAL-10: Add a `Score` resource.
|
||||
* [x] GAL-11: Increment score when an enemy is hit.
|
||||
* [x] **GAL-12: Levels/Stages**
|
||||
* [x] GAL-13: Add `CurrentStage` and `StageConfigurations` resources.
|
||||
* [x] GAL-14: Define criteria for clearing a stage.
|
||||
* [x] GAL-15: Advance to the next stage with increasing difficulty.
|
||||
|
||||
**2. Enemy Behavior - Formations & Attack Patterns**
|
||||
|
||||
* [x] **GAL-16: Enemy Formations**
|
||||
* [x] GAL-17: Define target positions for formations (`FormationLayout`).
|
||||
* [x] GAL-18: Enemies have an `Entering` state to fly to their position.
|
||||
* [x] GAL-19: Enemies have an `InFormation` state.
|
||||
* [x] **GAL-20: Enemy Attack Dives**
|
||||
* [x] GAL-21: Enemies have an `Attacking` state with different `AttackPattern`s (Swoop, Direct, Kamikaze).
|
||||
* [x] GAL-22: Periodically trigger random enemies to start an attack dive.
|
||||
* [x] GAL-23: Enemies fire bullets during their dives.
|
||||
* [x] GAL-24: Enemies are despawned when they fly off-screen after an attack.
|
||||
* [ ] **GAL-25: Enemy Variety**
|
||||
* [x] GAL-26: `EnemyType` enum (`Grunt`, `Boss`).
|
||||
* [ ] GAL-27: Different behaviors, points, and colors based on type.
|
||||
* [x] Colors differ (Grunt red, Boss purple) — `enemy.rs:80-83`
|
||||
* [x] Behaviors differ (Boss has `CaptureBeam`, distinct SwoopDive) — `enemy.rs:254-318`
|
||||
* [ ] Points: Boss currently awards same 100 points as Grunt — see `bullet.rs:48-51` (`// Same points as Grunt for now`). Boss should award more.
|
||||
|
||||
**3. Advanced Galaga Mechanics**
|
||||
|
||||
* [ ] **GAL-28: Boss Galaga & Capture Beam**
|
||||
* [x] GAL-29: Create a "Boss" enemy type.
|
||||
* [x] GAL-30: Implement the tractor beam attack logic (`boss_capture_attack` system).
|
||||
* [x] GAL-31: Player has a `Captured` component when hit by the beam.
|
||||
* [x] GAL-32: Boss has a `ReturningWithCaptive` state to go back to the formation.
|
||||
* [x] GAL-33: Improve the tractor beam visual effect (currently a simple rectangle).
|
||||
* Completed on branch gal-33-improve-tractor-beam-visual, commit 52b0919 — 2-layer glow beam with pulse animation, 8 unit tests
|
||||
* [ ] **GAL-34: Dual Fighter (Rescuing Captured Ship)**
|
||||
* [ ] GAL-35: Allow the player to shoot a Boss that is holding a captured ship.
|
||||
* [ ] GAL-36: Implement the logic to free the captured ship upon shooting the Boss.
|
||||
* [ ] GAL-37: Implement the dual fighter mode (controlling two ships, firing two bullets).
|
||||
* [ ] **GAL-38: Challenging Stages**
|
||||
* [ ] GAL-39: Implement a special stage type (e.g., every 3-4 levels).
|
||||
* [ ] GAL-40: Design and implement intricate flight patterns for enemies that do not shoot.
|
||||
* [ ] GAL-41: Award bonus points for destroying all enemies in the stage.
|
||||
|
||||
**4. Polish and User Interface**
|
||||
|
||||
* [ ] **GAL-42: Visuals**
|
||||
* [ ] GAL-43: Replace placeholder geometric shapes with actual sprites.
|
||||
* [x] GAL-44: Add explosion animations/effects.
|
||||
* **Branch:** `gal-44-add-explosion-effects`
|
||||
* **Comment:** 2026-05-06 — Implementation complete with commit `2ff561e`
|
||||
* [x] GAL-45: Implement a scrolling starfield background.
|
||||
* [ ] **GAL-46: Audio**
|
||||
* [ ] GAL-47: Integrate `bevy_audio`.
|
||||
* [ ] GAL-48: Add sound effects (shooting, explosions, player death, tractor beam, etc.).
|
||||
* [ ] GAL-49: Add background music.
|
||||
* [ ] **GAL-50: UI**
|
||||
* [x] GAL-51: Display Score, Lives, and Stage in the window title.
|
||||
* [ ] GAL-52: Display Score, Lives, and Stage on the screen using `bevy_ui`.
|
||||
* [ ] GAL-53: Implement a High Score system (saving/loading).
|
||||
* [x] GAL-54: Create a Start Menu state with a "Start Game" button.
|
||||
* [ ] GAL-55: Add a "Press R to Restart" message to the `GameOver` screen and implement restart logic.
|
||||
17
TODO/GAL-1.md
Normal file
17
TODO/GAL-1.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
id: GAL-1
|
||||
title: Player Lives
|
||||
status: Done
|
||||
parent: null
|
||||
labels: [gameplay, core-loop]
|
||||
---
|
||||
|
||||
# GAL-1: Player Lives
|
||||
|
||||
Player lives system: lives counter, decrement on hit, destruction and respawn flow.
|
||||
|
||||
## Sub-issues
|
||||
|
||||
- [x] [GAL-2](GAL-2.md) — Add a `PlayerLives` resource.
|
||||
- [x] [GAL-3](GAL-3.md) — Decrement lives on collision.
|
||||
- [x] [GAL-4](GAL-4.md) — Implement player destruction and respawn with temporary invincibility.
|
||||
11
TODO/GAL-10.md
Normal file
11
TODO/GAL-10.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-10
|
||||
title: Add a Score resource
|
||||
status: Done
|
||||
parent: GAL-9
|
||||
labels: [gameplay, core-loop]
|
||||
---
|
||||
|
||||
# GAL-10: Add a `Score` resource
|
||||
|
||||
Add a `Score` resource.
|
||||
11
TODO/GAL-11.md
Normal file
11
TODO/GAL-11.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-11
|
||||
title: Increment score when an enemy is hit
|
||||
status: Done
|
||||
parent: GAL-9
|
||||
labels: [gameplay, core-loop]
|
||||
---
|
||||
|
||||
# GAL-11: Increment score when an enemy is hit
|
||||
|
||||
Increment score when an enemy is hit.
|
||||
17
TODO/GAL-12.md
Normal file
17
TODO/GAL-12.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
id: GAL-12
|
||||
title: Levels/Stages
|
||||
status: Done
|
||||
parent: null
|
||||
labels: [gameplay, core-loop]
|
||||
---
|
||||
|
||||
# GAL-12: Levels/Stages
|
||||
|
||||
Stage progression with increasing difficulty driven by configuration resources.
|
||||
|
||||
## Sub-issues
|
||||
|
||||
- [x] [GAL-13](GAL-13.md) — Add `CurrentStage` and `StageConfigurations` resources.
|
||||
- [x] [GAL-14](GAL-14.md) — Define criteria for clearing a stage.
|
||||
- [x] [GAL-15](GAL-15.md) — Advance to the next stage with increasing difficulty.
|
||||
11
TODO/GAL-13.md
Normal file
11
TODO/GAL-13.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-13
|
||||
title: Add CurrentStage and StageConfigurations resources
|
||||
status: Done
|
||||
parent: GAL-12
|
||||
labels: [gameplay, core-loop]
|
||||
---
|
||||
|
||||
# GAL-13: Add `CurrentStage` and `StageConfigurations` resources
|
||||
|
||||
Add `CurrentStage` and `StageConfigurations` resources.
|
||||
11
TODO/GAL-14.md
Normal file
11
TODO/GAL-14.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-14
|
||||
title: Define criteria for clearing a stage
|
||||
status: Done
|
||||
parent: GAL-12
|
||||
labels: [gameplay, core-loop]
|
||||
---
|
||||
|
||||
# GAL-14: Define criteria for clearing a stage
|
||||
|
||||
Define criteria for clearing a stage.
|
||||
11
TODO/GAL-15.md
Normal file
11
TODO/GAL-15.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-15
|
||||
title: Advance to the next stage with increasing difficulty
|
||||
status: Done
|
||||
parent: GAL-12
|
||||
labels: [gameplay, core-loop]
|
||||
---
|
||||
|
||||
# GAL-15: Advance to the next stage with increasing difficulty
|
||||
|
||||
Advance to the next stage with increasing difficulty.
|
||||
17
TODO/GAL-16.md
Normal file
17
TODO/GAL-16.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
id: GAL-16
|
||||
title: Enemy Formations
|
||||
status: Done
|
||||
parent: null
|
||||
labels: [enemy, gameplay]
|
||||
---
|
||||
|
||||
# GAL-16: Enemy Formations
|
||||
|
||||
Enemies fly into target positions and hold formation.
|
||||
|
||||
## Sub-issues
|
||||
|
||||
- [x] [GAL-17](GAL-17.md) — Define target positions for formations (`FormationLayout`).
|
||||
- [x] [GAL-18](GAL-18.md) — Enemies have an `Entering` state to fly to their position.
|
||||
- [x] [GAL-19](GAL-19.md) — Enemies have an `InFormation` state.
|
||||
11
TODO/GAL-17.md
Normal file
11
TODO/GAL-17.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-17
|
||||
title: Define target positions for formations (FormationLayout)
|
||||
status: Done
|
||||
parent: GAL-16
|
||||
labels: [enemy, gameplay]
|
||||
---
|
||||
|
||||
# GAL-17: Define target positions for formations (`FormationLayout`)
|
||||
|
||||
Define target positions for formations (`FormationLayout`).
|
||||
11
TODO/GAL-18.md
Normal file
11
TODO/GAL-18.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-18
|
||||
title: Enemies have an Entering state to fly to their position
|
||||
status: Done
|
||||
parent: GAL-16
|
||||
labels: [enemy, gameplay]
|
||||
---
|
||||
|
||||
# GAL-18: Enemies have an `Entering` state to fly to their position
|
||||
|
||||
Enemies have an `Entering` state to fly to their position.
|
||||
11
TODO/GAL-19.md
Normal file
11
TODO/GAL-19.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-19
|
||||
title: Enemies have an InFormation state
|
||||
status: Done
|
||||
parent: GAL-16
|
||||
labels: [enemy, gameplay]
|
||||
---
|
||||
|
||||
# GAL-19: Enemies have an `InFormation` state
|
||||
|
||||
Enemies have an `InFormation` state.
|
||||
11
TODO/GAL-2.md
Normal file
11
TODO/GAL-2.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-2
|
||||
title: Add a PlayerLives resource
|
||||
status: Done
|
||||
parent: GAL-1
|
||||
labels: [gameplay, core-loop]
|
||||
---
|
||||
|
||||
# GAL-2: Add a `PlayerLives` resource
|
||||
|
||||
Add a `PlayerLives` resource.
|
||||
18
TODO/GAL-20.md
Normal file
18
TODO/GAL-20.md
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
id: GAL-20
|
||||
title: Enemy Attack Dives
|
||||
status: Done
|
||||
parent: null
|
||||
labels: [enemy, gameplay]
|
||||
---
|
||||
|
||||
# GAL-20: Enemy Attack Dives
|
||||
|
||||
Enemies leave formation to dive at the player along varied attack patterns.
|
||||
|
||||
## Sub-issues
|
||||
|
||||
- [x] [GAL-21](GAL-21.md) — Enemies have an `Attacking` state with different `AttackPattern`s (Swoop, Direct, Kamikaze).
|
||||
- [x] [GAL-22](GAL-22.md) — Periodically trigger random enemies to start an attack dive.
|
||||
- [x] [GAL-23](GAL-23.md) — Enemies fire bullets during their dives.
|
||||
- [x] [GAL-24](GAL-24.md) — Enemies are despawned when they fly off-screen after an attack.
|
||||
11
TODO/GAL-21.md
Normal file
11
TODO/GAL-21.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-21
|
||||
title: Attacking state with different AttackPatterns
|
||||
status: Done
|
||||
parent: GAL-20
|
||||
labels: [enemy, gameplay]
|
||||
---
|
||||
|
||||
# GAL-21: Enemies have an `Attacking` state with different `AttackPattern`s
|
||||
|
||||
Enemies have an `Attacking` state with different `AttackPattern`s (Swoop, Direct, Kamikaze).
|
||||
11
TODO/GAL-22.md
Normal file
11
TODO/GAL-22.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-22
|
||||
title: Periodically trigger random enemies to start an attack dive
|
||||
status: Done
|
||||
parent: GAL-20
|
||||
labels: [enemy, gameplay]
|
||||
---
|
||||
|
||||
# GAL-22: Periodically trigger random enemies to start an attack dive
|
||||
|
||||
Periodically trigger random enemies to start an attack dive.
|
||||
11
TODO/GAL-23.md
Normal file
11
TODO/GAL-23.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-23
|
||||
title: Enemies fire bullets during their dives
|
||||
status: Done
|
||||
parent: GAL-20
|
||||
labels: [enemy, gameplay]
|
||||
---
|
||||
|
||||
# GAL-23: Enemies fire bullets during their dives
|
||||
|
||||
Enemies fire bullets during their dives.
|
||||
11
TODO/GAL-24.md
Normal file
11
TODO/GAL-24.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-24
|
||||
title: Despawn enemies when they fly off-screen after an attack
|
||||
status: Done
|
||||
parent: GAL-20
|
||||
labels: [enemy, gameplay]
|
||||
---
|
||||
|
||||
# GAL-24: Enemies are despawned when they fly off-screen after an attack
|
||||
|
||||
Enemies are despawned when they fly off-screen after an attack.
|
||||
16
TODO/GAL-25.md
Normal file
16
TODO/GAL-25.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
id: GAL-25
|
||||
title: Enemy Variety
|
||||
status: In Progress
|
||||
parent: null
|
||||
labels: [enemy, gameplay]
|
||||
---
|
||||
|
||||
# GAL-25: Enemy Variety
|
||||
|
||||
Different enemy types with distinct visuals, behaviors, and point values.
|
||||
|
||||
## Sub-issues
|
||||
|
||||
- [x] [GAL-26](GAL-26.md) — `EnemyType` enum (`Grunt`, `Boss`).
|
||||
- [x] [GAL-27](GAL-27.md) — Different behaviors, points, and colors based on type.
|
||||
11
TODO/GAL-26.md
Normal file
11
TODO/GAL-26.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-26
|
||||
title: EnemyType enum (Grunt, Boss)
|
||||
status: Done
|
||||
parent: GAL-25
|
||||
labels: [enemy, gameplay]
|
||||
---
|
||||
|
||||
# GAL-26: `EnemyType` enum (`Grunt`, `Boss`)
|
||||
|
||||
`EnemyType` enum (`Grunt`, `Boss`).
|
||||
21
TODO/GAL-27.md
Normal file
21
TODO/GAL-27.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
id: GAL-27
|
||||
title: Different behaviors, points, and colors based on type
|
||||
status: Done
|
||||
parent: GAL-25
|
||||
labels: [enemy, gameplay]
|
||||
---
|
||||
|
||||
# GAL-27: Different behaviors, points, and colors based on type
|
||||
|
||||
Bosses are visually, behaviorally, and economically distinct from Grunts.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [x] Colors differ (Grunt red, Boss purple) — `enemy.rs:80-83`
|
||||
- [x] Behaviors differ (Boss has `CaptureBeam`, distinct SwoopDive) — `enemy.rs:254-318`
|
||||
- [x] Points: Boss awards 300 points (3x Grunt) — `bullet.rs:13-14`
|
||||
|
||||
## Comments
|
||||
|
||||
- Completed on branch GAL-27, commit 98b74a7.
|
||||
19
TODO/GAL-28.md
Normal file
19
TODO/GAL-28.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
id: GAL-28
|
||||
title: Boss Galaga & Capture Beam
|
||||
status: In Progress
|
||||
parent: null
|
||||
labels: [enemy, advanced-mechanics]
|
||||
---
|
||||
|
||||
# GAL-28: Boss Galaga & Capture Beam
|
||||
|
||||
Boss enemy with tractor beam capture mechanic and return-to-formation behavior.
|
||||
|
||||
## Sub-issues
|
||||
|
||||
- [x] [GAL-29](GAL-29.md) — Create a "Boss" enemy type.
|
||||
- [x] [GAL-30](GAL-30.md) — Implement the tractor beam attack logic (`boss_capture_attack` system).
|
||||
- [x] [GAL-31](GAL-31.md) — Player has a `Captured` component when hit by the beam.
|
||||
- [x] [GAL-32](GAL-32.md) — Boss has a `ReturningWithCaptive` state to go back to the formation.
|
||||
- [x] [GAL-33](GAL-33.md) — Improve the tractor beam visual effect (currently a simple rectangle).
|
||||
11
TODO/GAL-29.md
Normal file
11
TODO/GAL-29.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-29
|
||||
title: Create a Boss enemy type
|
||||
status: Done
|
||||
parent: GAL-28
|
||||
labels: [enemy, advanced-mechanics]
|
||||
---
|
||||
|
||||
# GAL-29: Create a "Boss" enemy type
|
||||
|
||||
Create a "Boss" enemy type.
|
||||
11
TODO/GAL-3.md
Normal file
11
TODO/GAL-3.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-3
|
||||
title: Decrement lives on collision
|
||||
status: Done
|
||||
parent: GAL-1
|
||||
labels: [gameplay, core-loop]
|
||||
---
|
||||
|
||||
# GAL-3: Decrement lives on collision
|
||||
|
||||
Decrement lives on collision.
|
||||
11
TODO/GAL-30.md
Normal file
11
TODO/GAL-30.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-30
|
||||
title: Implement the tractor beam attack logic
|
||||
status: Done
|
||||
parent: GAL-28
|
||||
labels: [enemy, advanced-mechanics]
|
||||
---
|
||||
|
||||
# GAL-30: Implement the tractor beam attack logic (`boss_capture_attack` system)
|
||||
|
||||
Implement the tractor beam attack logic (`boss_capture_attack` system).
|
||||
11
TODO/GAL-31.md
Normal file
11
TODO/GAL-31.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-31
|
||||
title: Player has a Captured component when hit by the beam
|
||||
status: Done
|
||||
parent: GAL-28
|
||||
labels: [enemy, advanced-mechanics]
|
||||
---
|
||||
|
||||
# GAL-31: Player has a `Captured` component when hit by the beam
|
||||
|
||||
Player has a `Captured` component when hit by the beam.
|
||||
11
TODO/GAL-32.md
Normal file
11
TODO/GAL-32.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-32
|
||||
title: Boss has a ReturningWithCaptive state
|
||||
status: Done
|
||||
parent: GAL-28
|
||||
labels: [enemy, advanced-mechanics]
|
||||
---
|
||||
|
||||
# GAL-32: Boss has a `ReturningWithCaptive` state to go back to the formation
|
||||
|
||||
Boss has a `ReturningWithCaptive` state to go back to the formation.
|
||||
15
TODO/GAL-33.md
Normal file
15
TODO/GAL-33.md
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
id: GAL-33
|
||||
title: Improve the tractor beam visual effect
|
||||
status: Done
|
||||
parent: GAL-28
|
||||
labels: [enemy, advanced-mechanics, visuals]
|
||||
---
|
||||
|
||||
# GAL-33: Improve the tractor beam visual effect
|
||||
|
||||
Improve the tractor beam visual effect (currently a simple rectangle).
|
||||
|
||||
## Comments
|
||||
|
||||
- Completed on branch `gal-33-improve-tractor-beam-visual`, commit 52b0919 — 2-layer glow beam with pulse animation, 8 unit tests.
|
||||
17
TODO/GAL-34.md
Normal file
17
TODO/GAL-34.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
id: GAL-34
|
||||
title: Dual Fighter (Rescuing Captured Ship)
|
||||
status: Todo
|
||||
parent: null
|
||||
labels: [gameplay, advanced-mechanics]
|
||||
---
|
||||
|
||||
# GAL-34: Dual Fighter (Rescuing Captured Ship)
|
||||
|
||||
Allow the player to rescue a captured ship and operate in dual-fighter mode.
|
||||
|
||||
## Sub-issues
|
||||
|
||||
- [ ] [GAL-35](GAL-35.md) — Allow the player to shoot a Boss that is holding a captured ship.
|
||||
- [ ] [GAL-36](GAL-36.md) — Implement the logic to free the captured ship upon shooting the Boss.
|
||||
- [ ] [GAL-37](GAL-37.md) — Implement the dual fighter mode (controlling two ships, firing two bullets).
|
||||
11
TODO/GAL-35.md
Normal file
11
TODO/GAL-35.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-35
|
||||
title: Allow the player to shoot a Boss holding a captured ship
|
||||
status: Todo
|
||||
parent: GAL-34
|
||||
labels: [gameplay, advanced-mechanics]
|
||||
---
|
||||
|
||||
# GAL-35: Allow the player to shoot a Boss that is holding a captured ship
|
||||
|
||||
Allow the player to shoot a Boss that is holding a captured ship.
|
||||
11
TODO/GAL-36.md
Normal file
11
TODO/GAL-36.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-36
|
||||
title: Free the captured ship upon shooting the Boss
|
||||
status: Todo
|
||||
parent: GAL-34
|
||||
labels: [gameplay, advanced-mechanics]
|
||||
---
|
||||
|
||||
# GAL-36: Implement the logic to free the captured ship upon shooting the Boss
|
||||
|
||||
Implement the logic to free the captured ship upon shooting the Boss.
|
||||
11
TODO/GAL-37.md
Normal file
11
TODO/GAL-37.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-37
|
||||
title: Implement the dual fighter mode
|
||||
status: Todo
|
||||
parent: GAL-34
|
||||
labels: [gameplay, advanced-mechanics]
|
||||
---
|
||||
|
||||
# GAL-37: Implement the dual fighter mode (controlling two ships, firing two bullets)
|
||||
|
||||
Implement the dual fighter mode (controlling two ships, firing two bullets).
|
||||
17
TODO/GAL-38.md
Normal file
17
TODO/GAL-38.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
id: GAL-38
|
||||
title: Challenging Stages
|
||||
status: In Progress
|
||||
parent: null
|
||||
labels: [gameplay, advanced-mechanics]
|
||||
---
|
||||
|
||||
# GAL-38: Challenging Stages
|
||||
|
||||
Special stages every few levels with intricate non-shooting flight patterns and bonus rewards.
|
||||
|
||||
## Sub-issues
|
||||
|
||||
- [x] [GAL-39](GAL-39.md) — Implement a special stage type (e.g., every 3-4 levels).
|
||||
- [ ] [GAL-40](GAL-40.md) — Design and implement intricate flight patterns for enemies that do not shoot.
|
||||
- [ ] [GAL-41](GAL-41.md) — Award bonus points for destroying all enemies in the stage.
|
||||
16
TODO/GAL-39.md
Normal file
16
TODO/GAL-39.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
id: GAL-39
|
||||
title: Implement a special stage type
|
||||
status: Done
|
||||
parent: GAL-38
|
||||
labels: [gameplay, advanced-mechanics]
|
||||
---
|
||||
|
||||
# GAL-39: Implement a special stage type (e.g., every 3-4 levels)
|
||||
|
||||
Implement a special stage type (e.g., every 3-4 levels).
|
||||
|
||||
## Comments
|
||||
|
||||
- 2026-05-06 — Status set to In Progress.
|
||||
- 2026-05-06 — Branch `GAL-39`, commit 9e6d538 — every 3rd level has no enemy attacks.
|
||||
11
TODO/GAL-4.md
Normal file
11
TODO/GAL-4.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-4
|
||||
title: Player destruction and respawn with temporary invincibility
|
||||
status: Done
|
||||
parent: GAL-1
|
||||
labels: [gameplay, core-loop]
|
||||
---
|
||||
|
||||
# GAL-4: Implement player destruction and respawn with temporary invincibility
|
||||
|
||||
Implement player destruction and respawn with temporary invincibility.
|
||||
11
TODO/GAL-40.md
Normal file
11
TODO/GAL-40.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-40
|
||||
title: Design intricate flight patterns for non-shooting enemies
|
||||
status: Todo
|
||||
parent: GAL-38
|
||||
labels: [gameplay, advanced-mechanics]
|
||||
---
|
||||
|
||||
# GAL-40: Design and implement intricate flight patterns for enemies that do not shoot
|
||||
|
||||
Design and implement intricate flight patterns for enemies that do not shoot.
|
||||
11
TODO/GAL-41.md
Normal file
11
TODO/GAL-41.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-41
|
||||
title: Award bonus points for clearing the special stage
|
||||
status: Todo
|
||||
parent: GAL-38
|
||||
labels: [gameplay, advanced-mechanics]
|
||||
---
|
||||
|
||||
# GAL-41: Award bonus points for destroying all enemies in the stage
|
||||
|
||||
Award bonus points for destroying all enemies in the stage.
|
||||
17
TODO/GAL-42.md
Normal file
17
TODO/GAL-42.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
id: GAL-42
|
||||
title: Visuals
|
||||
status: In Progress
|
||||
parent: null
|
||||
labels: [polish, visuals]
|
||||
---
|
||||
|
||||
# GAL-42: Visuals
|
||||
|
||||
Replace placeholder geometry with sprites, add explosions, and add a starfield background.
|
||||
|
||||
## Sub-issues
|
||||
|
||||
- [ ] [GAL-43](GAL-43.md) — Replace placeholder geometric shapes with actual sprites.
|
||||
- [x] [GAL-44](GAL-44.md) — Add explosion animations/effects.
|
||||
- [x] [GAL-45](GAL-45.md) — Implement a scrolling starfield background.
|
||||
11
TODO/GAL-43.md
Normal file
11
TODO/GAL-43.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-43
|
||||
title: Replace placeholder geometric shapes with actual sprites
|
||||
status: Todo
|
||||
parent: GAL-42
|
||||
labels: [polish, visuals]
|
||||
---
|
||||
|
||||
# GAL-43: Replace placeholder geometric shapes with actual sprites
|
||||
|
||||
Replace placeholder geometric shapes with actual sprites.
|
||||
16
TODO/GAL-44.md
Normal file
16
TODO/GAL-44.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
id: GAL-44
|
||||
title: Add explosion animations/effects
|
||||
status: Done
|
||||
parent: GAL-42
|
||||
labels: [polish, visuals]
|
||||
---
|
||||
|
||||
# GAL-44: Add explosion animations/effects
|
||||
|
||||
Add explosion animations/effects.
|
||||
|
||||
## Comments
|
||||
|
||||
- Branch: `gal-44-add-explosion-effects`.
|
||||
- 2026-05-06 — Implementation complete with commit `2ff561e`.
|
||||
11
TODO/GAL-45.md
Normal file
11
TODO/GAL-45.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-45
|
||||
title: Implement a scrolling starfield background
|
||||
status: Done
|
||||
parent: GAL-42
|
||||
labels: [polish, visuals]
|
||||
---
|
||||
|
||||
# GAL-45: Implement a scrolling starfield background
|
||||
|
||||
Implement a scrolling starfield background.
|
||||
17
TODO/GAL-46.md
Normal file
17
TODO/GAL-46.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
id: GAL-46
|
||||
title: Audio
|
||||
status: Todo
|
||||
parent: null
|
||||
labels: [polish, audio]
|
||||
---
|
||||
|
||||
# GAL-46: Audio
|
||||
|
||||
Wire up audio plugin, sound effects, and background music.
|
||||
|
||||
## Sub-issues
|
||||
|
||||
- [ ] [GAL-47](GAL-47.md) — Integrate `bevy_audio`.
|
||||
- [ ] [GAL-48](GAL-48.md) — Add sound effects (shooting, explosions, player death, tractor beam, etc.).
|
||||
- [ ] [GAL-49](GAL-49.md) — Add background music.
|
||||
11
TODO/GAL-47.md
Normal file
11
TODO/GAL-47.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-47
|
||||
title: Integrate bevy_audio
|
||||
status: Todo
|
||||
parent: GAL-46
|
||||
labels: [polish, audio]
|
||||
---
|
||||
|
||||
# GAL-47: Integrate `bevy_audio`
|
||||
|
||||
Integrate `bevy_audio`.
|
||||
11
TODO/GAL-48.md
Normal file
11
TODO/GAL-48.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-48
|
||||
title: Add sound effects
|
||||
status: Todo
|
||||
parent: GAL-46
|
||||
labels: [polish, audio]
|
||||
---
|
||||
|
||||
# GAL-48: Add sound effects (shooting, explosions, player death, tractor beam, etc.)
|
||||
|
||||
Add sound effects (shooting, explosions, player death, tractor beam, etc.).
|
||||
11
TODO/GAL-49.md
Normal file
11
TODO/GAL-49.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-49
|
||||
title: Add background music
|
||||
status: Todo
|
||||
parent: GAL-46
|
||||
labels: [polish, audio]
|
||||
---
|
||||
|
||||
# GAL-49: Add background music
|
||||
|
||||
Add background music.
|
||||
17
TODO/GAL-5.md
Normal file
17
TODO/GAL-5.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
id: GAL-5
|
||||
title: Game Over State
|
||||
status: Done
|
||||
parent: null
|
||||
labels: [gameplay, core-loop]
|
||||
---
|
||||
|
||||
# GAL-5: Game Over State
|
||||
|
||||
State machine covering `Playing` and `GameOver`, with a transition trigger and on-screen message.
|
||||
|
||||
## Sub-issues
|
||||
|
||||
- [x] [GAL-6](GAL-6.md) — Use Bevy's `States` (`Playing`, `GameOver`).
|
||||
- [x] [GAL-7](GAL-7.md) — Transition to `GameOver` when lives reach zero.
|
||||
- [x] [GAL-8](GAL-8.md) — Display a "Game Over" message.
|
||||
19
TODO/GAL-50.md
Normal file
19
TODO/GAL-50.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
id: GAL-50
|
||||
title: UI
|
||||
status: In Progress
|
||||
parent: null
|
||||
labels: [polish, ui]
|
||||
---
|
||||
|
||||
# GAL-50: UI
|
||||
|
||||
Score, lives, stage, high-score, start menu, and restart UI.
|
||||
|
||||
## Sub-issues
|
||||
|
||||
- [x] [GAL-51](GAL-51.md) — Display Score, Lives, and Stage in the window title.
|
||||
- [ ] [GAL-52](GAL-52.md) — Display Score, Lives, and Stage on the screen using `bevy_ui`.
|
||||
- [ ] [GAL-53](GAL-53.md) — Implement a High Score system (saving/loading).
|
||||
- [x] [GAL-54](GAL-54.md) — Create a Start Menu state with a "Start Game" button.
|
||||
- [ ] [GAL-55](GAL-55.md) — Add a "Press R to Restart" message to the `GameOver` screen and implement restart logic.
|
||||
11
TODO/GAL-51.md
Normal file
11
TODO/GAL-51.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-51
|
||||
title: Display Score, Lives, and Stage in the window title
|
||||
status: Done
|
||||
parent: GAL-50
|
||||
labels: [polish, ui]
|
||||
---
|
||||
|
||||
# GAL-51: Display Score, Lives, and Stage in the window title
|
||||
|
||||
Display Score, Lives, and Stage in the window title.
|
||||
11
TODO/GAL-52.md
Normal file
11
TODO/GAL-52.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-52
|
||||
title: Display Score, Lives, and Stage on screen using bevy_ui
|
||||
status: Todo
|
||||
parent: GAL-50
|
||||
labels: [polish, ui]
|
||||
---
|
||||
|
||||
# GAL-52: Display Score, Lives, and Stage on the screen using `bevy_ui`
|
||||
|
||||
Display Score, Lives, and Stage on the screen using `bevy_ui`.
|
||||
11
TODO/GAL-53.md
Normal file
11
TODO/GAL-53.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-53
|
||||
title: Implement a High Score system (saving/loading)
|
||||
status: Todo
|
||||
parent: GAL-50
|
||||
labels: [polish, ui]
|
||||
---
|
||||
|
||||
# GAL-53: Implement a High Score system (saving/loading)
|
||||
|
||||
Implement a High Score system (saving/loading).
|
||||
11
TODO/GAL-54.md
Normal file
11
TODO/GAL-54.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-54
|
||||
title: Create a Start Menu state with a Start Game button
|
||||
status: Done
|
||||
parent: GAL-50
|
||||
labels: [polish, ui]
|
||||
---
|
||||
|
||||
# GAL-54: Create a Start Menu state with a "Start Game" button
|
||||
|
||||
Create a Start Menu state with a "Start Game" button.
|
||||
11
TODO/GAL-55.md
Normal file
11
TODO/GAL-55.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-55
|
||||
title: Add Press R to Restart message and restart logic
|
||||
status: Todo
|
||||
parent: GAL-50
|
||||
labels: [polish, ui]
|
||||
---
|
||||
|
||||
# GAL-55: Add a "Press R to Restart" message to the `GameOver` screen and implement restart logic
|
||||
|
||||
Add a "Press R to Restart" message to the `GameOver` screen and implement restart logic.
|
||||
11
TODO/GAL-6.md
Normal file
11
TODO/GAL-6.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-6
|
||||
title: Use Bevy's States (Playing, GameOver)
|
||||
status: Done
|
||||
parent: GAL-5
|
||||
labels: [gameplay, core-loop]
|
||||
---
|
||||
|
||||
# GAL-6: Use Bevy's `States` (`Playing`, `GameOver`)
|
||||
|
||||
Use Bevy's `States` (`Playing`, `GameOver`).
|
||||
11
TODO/GAL-7.md
Normal file
11
TODO/GAL-7.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-7
|
||||
title: Transition to GameOver when lives reach zero
|
||||
status: Done
|
||||
parent: GAL-5
|
||||
labels: [gameplay, core-loop]
|
||||
---
|
||||
|
||||
# GAL-7: Transition to `GameOver` when lives reach zero
|
||||
|
||||
Transition to `GameOver` when lives reach zero.
|
||||
11
TODO/GAL-8.md
Normal file
11
TODO/GAL-8.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
id: GAL-8
|
||||
title: Display a Game Over message
|
||||
status: Done
|
||||
parent: GAL-5
|
||||
labels: [gameplay, core-loop]
|
||||
---
|
||||
|
||||
# GAL-8: Display a "Game Over" message
|
||||
|
||||
Display a "Game Over" message.
|
||||
16
TODO/GAL-9.md
Normal file
16
TODO/GAL-9.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
id: GAL-9
|
||||
title: Scoring
|
||||
status: Done
|
||||
parent: null
|
||||
labels: [gameplay, core-loop]
|
||||
---
|
||||
|
||||
# GAL-9: Scoring
|
||||
|
||||
Add a score resource and increment when an enemy is destroyed.
|
||||
|
||||
## Sub-issues
|
||||
|
||||
- [x] [GAL-10](GAL-10.md) — Add a `Score` resource.
|
||||
- [x] [GAL-11](GAL-11.md) — Increment score when an enemy is hit.
|
||||
30
TODO/README.md
Normal file
30
TODO/README.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Project Issues
|
||||
|
||||
Linear-style issue tracker for bglga. Each issue lives in its own `GAL-N.md` file in this folder.
|
||||
|
||||
Statuses: `Todo`, `In Progress`, `Done`.
|
||||
|
||||
## 1. Core Gameplay Loop & State Management
|
||||
|
||||
- [x] [GAL-1](GAL-1.md) — Player Lives
|
||||
- [x] [GAL-5](GAL-5.md) — Game Over State
|
||||
- [x] [GAL-9](GAL-9.md) — Scoring
|
||||
- [x] [GAL-12](GAL-12.md) — Levels/Stages
|
||||
|
||||
## 2. Enemy Behavior — Formations & Attack Patterns
|
||||
|
||||
- [x] [GAL-16](GAL-16.md) — Enemy Formations
|
||||
- [x] [GAL-20](GAL-20.md) — Enemy Attack Dives
|
||||
- [ ] [GAL-25](GAL-25.md) — Enemy Variety
|
||||
|
||||
## 3. Advanced Galaga Mechanics
|
||||
|
||||
- [ ] [GAL-28](GAL-28.md) — Boss Galaga & Capture Beam
|
||||
- [ ] [GAL-34](GAL-34.md) — Dual Fighter (Rescuing Captured Ship)
|
||||
- [ ] [GAL-38](GAL-38.md) — Challenging Stages
|
||||
|
||||
## 4. Polish and User Interface
|
||||
|
||||
- [ ] [GAL-42](GAL-42.md) — Visuals
|
||||
- [ ] [GAL-46](GAL-46.md) — Audio
|
||||
- [ ] [GAL-50](GAL-50.md) — UI
|
||||
|
|
@ -11,7 +11,7 @@ use crate::resources::{PlayerLives, PlayerRespawnTimer, Score};
|
|||
use crate::systems::spawn_explosion;
|
||||
|
||||
const GRUNT_POINTS: u32 = 100;
|
||||
const BOSS_POINTS: u32 = 100; // TODO(GAL-27): differentiate Boss from Grunt scoring
|
||||
const BOSS_POINTS: u32 = 300;
|
||||
|
||||
pub fn move_bullets(
|
||||
mut query: Query<(Entity, &mut Transform), With<Bullet>>,
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@ pub const BEAM_CORE_COLOR: Color = Color::srgba(0.7, 0.2, 1.0, 0.7);
|
|||
pub const BEAM_PULSE_FREQ: f32 = 3.0;
|
||||
pub const BEAM_PULSE_AMPLITUDE: f32 = 0.15;
|
||||
|
||||
// Special stages
|
||||
pub const SPECIAL_STAGE_INTERVAL: u32 = 3;
|
||||
|
||||
// Starfield
|
||||
pub const STAR_COUNT: usize = 150;
|
||||
pub const STAR_MIN_SIZE: f32 = 1.0;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use crate::constants::{
|
|||
};
|
||||
use crate::resources::{
|
||||
AttackDiveTimer, CurrentStage, EnemySpawnTimer, FormationState, StageConfigurations,
|
||||
is_special_stage,
|
||||
};
|
||||
|
||||
const BOSS_BASE_CHANCE: f32 = 0.30;
|
||||
|
|
@ -341,7 +342,11 @@ pub fn enemy_shoot(
|
|||
mut commands: Commands,
|
||||
time: Res<Time>,
|
||||
mut enemy_query: Query<(&Transform, &mut Enemy, &EnemyState), Without<FormationTarget>>,
|
||||
stage: Res<CurrentStage>,
|
||||
) {
|
||||
if is_special_stage(stage.number) {
|
||||
return;
|
||||
}
|
||||
for (transform, mut enemy, state) in enemy_query.iter_mut() {
|
||||
if !matches!(state, EnemyState::Attacking(_)) {
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -3,9 +3,14 @@ use bevy::prelude::*;
|
|||
use crate::components::AttackPattern;
|
||||
use crate::constants::{
|
||||
ENEMY_SHOOT_INTERVAL, FORMATION_BASE_Y, FORMATION_COLS, FORMATION_ENEMY_COUNT,
|
||||
FORMATION_X_SPACING, FORMATION_Y_SPACING, WINDOW_WIDTH,
|
||||
FORMATION_X_SPACING, FORMATION_Y_SPACING, SPECIAL_STAGE_INTERVAL, WINDOW_WIDTH,
|
||||
};
|
||||
|
||||
/// Returns `true` when `stage_number` is a special stage (every 3rd stage).
|
||||
pub fn is_special_stage(stage_number: u32) -> bool {
|
||||
stage_number > 0 && stage_number.is_multiple_of(SPECIAL_STAGE_INTERVAL)
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct EnemySpawnTimer {
|
||||
pub timer: Timer,
|
||||
|
|
@ -58,13 +63,21 @@ pub struct StageConfig {
|
|||
#[derive(Resource, Debug, Clone)]
|
||||
pub struct StageConfigurations {
|
||||
pub stages: Vec<StageConfig>,
|
||||
pub special_stage: StageConfig,
|
||||
}
|
||||
|
||||
impl StageConfigurations {
|
||||
/// Cycles through configured stages once `stage_number` exceeds the count.
|
||||
/// Returns the config for the given stage, using the special stage config
|
||||
/// when `stage_number` is a multiple of `SPECIAL_STAGE_INTERVAL`.
|
||||
pub fn for_stage(&self, stage_number: u32) -> &StageConfig {
|
||||
let idx = (stage_number.saturating_sub(1) as usize) % self.stages.len();
|
||||
&self.stages[idx]
|
||||
if is_special_stage(stage_number) {
|
||||
return &self.special_stage;
|
||||
}
|
||||
// Count how many special stages come before this one
|
||||
let special_before = stage_number / SPECIAL_STAGE_INTERVAL;
|
||||
let normal_idx =
|
||||
(stage_number.saturating_sub(1) - special_before) as usize % self.stages.len();
|
||||
&self.stages[normal_idx]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -89,8 +102,18 @@ impl Default for StageConfigurations {
|
|||
enemy_shoot_interval: ENEMY_SHOOT_INTERVAL * 0.8,
|
||||
};
|
||||
|
||||
let special_stage = StageConfig {
|
||||
formation_layout: FormationLayout::default(),
|
||||
enemy_count: FORMATION_ENEMY_COUNT,
|
||||
attack_patterns: vec![],
|
||||
attack_dive_interval: f32::MAX,
|
||||
enemy_speed_multiplier: 1.0,
|
||||
enemy_shoot_interval: ENEMY_SHOOT_INTERVAL,
|
||||
};
|
||||
|
||||
Self {
|
||||
stages: vec![stage1, stage2],
|
||||
special_stage,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use std::time::Duration;
|
|||
use crate::components::{Explosion, Invincible, Player};
|
||||
use crate::constants::{EXPLOSION_BASE_SIZE, EXPLOSION_COLOR, EXPLOSION_DURATION, EXPLOSION_MAX_SIZE};
|
||||
use crate::player::spawn_player_ship;
|
||||
use crate::resources::{CurrentStage, PlayerLives, Score};
|
||||
use crate::resources::{CurrentStage, PlayerLives, Score, is_special_stage};
|
||||
use crate::starfield::spawn_starfield;
|
||||
|
||||
pub fn setup(mut commands: Commands) {
|
||||
|
|
@ -38,10 +38,15 @@ pub fn update_window_title(
|
|||
if !(lives.is_changed() || score.is_changed() || stage.is_changed()) {
|
||||
return;
|
||||
}
|
||||
let stage_label = if is_special_stage(stage.number) {
|
||||
format!("{}*", stage.number)
|
||||
} else {
|
||||
stage.number.to_string()
|
||||
};
|
||||
if let Ok(mut window) = windows.single_mut() {
|
||||
window.title = format!(
|
||||
"Galaga :: Stage: {} Lives: {} Score: {}",
|
||||
stage.number, lives.count, score.value
|
||||
stage_label, lives.count, score.value
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
140
tests/special_stage.rs
Normal file
140
tests/special_stage.rs
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
use bglga::constants::SPECIAL_STAGE_INTERVAL;
|
||||
use bglga::resources::is_special_stage;
|
||||
use bglga::resources::StageConfigurations;
|
||||
|
||||
// ── SPECIAL_STAGE_INTERVAL constant ──
|
||||
|
||||
#[test]
|
||||
fn special_stage_interval_is_three() {
|
||||
assert_eq!(SPECIAL_STAGE_INTERVAL, 3);
|
||||
}
|
||||
|
||||
// ── is_special_stage function ──
|
||||
|
||||
#[test]
|
||||
fn stage_zero_is_not_special() {
|
||||
assert!(!is_special_stage(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stage_1_is_not_special() {
|
||||
assert!(!is_special_stage(1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stage_2_is_not_special() {
|
||||
assert!(!is_special_stage(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stage_3_is_special() {
|
||||
assert!(is_special_stage(3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stage_4_is_not_special() {
|
||||
assert!(!is_special_stage(4));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stage_5_is_not_special() {
|
||||
assert!(!is_special_stage(5));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stage_6_is_special() {
|
||||
assert!(is_special_stage(6));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stage_9_is_special() {
|
||||
assert!(is_special_stage(9));
|
||||
}
|
||||
|
||||
// ── for_stage returns special config for special stages ──
|
||||
|
||||
#[test]
|
||||
fn for_stage_returns_special_config_at_stage_3() {
|
||||
let configs = StageConfigurations::default();
|
||||
let config = configs.for_stage(3);
|
||||
// Special stages have no dive attacks
|
||||
assert!(
|
||||
config.attack_patterns.is_empty(),
|
||||
"Stage 3 (special) should have empty attack_patterns"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_stage_returns_special_config_at_stage_6() {
|
||||
let configs = StageConfigurations::default();
|
||||
let config = configs.for_stage(6);
|
||||
assert!(
|
||||
config.attack_patterns.is_empty(),
|
||||
"Stage 6 (special) should have empty attack_patterns"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_stage_returns_normal_config_at_stage_1() {
|
||||
let configs = StageConfigurations::default();
|
||||
let config = configs.for_stage(1);
|
||||
assert!(
|
||||
!config.attack_patterns.is_empty(),
|
||||
"Stage 1 (normal) should have attack patterns"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_stage_returns_normal_config_at_stage_2() {
|
||||
let configs = StageConfigurations::default();
|
||||
let config = configs.for_stage(2);
|
||||
assert!(
|
||||
!config.attack_patterns.is_empty(),
|
||||
"Stage 2 (normal) should have attack patterns"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_stage_returns_normal_config_at_stage_4() {
|
||||
let configs = StageConfigurations::default();
|
||||
let config = configs.for_stage(4);
|
||||
assert!(
|
||||
!config.attack_patterns.is_empty(),
|
||||
"Stage 4 (normal) should have attack patterns"
|
||||
);
|
||||
}
|
||||
|
||||
// ── Special stage config properties ──
|
||||
|
||||
#[test]
|
||||
fn special_stage_has_full_formation() {
|
||||
let configs = StageConfigurations::default();
|
||||
let config = configs.for_stage(3);
|
||||
assert_eq!(config.enemy_count, 32, "Special stage should have 32 enemies");
|
||||
assert_eq!(
|
||||
config.formation_layout.positions.len(),
|
||||
32,
|
||||
"Special stage formation should have 32 positions"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn special_stage_has_max_dive_interval() {
|
||||
let configs = StageConfigurations::default();
|
||||
let config = configs.for_stage(3);
|
||||
assert_eq!(
|
||||
config.attack_dive_interval,
|
||||
f32::MAX,
|
||||
"Special stage should have max dive interval"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn special_stage_has_base_speed() {
|
||||
let configs = StageConfigurations::default();
|
||||
let config = configs.for_stage(3);
|
||||
assert_eq!(
|
||||
config.enemy_speed_multiplier, 1.0,
|
||||
"Special stage should have 1.0x speed multiplier"
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue