Gameplay
Core mechanics, enemies, collectibles, and progression.
Core Gameplay Loop
Galaxy Eggbert is a 3D platformer. The player controls Blupi — a small character — through voxel worlds, collecting treasures, picking up keys and power-ups, avoiding enemies and hazard tiles, and reaching the level exit.
- Select a gamer slot (1, 2, or 3) on the gamer-select screen.
- Navigate Blupi through the 3D world.
- Collect all treasures for a bonus life.
- Collect any keys required to unlock doors (tracked in HUD).
- Avoid patrol enemies, hazard tiles (Lava, Spike, Crusher), and fall deaths.
- Reach the level exit (type 7 object) to advance to the next world.
- After world 5, progression wraps back to world 1.
- Losing all lives returns to the gamer-select screen; saves reset to 3 lives, world 1.
Player Character (Blupi)
Implemented in src/GalaxyEggbert/Game/Blupi.hpp and Blupi.cpp.
Physics Constants
| Constant | Value | Notes |
|---|---|---|
kGravity | −22.0 units/s² | Applied every frame to Y velocity |
kJumpSpeed | 10.0 units/s | Initial Y velocity on jump |
kMoveSpeed | 5.5 units/s | Horizontal movement speed |
kTurnSpeed | 180 °/s | Rotation speed (LEFT/RIGHT keys) |
kHalfW | 0.35 units | Half-width for AABB collision |
kHalfH | 0.70 units | Half-height for AABB collision |
| Terminal velocity | −30 units/s | Y velocity clamped |
| Fall death threshold | Y < −10 units | Triggers death + respawn |
Animation States
State (BlupiAction) | Triggered when |
|---|---|
Stop | On ground, no horizontal input, not turning |
March | On ground, horizontal speed > 0.1 |
Turn | On ground, not moving, pressing LEFT or RIGHT |
Jump | In air, Y velocity > 0 (rising) |
Air | In air, Y velocity ≤ 0 (falling) |
Animation frames are looked up from Tables::GetBlupiIcon(action, scaledPhase),
which maps to the blupi.png sprite sheet (600×2040 px, 60×60 tiles, 10 columns × 34 rows).
The animation ticks at 1/3 game-tick rate to match the original 20 fps timing.
Respawn Invincibility
After any respawn (fall death, tile hazard, or enemy hit), Blupi has 2 seconds of invincibility. During this time the sprite flashes (visible/invisible every 0.1 s). Tile hazards and enemy hits are skipped while the timer is active.
Lives and Death
- Start with 3 lives. Maximum is 9 lives.
- Lose a life on: fall death, hazard tile contact, enemy contact (without shield).
- Earn an extra life when all treasures in a level are collected (once per level).
- At 0 lives: game over → gamer-select screen; save resets to 3 lives, world 1.
Collectibles
| Object Type | Name | Effect |
|---|---|---|
ObjectType5 | Treasure | Counts toward treasure total; bonus life when all collected |
ObjectType6 | Extra-Life Egg | Counts as collected item |
ObjectType30 | Drink | Counts as collected item |
ObjectType49 | Red Key | Key collected (tracked in HUD) |
ObjectType50 | Green Key | Key collected |
ObjectType51 | Blue Key | Key collected |
ObjectType25 | Shield Orb | 5 seconds of invincibility |
ObjectType13 | Helicopter | Grants shield (vehicle boarding placeholder) |
Hazards
Tile Hazards
| Block Type | Icon ID | Effect |
|---|---|---|
Lava | 68 | Kills Blupi on contact (removes 1 life) |
Spike | 373 | Kills Blupi on contact |
Crusher | 317 | Kills Blupi on contact |
Tile hazard detection is performed in GalaxyEggbertGame::UpdatePlay() each frame
when Blupi is on the ground and neither the shield nor respawn invincibility is active.
Fall Death
Falling below Y = −10 world units triggers a death. The spawn point is fixed to the position
encoded in the level file's blupiPos= header field.
Enemies
| Object Type | Name | Behavior |
|---|---|---|
ObjectType2 | Patrol Enemy A | Patrols linearly between two points; kills on contact |
ObjectType3 | Patrol Enemy B | Same patrol, different sprite |
ObjectType4 | Bulldozer | Patrol using bulldozer sprite; kills on contact |
ObjectType16 | Spider | Patrol; kills on contact |
ObjectType17 | Fish | Patrol (water sections); kills on contact |
ObjectType20 | Bird | Patrol; kills on contact |
ObjectType33 | Blupit Tank | Patrol; kills on contact |
All patrol enemies use linear movement between posStart and posEnd.
If a patrol enemy's start equals its end (stationary in level file), a default ±2 tile X patrol range is applied.
Contact detection uses a 0.85 unit radius check.
Moving Platforms
ObjectType1 is a moving platform lift. It moves linearly between two endpoints.
When Blupi is within 0.85 units horizontally and 1.5 units vertically of the platform center,
the platform's XZ movement delta is applied to Blupi's position via Blupi::ApplyExternalDelta().
The Level Exit
ObjectType7 is the level exit goal marker. When Blupi's position is within 0.85 units
of the exit, Decor::WasExitReached() returns true, the win sound plays, and the game
transitions to the Win phase, then loads the next world.
World Progression
- Worlds are numbered 1–5.
- Per-world sky: Grassland (1), Forest (2), Ice Caves (3), Lava Fields (4), Space Station (5).
- After world 5, wraps to world 1 (
currentWorld_resets to 1). - Each world adds +1 Crusher tile and +1 patrol enemy for increasing difficulty.
- Progress (current world, lives) is saved after every win/loss/quit.
Game Phases (Screens)
| Phase | Screen | Notes |
|---|---|---|
Init | Gamer-select / main menu | Keys 1/2/3 select slot; S opens settings; ESC quits |
Play | Active gameplay | Main game state |
Pause | Pause overlay | ESC resumes; S opens settings |
Win | Level complete | Any key advances to next world |
Lost | Game over | Any key returns to gamer-select |
MainSetup | Settings (from main menu) | S toggles sound; ESC returns |
PlaySetup | Settings (during pause) | S toggles sound; ESC returns |