A comprehensive dungeon generation and exploration game built with SpriteKit.
DeepLevel features a simple and intuitive touch-based control system:
- Directional Tap: Tap anywhere on screen to move continuously in that direction
- Stop Movement: Tap on the player character to stop movement
- Movement continues until hitting a boundary or obstacle
- Zoom In: Double-tap on the top half of the screen
- Zoom Out: Double-tap on the bottom half of the screen
The project uses Travis CI for automated building and testing:
- Builds for both iOS and macOS targets
- Runs unit tests on each commit
- Supports multiple Xcode versions
- Automatic deployment pipeline ready
DeepLevel is a sophisticated dungeon generation system that provides multiple algorithms for creating diverse and engaging underground and above ground environments. The game features real-time exploration with field-of-view calculations, pathfinding AI, and interactive gameplay elements.
The system supports three distinct generation algorithms:
- Room-and-Corridor: Traditional rectangular rooms connected by passages
- Binary Space Partitioning (BSP): Organic room layouts through recursive space division
- Cellular Automata: Cave-like structures with natural, irregular formations
GameScene
DungeonMap
Entity
TileKind
DungeonGenerating
DungeonGenerator
RoomsGenerator
BSPGenerator
CellularAutomataGenerator
DungeonConfig
Pathfinder
FOV
TileSetBuilder
HUD
Tile
Rect
SeededGenerator
Monster
PersistenceController
- doc:Getting-Started
- doc:Dungeon-Algorithms
- doc:Game-Architecture
Understand the different algorithms available for creating varied dungeon layouts.
DeepLevel offers three distinct algorithms for dungeon generation, each producing unique characteristics and gameplay experiences. Understanding these algorithms helps you choose the right approach for your game's needs.
The traditional approach that creates rectangular rooms connected by L-shaped corridors.
- Structure: Clean, architectural layouts with distinct rooms
- Connectivity: Guaranteed connectivity between all areas
- Doors: Automatic door placement at room entrances
- Secret Rooms: Optional hidden areas with secret doors
- Traditional dungeon crawlers
- Grid-based movement games
- Games requiring predictable room layouts
var config = DungeonConfig()
config.algorithm = .roomsCorridors
config.maxRooms = 20
config.roomMinSize = 4
config.roomMaxSize = 10
config.secretRoomChance = 0.08
config.roomBorders = true // Add 1-tile borders around rooms
Enable roomBorders
to add 1-tile thick wall borders around each room, creating a sidewalk-like effect around rooms similar to city blocks. This feature works with all generation algorithms and provides visual separation between rooms and corridors.
Recursively divides space into smaller regions, creating more organic room arrangements.
- Structure: Varied room sizes with natural clustering
- Layout: Tree-based connectivity following partition hierarchy
- Flexibility: Adapts to different space constraints
- Organic Feel: Less rigid than room-and-corridor
- Exploration-focused games
- Varied pacing with different room densities
- More realistic architectural layouts
var config = DungeonConfig()
config.algorithm = .bsp
config.bspMaxDepth = 5
config.roomMinSize = 4
config.roomMaxSize = 10
config.roomBorders = true // Add 1-tile borders around rooms
Creates cave-like structures using iterative smoothing rules.
- Structure: Organic, natural cave systems
- Connectivity: Single large connected area
- Irregularity: No geometric patterns or straight lines
- Realism: Resembles natural cave formations
- Cave exploration games
- Organic, natural environments
- Survival or mining games
var config = DungeonConfig()
config.algorithm = .cellular
config.cellularFillProb = 0.45 // Initial wall density
config.cellularSteps = 5 // Smoothing iterations
Feature | Room-Corridor | BSP | Cellular |
---|---|---|---|
Room Definition | Explicit rectangular rooms | Varied organic rooms | Open cave areas |
Connectivity | Corridor network | Hierarchical tree | Single large space |
Predictability | High | Medium | Low |
Navigation | Grid-friendly | Moderate complexity | Freeform |
Doors | Automatic placement | Possible | Not applicable |
- Room-Corridor: O(width × height + maxRooms²)
- BSP: O(width × height + 2^maxDepth)
- Cellular: O(width × height × cellularSteps)
DeepLevel is built with a modular architecture that separates concerns between generation, rendering, gameplay, and persistence. This design enables flexibility and maintainability while supporting real-time gameplay.
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ User Input │ │ Game Logic │ │ Rendering │
│ │ │ │ │ │
│ Touch/Keyboard │───▶│ GameScene │───▶│ SpriteKit │
│ SwiftUI Views │ │ Entity │ │ TileMapNode │
└─────────────────┘ │ HUD │ │ SKSpriteNode │
└─────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Generation │ │ Game Systems │ │ Persistence │
│ │ │ │ │ │
│ DungeonGenerator│◀───│ Pathfinder │ │ CoreData │
│ Algorithms │ │ FOV │ │ CloudKit │
│ TileSetBuilder │ │ Physics │ │ UserDefaults │
└─────────────────┘ └─────────────────┘ └─────────────────┘
- SwiftUI Views: App structure and UI integration
- SpriteKit Rendering: Game visuals and animations
- Input Handling: Touch and keyboard input processing
- GameScene: Main game coordinator and update loop
- Entity System: Player, monsters, and item management
- HUD: User interface and information display
- Pathfinding: A* algorithm for AI movement
- Field of View: Visibility and exploration tracking
- Physics: Collision detection and movement validation
- DungeonGenerator: Algorithm coordination and post-processing
- Generation Algorithms: Room-corridor, BSP, cellular automata
- TileSetBuilder: Texture and tile group creation
- Core Data: Local data storage and object management
- CloudKit: Cross-device synchronization
- Configuration: Settings and preferences
- Configuration →
DungeonConfig
defines parameters - Algorithm Selection →
DungeonGenerator
chooses implementation - Generation → Algorithm creates
DungeonMap
- Post-Processing → Floor variants and optimizations
- Tile Building →
TileSetBuilder
creates visual assets
- Input → User actions create movement requests
- Validation →
DungeonMap
checks movement legality - Entity Update → Positions and states change
- AI Processing →
Pathfinder
calculates monster movement - Visibility →
FOV
updates visible tiles - Rendering → SpriteKit draws current state
override func update(_ currentTime: TimeInterval) {
// 1. Process input
handlePendingInput()
// 2. Update game logic
updateEntities(deltaTime: currentTime - lastUpdateTime)
// 3. AI processing
updateMonsterAI()
// 4. Visibility calculation
updateFieldOfView()
// 5. Camera and HUD
updateCamera()
updateHUD()
lastUpdateTime = currentTime
}
- Entities query
DungeonMap
for movement validation - Map provides collision and visibility information
- Entities update their grid positions through map constraints
TileSetBuilder
converts logical tiles to visual assetsTileRefs
provides efficient access to tile groups- Texture caching optimizes memory usage
Pathfinder
uses map data for navigationFOV
tracks exploration state- Monster AI combines pathfinding with visibility data
- Texture caching in
TileSetBuilder
- Object pooling for frequently created entities
- Lazy loading of visual assets
- A* pathfinding with early termination
- Incremental FOV updates
- Batch tile updates for rendering
- Configurable complexity parameters
- Adaptive quality based on device performance
- Modular algorithm implementations
The architecture supports extension through:
Implement DungeonGenerating
protocol for new generation methods
Extend Entity
class hierarchy for new game objects
Add processing systems that operate on game state
Extend TileSetBuilder
for visual effects and animations
- Unit Tests: Algorithm correctness and edge cases
- Integration Tests: Component interaction validation
- UI Tests: User flow and screenshot regression
- Performance Tests: Generation time and memory usage
DeepLevel provides a complete solution for procedural dungeon generation in Swift games. This guide will walk you through the basic setup and usage patterns.
import DeepLevel
// Configure generation parameters
var config = DungeonConfig()
config.width = 80
config.height = 50
config.algorithm = .roomsCorridors
config.seed = 12345 // For reproducible results
// Generate the dungeon
let generator = DungeonGenerator(config: config)
let dungeon = generator.generate()
// Access the result
print("Generated dungeon with \(dungeon.rooms.count) rooms")
print("Player starts at: \(dungeon.playerStart)")
// Build tile set for rendering
let (tileSet, tileRefs) = TileSetBuilder.build(tileSize: 24.0)
// Create tile map node
let tileMapNode = SKTileMapNode(
tileSet: tileSet,
columns: dungeon.width,
rows: dungeon.height,
tileSize: CGSize(width: 24, height: 24)
)
// Apply tiles to the map
for y in 0..<dungeon.height {
for x in 0..<dungeon.width {
let tile = dungeon.tiles[dungeon.index(x: x, y: y)]
let tileGroup: SKTileGroup
switch tile.kind {
case .floor:
tileGroup = tileRefs.floorVariants[tile.variant]
case .wall:
tileGroup = tileRefs.wall
case .doorClosed:
tileGroup = tileRefs.door
case .doorSecret:
tileGroup = tileRefs.secretDoor
}
tileMapNode.setTileGroup(tileGroup, forColumn: x, row: y)
}
}
// Update field of view from player position
var mutableDungeon = dungeon
FOV.compute(
map: &mutableDungeon,
originX: playerX,
originY: playerY,
radius: 8
)
// Check tile visibility
let tile = mutableDungeon.tiles[mutableDungeon.index(x: x, y: y)]
if tile.visible {
// Tile is currently visible
}
if tile.explored {
// Tile has been seen before
}