shadowengine2d 2.0.0

A comprehensive 2D game engine built in Rust with ECS, rendering, audio, assets, animations, and scene management
Documentation

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
  • Particle System - Advanced 2D particles with randomization, gravity, burst emission, and custom behaviors

Particle System

ShadowEngine2D includes an advanced 2D particle system for effects like explosions, fire, smoke, and more. Features include:

  • Randomized velocity, color, and size
  • Gravity and acceleration
  • Burst emission and emission shapes (point, circle)
  • Custom update callbacks for unique behaviors

Basic Usage

use shadowengine2d::prelude::*;

let mut emitter = ParticleEmitter::new(Position::new(400.0, 300.0));
emitter.emission_rate = 100.0;
emitter.particle_lifetime = 2.0;
emitter.particle_size = 10.0;
emitter.color = [1.0, 0.5, 0.2, 1.0];
emitter.velocity = Position::new(0.0, -150.0);
emitter.gravity = Position::new(0.0, 300.0);
emitter.velocity_randomness = Position::new(50.0, 50.0);
emitter.size_randomness = 5.0;
emitter.emission_shape = EmissionShape::Circle { radius: 20.0 };
emitter.burst = Some(50); // Optional: burst emission

// In your update loop:
emitter.update(delta_time);

// In your render loop:
emitter.render(&mut renderer);

// Optional: custom update callback for advanced effects
emitter.custom_update = Some(Box::new(|particle, dt| {
    // Example: fade out alpha
    particle.color[3] = 1.0 - (particle.age / particle.lifetime);
}));

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};

// Enable/disable debug output
Output::set_enabled(true);

// Different log levels
Output::debug("Debug information");
Output::info("General information");
Output::warn("Warning message");
Output::error("Error message (always shown)");

// Or use convenient macros with formatting
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