How to Create a Custom Level
This tutorial shows how to design and implement a new level in R-Type.
📋 Level Structure​
A level consists of:
- Metadata: Name, duration, background, music
- Waves: Timed enemy spawn events
- Boss: Final boss encounter
- Scripted Events: Story moments, cutscenes
🎯 Step 1: Create Level File​
Create config/game/levels/level4.toml:
[level]
id = 4 # Unique level number
name = "Nebula Gauntlet" # Display name
description = "Navigate through a dangerous nebula field"
background = "bg_nebula.png" # Background image
parallax_layers = [ # Optional parallax scrolling
{ sprite = "nebula_far.png", speed = 0.2 },
{ sprite = "nebula_mid.png", speed = 0.5 },
{ sprite = "nebula_near.png", speed = 0.8 }
]
music = "level4_music.ogg" # Background music
duration = 240 # Level duration (seconds, 0 = until boss defeated)
difficulty_multiplier = 1.5 # Difficulty scaling
🎯 Step 2: Design Wave Sequence​
Basic Wave Structure​
[[wave]]
time = 10 # Spawn at 10 seconds into level
enemy = "scout" # Enemy type (from enemies.toml)
count = 12 # Number of enemies
formation = "v" # Formation pattern
spawn_interval = 0.5 # Seconds between individual spawns
spawn_x = 1920 # X position (right edge of screen)
spawn_y = 360 # Y position (or "random")
Full Wave Sequence Example​
# Early wave - introduce level
[[wave]]
time = 5
enemy = "scout"
count = 8
formation = "line"
spawn_interval = 0.6
spawn_x = 1920
spawn_y = "random"
# Mid wave - increase difficulty
[[wave]]
time = 30
enemy = "interceptor"
count = 10
formation = "v"
spawn_interval = 0.8
spawn_x = 1920
spawn_y = 360
# Mixed wave - variety
[[wave]]
time = 45
enemy = "scout"
count = 6
formation = "box"
spawn_interval = 0.5
spawn_x = 1920
spawn_y = 200
[[wave]]
time = 48 # Overlaps with previous wave
enemy = "heavy"
count = 3
formation = "line"
spawn_interval = 1.5
spawn_x = 1920
spawn_y = 600
# Challenge wave - many enemies
[[wave]]
time = 60
enemy = "interceptor"
count = 15
formation = "random"
spawn_interval = 0.4
spawn_x = "random" # Can also randomize X
spawn_y = "random"
# Elite wave - tough enemies
[[wave]]
time = 90
enemy = "elite_cruiser"
count = 5
formation = "wedge"
spawn_interval = 2.0
spawn_x = 1920
spawn_y = 360
🎯 Step 3: Formation Patterns​
Available Formations​
V-Formation​
formation = "v"
formation_params = {
angle = 45.0, # Angle of V (degrees)
spacing = 50.0, # Distance between units
direction = "right" # or "left", "up", "down"
}
Line Formation​
formation = "line"
formation_params = {
spacing = 60.0,
orientation = "horizontal" # or "vertical"
}
Box/Grid Formation​
formation = "box"
formation_params = {
rows = 3,
cols = 4,
spacing_x = 50.0,
spacing_y = 50.0
}
Circle Formation​
formation = "circle"
formation_params = {
radius = 150.0
}
Wedge Formation​
formation = "wedge"
formation_params = {
angle = 60.0,
spacing = 40.0
}
Random Formation​
formation = "random"
formation_params = {
min_x = 1500,
max_x = 1920,
min_y = 100,
max_y = 980
}
🎯 Step 4: Add Boss Fight​
[[boss]]
enemy = "nebula_guardian" # Boss enemy ID
spawn_time = 180 # Spawn at 3 minutes
music = "boss_theme_2.ogg" # Boss battle music
warning_time = 10 # Warning shown 10s before
warning_message = "DANGER: BOSS INCOMING!"
camera_shake_on_spawn = true
screen_flash_on_spawn = true
Multi-Phase Boss​
[[boss]]
enemy = "mothership"
spawn_time = 200
music = "final_boss.ogg"
warning_time = 15
warning_message = "FINAL BOSS: MOTHERSHIP"
# Boss phases trigger at HP thresholds
[[boss.phases]]
phase = 1
health_threshold = 10000 # Full health
behavior = "stationary"
fire_pattern = "spread"
minion_spawn_rate = 5.0 # Spawn minions every 5s
minion_type = "drone"
message = "Phase 1: Destroy the shield generators!"
[[boss.phases]]
phase = 2
health_threshold = 6000 # 60% HP
behavior = "circle"
fire_pattern = "spiral"
minion_spawn_rate = 3.0
minion_type = "interceptor"
message = "Phase 2: The shields are down!"
camera_shake_intensity = 2.0
[[boss.phases]]
phase = 3
health_threshold = 2000 # 20% HP
behavior = "kamikaze"
fire_pattern = "chaos"
minion_spawn_rate = 1.0
minion_type = "elite"
message = "Phase 3: Final assault!"
screen_tint = [255, 0, 0, 50] # Red tint (RGBA)
🎯 Step 5: Scripted Events​
Cutscene/Dialogue​
[[event]]
type = "dialogue"
time = 0 # Start of level
character = "commander"
text = "Entering nebula sector. Stay alert!"
duration = 3.0 # Seconds
voice_clip = "commander_alert.ogg"
[[event]]
type = "dialogue"
time = 120
character = "pilot"
text = "Enemy mothership detected ahead!"
duration = 3.0
Environmental Hazards​
[[event]]
type = "hazard"
time = 45
hazard = "asteroid_field"
duration = 20.0 # 20 seconds of asteroids
spawn_rate = 2.0 # Asteroids per second
damage = 25
Power-Up Drops​
[[event]]
type = "powerup_spawn"
time = 60
powerup = "force_pod"
position = { x = 1500, y = 360 }
Checkpoint​
[[event]]
type = "checkpoint"
time = 120
message = "Checkpoint reached"
save_progress = true
🎯 Step 6: Background & Atmosphere​
Static Background​
[level]
background = "bg_nebula.png"
background_scroll_speed = 100.0 # Pixels per second
Parallax Scrolling​
[level]
parallax_layers = [
{
sprite = "stars_far.png",
speed = 0.1, # 10% of camera speed
repeat = true
},
{
sprite = "nebula_mid.png",
speed = 0.5, # 50% of camera speed
repeat = true
},
{
sprite = "debris_near.png",
speed = 1.2, # 120% - moves faster than camera
repeat = true
}
]
Lighting & Effects​
[level.atmosphere]
ambient_color = [50, 100, 200, 255] # Blue tint (RGBA)
fog_enabled = true
fog_color = [100, 150, 200, 100]
fog_density = 0.5
particle_effects = [
{ type = "stars", density = 100 },
{ type = "nebula_gas", density = 50, color = [255, 0, 255, 128] }
]
🎯 Step 7: Difficulty Curve​
Pacing Guidelines​
Introduction (0-30s):
- Easy enemies
- Low spawn rate
- Teach mechanics
Build-Up (30-90s):
- Increase variety
- Mix enemy types
- Introduce patterns
Climax (90-150s):
- High difficulty
- Dense waves
- Pressure player
Boss Intro (150-180s):
- Calm before storm
- Final power-up
- Boss warning
Boss Fight (180s+):
- Epic encounter
- Multiple phases
- Victory!
Example Pacing​
# Introduction - Easy
[[wave]]
time = 5
enemy = "scout"
count = 6
spawn_interval = 1.0
# Build-up - Increasing
[[wave]]
time = 30
enemy = "scout"
count = 10
spawn_interval = 0.8
[[wave]]
time = 45
enemy = "interceptor"
count = 8
spawn_interval = 0.7
# Climax - Intense
[[wave]]
time = 90
enemy = "scout"
count = 20
spawn_interval = 0.3
[[wave]]
time = 95
enemy = "heavy"
count = 5
spawn_interval = 1.0
# Calm - Prepare for boss
[[wave]]
time = 150
enemy = "scout"
count = 3
spawn_interval = 2.0
# Boss
[[boss]]
spawn_time = 180
enemy = "boss"
🎯 Step 8: Testing & Balancing​
Playtesting Checklist​
- Level starts correctly
- Waves spawn at right times
- Formation patterns work
- Boss appears and functions
- Difficulty feels appropriate
- Music transitions smoothly
- Background looks good
- Events trigger correctly
- Level is completable
- Performance is acceptable
Balancing Tips​
-
Count enemy HP pools:
- Total damage needed to complete level
- Ensure player has enough time/ammo
-
Check spawn density:
- Don't overwhelm player
- Allow breathing room between waves
-
Test with different player counts:
- Solo should be possible
- 4-player shouldn't be trivial
-
Verify power-up availability:
- Enough power-ups to stay equipped
- Not so many it's too easy
Debug Mode​
Add test configuration:
[level.debug]
enabled = true
player_invincible = false
skip_to_time = 0 # Jump to specific time
spawn_all_powerups = false
show_hitboxes = false
🎯 Step 9: Add to Level Progression​
Edit config/game/levels.toml:
[campaign]
levels = [
"level1.toml",
"level2.toml",
"level3.toml",
"level4.toml" # Your new level
]
[[level_unlock]]
level = 4
requires_completion = 3 # Must beat level 3
min_score = 50000 # Optional score requirement
🎯 Step 10: Create Assets​
Background Image​
- Resolution: 1920x1080 or larger
- Format: PNG
- Location:
assets/img/ - Seamless: Tileable for infinite scrolling
Music​
- Format: OGG Vorbis
- Length: 2-3 minutes (loopable)
- Location:
assets/audio/ - Loop point: Set loop markers in audio editor
Example: Creating Looping Music​
Using Audacity:
1. Create/import 2-minute track
2. Ensure smooth loop:
- Fade in at start
- Fade out at end
- Match waveforms at loop point
3. Export as OGG:
- File → Export → Export as OGG
- Quality: 5-7
- Add loop metadata
📊 Level Design Patterns​
Wave-Based Level​
Focus on timed enemy waves with boss at end.
duration = 180
# Multiple waves leading to boss
[[boss]]
spawn_time = 180
Gauntlet Level​
Continuous enemy stream, no distinct waves.
duration = 300
# Many small waves with short intervals
[[wave]]
time = 0
count = 3
[[wave]]
time = 5
count = 3
# ... continues
Boss Rush​
Multiple bosses, minimal trash mobs.
[[boss]]
spawn_time = 30
enemy = "mini_boss_1"
[[boss]]
spawn_time = 90
enemy = "mini_boss_2"
[[boss]]
spawn_time = 150
enemy = "final_boss"
Survival Level​
Time-based, increasing difficulty.
duration = 0 # Infinite
difficulty_increase_rate = 0.1 # 10% per minute
🎓 Advanced Techniques​
Dynamic Difficulty​
Adjust level based on player performance:
[level.adaptive]
enabled = true
track_player_deaths = true
adjust_enemy_health = true
health_adjustment_range = [0.7, 1.3] # 70%-130%
adjust_spawn_rate = true
spawn_rate_range = [0.8, 1.2]
Branching Paths​
Let players choose route through level:
[[event]]
type = "choice"
time = 60
message = "Choose your path:"
options = [
{ text = "Left path (harder, better rewards)", trigger_waves = ["hard_left_1", "hard_left_2"] },
{ text = "Right path (easier)", trigger_waves = ["easy_right_1", "easy_right_2"] }
]
Destructible Environment​
Objects players can destroy:
[[obstacle]]
type = "destructible"
sprite = "space_station.png"
position = { x = 1200, y = 400 }
health = 200
score = 500
drop_powerup = "mega_bomb"
📚 Example: Complete Level​
See config/game/levels/level2.toml for a complete, balanced level example.
📖 Related Documentation​
Happy level designing! 🎮