Skip to content

foxzool/bevy_fog_of_war

Repository files navigation

Bevy Fog of War

中文文档 | English

Fog of war screenshot

CI Crates.io Downloads Documentation MIT/Apache 2.0

bevy_fog_of_war is a 2D fog-of-war plugin for Bevy with GPU rendering, chunk-based streaming, explored-area snapshots, and persistence helpers.

Highlights

  • Chunk-based fog processing suitable for large 2D maps.
  • Circle, square, and cone VisionSource shapes.
  • Three visibility states: Unexplored, Explored, and Visible.
  • Capturable entities that can be revealed and snapshotted.
  • Atomic fog reset with FogResetSuccess / FogResetFailed messages.
  • Save/load flow through Bevy messages.
  • Optional JSON / MessagePack / bincode serialization.
  • Optional gzip / LZ4 / Zstd file helpers in persistence_utils.

Compatibility

bevy_fog_of_war Bevy
0.3.x 0.18

Installation

[dependencies]
bevy = "0.18"
bevy_fog_of_war = "0.3"

Default features enable format-bincode.

Optional feature flags

# Add MessagePack support
bevy_fog_of_war = { version = "0.3", features = ["format-messagepack"] }

# Add JSON support
bevy_fog_of_war = { version = "0.3", features = ["format-json"] }

# Add compression helpers for persistence_utils
bevy_fog_of_war = { version = "0.3", features = ["compression-zstd"] }

# Everything: all formats + all compression helpers
bevy_fog_of_war = { version = "0.3", features = ["all-formats"] }

Quick start

Most users can import everything they need with:

use bevy_fog_of_war::prelude::*;

Minimal setup:

use bevy::prelude::*;
use bevy::render::render_resource::TextureFormat;
use bevy_fog_of_war::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(FogOfWarPlugin)
        .add_systems(Startup, setup)
        .run();
}

fn setup(mut commands: Commands, mut fog: ResMut<FogMapSettings>) {
    commands.spawn((Camera2d, FogOfWarCamera, VisionSource::circle(120.0)));

    commands.spawn((
        Sprite {
            color: Color::srgb(0.2, 0.8, 0.8),
            custom_size: Some(Vec2::splat(48.0)),
            ..default()
        },
        Transform::from_xyz(160.0, 0.0, 0.0),
        Capturable,
    ));

    *fog = FogMapSettings {
        enabled: true,
        chunk_size: UVec2::splat(256),
        texture_resolution_per_chunk: UVec2::splat(512),
        fog_color_unexplored: Color::BLACK,
        fog_color_explored: bevy::color::palettes::basic::GRAY.into(),
        vision_clear_color: Color::NONE,
        fog_texture_format: TextureFormat::R8Unorm,
        snapshot_texture_format: TextureFormat::Rgba8UnormSrgb,
    };
}

Core concepts

FogOfWarCamera

Mark the 2D camera that should drive fog rendering:

commands.spawn((Camera2d, FogOfWarCamera));

You can also attach a VisionSource to the camera if you want the camera/player to reveal nearby areas.

VisionSource

Use built-in constructors for common shapes:

commands.spawn((Transform::default(), VisionSource::circle(120.0)));
commands.spawn((Transform::default(), VisionSource::square(120.0)));
commands.spawn((
    Transform::default(),
    VisionSource::cone(180.0, 0.0, std::f32::consts::FRAC_PI_2),
));

Capturable

Add Capturable to entities that should only be visible after they have been discovered by fog-of-war vision.

Resetting fog

Send ResetFogOfWar to clear explored state and rebuild the fog textures without respawning your world:

use bevy::prelude::*;
use bevy_fog_of_war::prelude::*;

fn reset_on_keypress(
    keyboard: Res<ButtonInput<KeyCode>>,
    mut reset: MessageWriter<ResetFogOfWar>,
) {
    if keyboard.just_pressed(KeyCode::KeyR) {
        reset.write(ResetFogOfWar);
    }
}

fn handle_reset_messages(
    mut success: MessageReader<FogResetSuccess>,
    mut failed: MessageReader<FogResetFailed>,
) {
    for event in success.read() {
        info!(
            "fog reset finished in {}ms ({} chunks)",
            event.duration_ms, event.chunks_reset
        );
    }

    for event in failed.read() {
        error!("fog reset failed after {}ms: {}", event.duration_ms, event.error);
    }
}

Persistence via Bevy messages

The runtime API uses Bevy messages plus raw bytes. Compression-oriented file helpers live in persistence_utils.

Save

use bevy::prelude::*;
use bevy_fog_of_war::prelude::*;

fn request_save(mut save: MessageWriter<SaveFogOfWarRequest>) {
    save.write(SaveFogOfWarRequest {
        include_texture_data: true,
        format: None, // auto-picks the best enabled SerializationFormat
    });
}

fn handle_saved(mut events: MessageReader<FogOfWarSaved>) {
    for event in events.read() {
        let ext = match event.format {
            #[cfg(feature = "format-json")]
            SerializationFormat::Json => "json",
            #[cfg(feature = "format-messagepack")]
            SerializationFormat::MessagePack => "msgpack",
            #[cfg(feature = "format-bincode")]
            SerializationFormat::Bincode => "bincode",
        };

        let path = format!("fog_save.{ext}");
        std::fs::write(&path, &event.data).expect("failed to write fog save");
        info!("saved {} chunks to {}", event.chunk_count, path);
    }
}

Load

use bevy::prelude::*;
use bevy_fog_of_war::prelude::*;

fn request_load(mut load: MessageWriter<LoadFogOfWarRequest>) {
    if let Ok(data) = std::fs::read("fog_save.bincode") {
        load.write(LoadFogOfWarRequest {
            data,
            format: None, // auto-detect from bytes
        });
    }
}

fn handle_loaded(mut events: MessageReader<FogOfWarLoaded>) {
    for event in events.read() {
        info!("loaded {} chunks", event.chunk_count);

        for warning in &event.warnings {
            warn!("load warning: {warning}");
        }
    }
}

Persistence file helpers

If you want extension-based save/load helpers or compressed files, use bevy_fog_of_war::persistence_utils:

use bevy_fog_of_war::persistence::FogOfWarSaveData;
use bevy_fog_of_war::persistence_utils::{load_fog_data, save_fog_data, FileFormat};

# fn example(save_data: &FogOfWarSaveData) -> Result<(), Box<dyn std::error::Error>> {
save_fog_data(save_data, "fog_save.bincode", FileFormat::Bincode)?;
let restored = load_fog_data("fog_save.bincode", None)?;
# let _ = restored;
# Ok(())
# }

Compressed variants such as FileFormat::BincodeZstd or FileFormat::MessagePackLz4 are available when the matching compression features are enabled.

Examples

cargo run --example simple_2d
cargo run --example playground
  • simple_2d: minimal gameplay scene plus save/load demonstration.
  • playground: interactive demo with camera controls, live settings text, reset flow, and persistence.

API docs

License

Licensed under either of:

at your option.

Contributing

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed as above, without any additional terms or conditions.

About

A Bevy Plugin for Fog of War.

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Packages

 
 
 

Contributors