SportsBallEngine/ARCHITECTURE.md
2025-12-15 16:03:37 -08:00

396 lines
13 KiB
Markdown

# 🏗️ SportsBallEngine Architecture
This document provides a detailed overview of the engine's architecture, following industry-standard design patterns for cross-platform game development.
## Core Principles
### 1. Strict Layer Separation
The engine is divided into two distinct categories:
#### **Platform-Agnostic Layer (Engine Core)**
- Pure Swift code with **ZERO** platform-specific imports
- Contains all game logic, physics, and asset management
- Can be tested and developed independently of any platform
- Modules: `EngineCore`, `PhysicsEngine`, `AssetLoader`
#### **Platform Abstraction Layer (PAL)**
- Thin wrappers around OS-specific APIs
- Implements protocols defined by the core layer
- Only place where platform-specific code exists
- Modules: `PlatformLinux`, `PlatformWin32`, `VulkanRenderer`, `DX12Renderer`
### 2. Protocol-Oriented Design
All platform-dependent functionality is accessed through Swift protocols:
```swift
// RendererAPI module (platform-agnostic)
public protocol Renderer: Sendable {
func initialize(config: RendererConfig) async throws
func beginFrame() throws
func draw(scene: Scene) throws
func endFrame() throws
func shutdown() async
// ... more methods
}
// VulkanRenderer module (platform-specific)
public final class VulkanRenderer: Renderer {
// Concrete Vulkan implementation
}
// DX12Renderer module (platform-specific)
public final class DX12Renderer: Renderer {
// Concrete DirectX 12 implementation
}
```
### 3. Dependency Injection
Platform implementations are created and injected at startup:
```swift
// main.swift
let renderer = PlatformFactory.createRenderer() // Creates Vulkan or DX12
let windowManager = PlatformFactory.createWindowManager()
let inputHandler = PlatformFactory.createInputHandler()
let audioEngine = PlatformFactory.createAudioEngine()
// Inject into engine core
let engine = GameEngine(
renderer: renderer,
windowManager: windowManager,
inputHandler: inputHandler,
audioEngine: audioEngine
)
```
## Module Dependency Graph
```
┌─────────────────────────────────────────────────────────────┐
│ main.swift │
│ (Platform Detection) │
└────────────────┬────────────────────────────────────────────┘
│ Creates & Injects
┌─────────────────────────────────────────────────────────────┐
│ EngineCore │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Main Loop │ │ Scene │ │ Systems │ │
│ │ (Fixed Δt) │ │ Management │ │Coordinator │ │
│ └────────────┘ └────────────┘ └────────────┘ │
│ │
│ Depends on protocols only: │
│ - Renderer (draw calls) │
│ - WindowManager (events) │
│ - InputHandler (keyboard/mouse) │
│ - AudioEngine (sound) │
└────────┬───────────────────┬──────────────────────────────┘
│ │
│ │
┌────▼────┐ ┌────▼────┐
│ Physics │ │ Asset │
│ Engine │ │ Loader │
└─────────┘ └─────────┘
┌─────────────────────────────────────────────────────────────┐
│ RendererAPI (Protocols) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Renderer │ │ Window │ │ Input │ │ Audio │ │
│ │ Protocol │ │ Protocol │ │ Protocol │ │ Protocol │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ Also defines: Scene, Camera, Entity, Transform, etc. │
└────┬─────────────┬─────────────┬─────────────┬────────────┘
│ │ │ │
│ │ │ │
│ │ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ Vulkan │ │ DX12 │ │ Platform│ │ Platform│
│Renderer │ │Renderer │ │ Linux │ │ Win32 │
└─────────┘ └─────────┘ └─────────┘ └─────────┘
│ │ │ │
│ │ │ │
┌────▼────────────▼─────────────▼─────────────▼────┐
│ Operating System APIs │
│ Vulkan | DirectX 12 | X11 | Wayland | Win32 │
└───────────────────────────────────────────────────┘
```
## Data Flow
### Frame Rendering Flow
```
1. main.swift
└─> GameEngine.runMainLoop()
2. EngineCore
├─> windowManager.processEvents() [Platform layer]
├─> inputHandler.pollEvents() [Platform layer]
├─> fixedUpdate(deltaTime) [Fixed timestep]
│ ├─> physicsEngine.step() [Core layer]
│ ├─> audioEngine.update() [Platform layer]
│ └─> updateGameLogic() [Core layer]
└─> render(interpolationAlpha)
├─> renderer.beginFrame() [Platform layer]
├─> renderer.draw(scene) [Platform layer]
└─> renderer.endFrame() [Platform layer]
3. Renderer (Vulkan or DX12)
├─> Acquire swapchain image
├─> Record command buffer
│ ├─> Bind pipeline
│ ├─> Set viewport/scissor
│ └─> For each entity:
│ ├─> Bind vertex/index buffers
│ └─> Draw indexed
├─> Submit command buffer
└─> Present to window
```
### Asset Loading Flow
```
1. EngineCore
└─> assetLoader.loadMesh("player.fbx")
2. AssetLoader
├─> Read file from disk
├─> Parse FBX format
├─> Extract vertices, indices, bones
└─> Return MeshData (CPU-side)
3. EngineCore
└─> renderer.loadMesh(vertices, indices)
4. Renderer (Vulkan or DX12)
├─> Allocate GPU buffer
├─> Upload data to GPU
└─> Return MeshHandle (GPU resource)
5. EngineCore
└─> Store MeshHandle for rendering
```
## Key Abstractions
### Renderer Protocol
Handles all graphics API calls:
- Frame management (begin/end)
- Scene rendering
- Resource loading (meshes, textures)
- Material creation
**Implementations**: `VulkanRenderer`, `DX12Renderer`
### WindowManager Protocol
Handles OS window management:
- Window creation/destruction
- Event processing (resize, close, etc.)
- Native handle retrieval (for surface creation)
- Fullscreen toggling
**Implementations**: `LinuxWindowManager`, `Win32WindowManager`
### InputHandler Protocol
Handles user input:
- Keyboard state
- Mouse state and position
- Gamepad/controller support
- Input events
**Implementations**: `LinuxInputHandler`, `Win32InputHandler`
### AudioEngine Protocol
Handles 3D audio:
- Audio loading and playback
- 3D spatial audio
- Listener position (camera)
- Volume control
**Implementations**: `LinuxAudioEngine`, `Win32AudioEngine`
## Sports Game Optimizations
### Physics System
The `PhysicsEngine` is optimized for sports scenarios:
```swift
// Special tracking for sports entities
private var ballBodies: Set<UUID> = [] // Balls/pucks
private var playerBodies: Set<UUID> = [] // Players
// Custom physics for balls
if ballBodies.contains(id) {
// Apply spin, air drag, magnus effect
let drag = -body.velocity * dragCoefficient
body.acceleration += drag / body.mass
}
```
### Animation System (Future)
Skeletal animation with state machines:
- Running → Shooting transition
- Tackling animations
- Celebration sequences
- Injury reactions
### Stadium Rendering (Future)
Large environment optimizations:
- LOD (Level of Detail) for distant objects
- Occlusion culling
- Crowd rendering (instancing)
- Particle systems (grass, dust)
## Thread Safety
The engine uses Swift 6 concurrency features:
- `actor` for thread-safe state management
- `Sendable` protocols for cross-thread data
- `async/await` for asynchronous operations
- `@unchecked Sendable` for platform handles
```swift
// EngineCore is an actor - all access is serialized
public actor GameEngine {
private let physicsEngine: PhysicsWorld
private var currentScene: Scene
// ...
}
```
## Build System
Uses Swift Package Manager with modular targets:
```swift
// Package.swift structure
targets: [
// Executable
.executableTarget(name: "SportsBallEngine", dependencies: [...]),
// Core modules (platform-agnostic)
.target(name: "EngineCore", dependencies: ["RendererAPI", ...]),
.target(name: "RendererAPI", dependencies: []),
.target(name: "PhysicsEngine", dependencies: []),
.target(name: "AssetLoader", dependencies: []),
// Platform modules (platform-specific)
.target(name: "VulkanRenderer", dependencies: ["RendererAPI"]),
.target(name: "DX12Renderer", dependencies: ["RendererAPI"]),
.target(name: "PlatformLinux", dependencies: ["RendererAPI", "VulkanRenderer"]),
.target(name: "PlatformWin32", dependencies: ["RendererAPI", "DX12Renderer"]),
]
```
## Testing Strategy
### Unit Tests
- Test core modules in isolation (no platform dependencies)
- Mock platform implementations using protocols
- Physics simulation verification
- Asset parsing validation
### Integration Tests
- Test platform implementations on target OS
- Renderer functionality tests
- Window management tests
- Input handling tests
### Performance Tests
- Frame time consistency
- Physics simulation speed
- Asset loading performance
- Memory usage profiling
## Extension Points
### Adding a New Platform
1. Create `Sources/Platform{Name}/`
2. Implement all protocols:
- `WindowManager`
- `InputHandler`
- `AudioEngine`
3. Choose or implement renderer
4. Update `PlatformFactory` in `main.swift`
### Adding a New Renderer
1. Create `Sources/{API}Renderer/`
2. Implement `Renderer` protocol
3. Handle resource loading (meshes, textures)
4. Implement draw commands
5. Add to `PlatformFactory`
### Adding Game-Specific Features
All game logic stays in `EngineCore` or custom modules:
- Player AI systems
- Ball physics customization
- Game rules and scoring
- Network synchronization
**Never** add game logic to platform layers!
## Performance Considerations
### Fixed Timestep
Uses fixed timestep for deterministic physics:
```swift
// Variable framerate for rendering
// Fixed 60Hz for physics/gameplay
while accumulator >= fixedTimeStep {
fixedUpdate(deltaTime: fixedTimeStep)
accumulator -= fixedTimeStep
}
// Interpolate between physics states for smooth rendering
render(interpolationAlpha: accumulator / fixedTimeStep)
```
### Memory Management
- GPU resources managed through opaque handles
- Asset caching with LRU eviction (future)
- Pool allocators for frequent objects (future)
- Reference counting for shared resources
### Multithreading (Future)
- Physics on separate thread
- Async asset loading
- GPU command recording parallelization
- Job system for parallel tasks
---
This architecture ensures:
- ✅ Clean separation of concerns
- ✅ Easy platform porting
- ✅ Testable core logic
- ✅ Maintainable codebase
- ✅ Performance optimization opportunities
- ✅ Sports game-specific features