ShadowEngine2D
A comprehensive 2D game engine built in Rust, featuring Entity-Component-System (ECS) architecture, modern graphics rendering, audio systems, asset management, animations, and scene management.
Features
- 🎮 Entity-Component-System (ECS) - Flexible and performant game object management
- 🎨 Modern Graphics - GPU-accelerated rendering with WGPU
- 🔊 Audio System - 3D positional audio, effects, and music playback
- 📦 Asset Management - Hot-reloadable assets with multiple format support
- 🎬 Animation System - Sprite animations and tweening with easing functions
- 🎭 Scene Management - Hierarchical scenes with transitions and lifecycle management
- ⌨️ Input Handling - Keyboard, mouse, and gamepad support
- 🖼️ UI System - Immediate-mode GUI with flexible layouts
- ⏱️ Time Management - Delta time, time scaling, and frame-rate independent logic
Quick Start
Add this to your Cargo.toml:
[dependencies]
shadowengine2d = "1.1.0"
Basic Usage
use shadowengine2d::prelude::*;
fn main() -> EngineResult<()> {
App::new()
.set_window(WindowConfig {
title: "My Game".to_string(),
width: 800,
height: 600,
resizable: true,
})
.add_startup_system(setup)
.add_system(update)
.build()
.run()
}
fn setup(engine: &mut Engine, resources: &mut Resources) -> EngineResult<()> {
engine.entities.spawn()
.ball(400.0, 300.0, 100.0, -150.0, Color::RED, 50.0)
.build();
Ok(())
}
fn update(engine: &mut Engine, resources: &mut Resources) -> EngineResult<()> {
if engine.input.is_key_pressed(KeyCode::Space) {
engine.entities.spawn()
.at_position(400.0, 100.0)
.with_colored_square(Color::BLUE, 32.0)
.with_movement(0.0, -200.0)
.build();
}
Ok(())
}
Entity Creation
let entity = engine.entities.spawn()
.at_position(100.0, 200.0)
.with_colored_square(Color::GREEN, 64.0)
.build();
let player = engine.entities.spawn()
.game_object(
Position::new(400.0, 300.0),
Sprite::new(Color::WHITE, Size::new(32.0, 48.0))
)
.with_velocity(Velocity::zero())
.build();
let ball = engine.entities.spawn()
.ball(x, y, vel_x, vel_y, color, size)
.build();
Resources
#[derive(Debug)]
struct GameState {
score: u32,
lives: u32,
}
app.insert_resource(GameState { score: 0, lives: 3 });
fn game_logic(engine: &mut Engine, resources: &mut Resources) -> EngineResult<()> {
let mut state = resources.get_mut::<GameState>().unwrap();
state.score += 10;
Ok(())
}
UI
fn ui_system(engine: &mut Engine, resources: &mut Resources) -> EngineResult<()> {
let mut ui = resources.get_mut::<UiContext>().unwrap();
ui.panel(Rect::new(10.0, 10.0, 200.0, 100.0), Color::new(0.0, 0.0, 0.0, 0.7));
ui.button(Rect::new(20.0, 30.0, 100.0, 30.0), "Start", ButtonStyle::primary());
ui.render_to_entities(&mut engine.entities);
Ok(())
}
Debug Output
use shadowengine2d::{Output, debug, info, warn, error};
Output::set_enabled(true);
Output::debug("Debug information");
Output::info("General information");
Output::warn("Warning message");
Output::error("Error message (always shown)");
debug!("Player at position ({}, {})", x, y);
info!("Score: {}, Lives: {}", score, lives);
warn!("Low health: {}%", health_percent);
error!("Failed to load asset: {}", filename);
Examples
cargo run --example bouncing_ball
cargo run --example modern_game
cargo run --example output_demo