A classic Breakout/Arkanoid clone demonstrating physics, collision detection, and entity management in the SolarSail engine.
- Paddle movement with arrow keys/A/D
- Ball launching with SPACE
- Paddle-ball collision with angle control
- 50 bricks dynamically spawned
- Ball-brick collision and destruction with ray-cast collision detection
- Score tracking (10-50 points per brick)
- Lives system (3 lives)
- Game over and restart functionality
- Left/Right Arrow or A/D: Move paddle
- Space: Launch ball / Start game
- R: Restart game
- Q: Quit
- Paddle with smooth movement
- Ball physics with velocity reflection
- Brick grid with different colors/points per row
- Score tracking and lives system
- Ball spin based on paddle hit position
- Progressive speed increase
-
Shared Game State: Uses a
game_state.lua
module to share references between scripts- Avoids the need for entity lookups (which aren't available as globals in SolarSail)
- Similar pattern to asteroids and snake demos
-
Template System: Bricks are created using
instantiateTemplate()
- Template defined in
game.json
- 50 instances created dynamically at runtime
- Template defined in
-
Ray-Cast Collision Detection: Uses engine raycast methods for accurate collision
- Prevents multi-collision bugs by checking entire movement path
- Always hits closest brick first for proper temporal ordering
-
Frame-Independent Movement: Uses
Time.deltaTime
for all physics- Ensures consistent gameplay at any framerate
-
Component Pattern: Each game object (paddle, ball, brick) has its own script
- Promotes code organization and reusability
game.json
- Scene definition with entities and templatesprogram.lua
- Main engine callbacksgame_controller.lua
- Game logic, scoring, livespaddle.lua
- Paddle movement logicball.lua
- Ball physics and collision detectionbrick.lua
- Brick destruction behaviorgame_state.lua
- Shared state between scriptsconfig.lua
- Game configuration (speeds, sizes, etc.)
-
Create SVG files with transparent backgrounds:
ball.svg
- 32x32 ball with radial gradientpaddle.svg
- 64x16 paddle with metallic gradientbrick.svg
- 48x16 brick with 3D bevel effect
-
Convert SVG to PNG using Inkscape CLI:
inkscape ball.svg -o ball.png -w 32 -h 32 inkscape paddle.svg -o paddle.png -w 64 -h 16 inkscape brick.svg -o brick.png -w 48 -h 16
-
Create different colored bricks (optional):
# Edit brick.svg to change colors, then convert each variant inkscape brick_red.svg -o brick_red.png -w 48 -h 16 inkscape brick_orange.svg -o brick_orange.png -w 48 -h 16 # etc...
-
Combine into atlas:
# Create a blank transparent canvas for the atlas convert -size 128x64 xc:transparent atlas.png # Composite sprites onto the atlas at specific positions convert atlas.png ball.png -geometry +0+0 -composite atlas.png # Ball at (0,0) convert atlas.png paddle.png -geometry +32+0 -composite atlas.png # Paddle at (32,0) convert atlas.png brick.png -geometry +0+32 -composite atlas.png # Brick at (0,32)
Atlas Layout:
0,0 32,0 96,0 +------+------------+ | Ball | Paddle | | 32x32| 64x16 | +------+------------+ | Brick | | 48x16 | +------------------+ 0,32 48,32
-
Update atlas.lua to match sprite positions:
-- Ball sprite sprite = addsprite() sprite.name = "ball" sprite.frame.x = 0 -- X position in atlas sprite.frame.y = 0 -- Y position in atlas sprite.frame.width = 32 sprite.frame.height = 32 -- Paddle sprite sprite = addsprite() sprite.name = "paddle" sprite.frame.x = 32 -- Positioned right of ball sprite.frame.y = 0 sprite.frame.width = 64 sprite.frame.height = 16 -- Brick sprite sprite = addsprite() sprite.name = "brick" sprite.frame.x = 0 -- New row below ball sprite.frame.y = 32 sprite.frame.width = 48 sprite.frame.height = 16
- Use gradients for 3D effects (radial for spheres, linear for flat surfaces)
- Add subtle highlights and shadows
- Keep stroke widths consistent (1px works well at these sizes)
- Use opacity for softer highlights
- Design at exact pixel dimensions to avoid scaling artifacts
- Performance: Single texture = fewer draw calls
- Memory: More efficient than loading multiple textures
- Simplicity: One file to manage instead of many
- Plan the layout - Draw it on paper first
- Use power-of-2 dimensions when possible (128x64 in our case)
- Leave transparent padding between sprites to avoid bleeding
- Group related sprites together (all bricks in one area, etc.)
- Document the layout in your README for future reference
make
- Uses SolarSail's Entity Component System
- All coordinates in world space (-1.78 to 1.78 for X, -1 to 1 for Y)
- Collision detection uses AABB (Axis-Aligned Bounding Box)
- Ball velocity reflection based on surface normals
- Paddle hit position affects ball trajectory for player control
- Visual score display (currently console only)
- Sound effects and music
- Power-ups (multi-ball, wider paddle, etc.)
- Different brick patterns/levels
- High score tracking
- Particle effects for brick destruction
- Multiple ball support
- Special bricks (unbreakable, multi-hit, etc.)