jugar-procgen

Procedural generation: noise, dungeons, and Wave Function Collapse.

Value Noise

#![allow(unused)]
fn main() {
use jugar_procgen::noise::*;

let noise = ValueNoise::new(seed);

// Single value at point
let value = noise.sample(x, y);  // Returns 0.0 to 1.0

// With octaves (fractal noise)
let config = NoiseConfig {
    octaves: 4,
    persistence: 0.5,  // Amplitude decrease per octave
    lacunarity: 2.0,   // Frequency increase per octave
    scale: 0.01,
};
let value = noise.sample_octaves(x, y, &config);
}

Noise Types

#![allow(unused)]
fn main() {
// Value noise (smooth)
let value = ValueNoise::new(seed);

// Perlin noise (gradient-based)
let perlin = PerlinNoise::new(seed);

// Simplex noise (faster, less artifacts)
let simplex = SimplexNoise::new(seed);

// Worley noise (cellular)
let worley = WorleyNoise::new(seed);
}

Generating Terrain

#![allow(unused)]
fn main() {
fn generate_heightmap(width: usize, height: usize, seed: u64) -> Vec<f32> {
    let noise = SimplexNoise::new(seed);
    let config = NoiseConfig::default();

    let mut heightmap = vec![0.0; width * height];

    for y in 0..height {
        for x in 0..width {
            let value = noise.sample_octaves(
                x as f32,
                y as f32,
                &config,
            );
            heightmap[y * width + x] = value;
        }
    }

    heightmap
}
}

Dungeon Generation

#![allow(unused)]
fn main() {
use jugar_procgen::dungeon::*;

// BSP-based dungeon
let config = DungeonConfig {
    width: 80,
    height: 60,
    min_room_size: 5,
    max_room_size: 15,
    corridor_width: 2,
};

let dungeon = BspDungeon::generate(config, seed);

// Access tiles
for y in 0..dungeon.height {
    for x in 0..dungeon.width {
        match dungeon.get_tile(x, y) {
            Tile::Floor => { /* walkable */ }
            Tile::Wall => { /* blocked */ }
            Tile::Door => { /* door */ }
        }
    }
}

// Get rooms
for room in dungeon.rooms() {
    spawn_enemies_in_room(room);
}
}

Wave Function Collapse

#![allow(unused)]
fn main() {
use jugar_procgen::wfc::*;

// Define tiles and rules
let tiles = vec![
    Tile::new("grass").edges(["g", "g", "g", "g"]),
    Tile::new("water").edges(["w", "w", "w", "w"]),
    Tile::new("shore_n").edges(["g", "g", "w", "g"]),
    // ... more tiles with edge constraints
];

let wfc = WaveFunctionCollapse::new(tiles);

// Generate map
let result = wfc.generate(width, height, seed);

for y in 0..height {
    for x in 0..width {
        let tile = result.get(x, y);
        render_tile(tile, x, y);
    }
}
}

WFC Constraints

#![allow(unused)]
fn main() {
// Socket-based constraints
let tiles = vec![
    Tile::new("road_horizontal")
        .sockets(Socket {
            north: "grass",
            south: "grass",
            east: "road",
            west: "road",
        }),
    Tile::new("road_vertical")
        .sockets(Socket {
            north: "road",
            south: "road",
            east: "grass",
            west: "grass",
        }),
    // ...
];
}

Room Placement

#![allow(unused)]
fn main() {
use jugar_procgen::rooms::*;

let mut placer = RoomPlacer::new(100, 100);

// Add rooms with constraints
placer.add_room(Room::new(10, 10).tag("spawn"));
placer.add_room(Room::new(15, 15).tag("boss"));
placer.add_rooms(5, Room::random(5..10, 5..10).tag("normal"));

// Connect rooms
placer.connect_all_rooms();

// Generate
let layout = placer.generate(seed);
}

Combining Techniques

#![allow(unused)]
fn main() {
fn generate_world(seed: u64) -> World {
    // 1. Generate heightmap with noise
    let heightmap = generate_heightmap(256, 256, seed);

    // 2. Generate dungeon layout
    let dungeon = BspDungeon::generate(config, seed);

    // 3. Use WFC to fill in details
    let details = wfc.generate(dungeon.width, dungeon.height, seed);

    // 4. Combine everything
    // ...
}
}