An extension to the bevy_ecs_tilemap, allowing for configurable tilesets, auto tiling, and more

Overview

bevy_ecs_tilemap_tileset

A mouthful, I know. Working on a better name.

An extension to the wonderful bevy_ecs_tilemap crate for Bevy, allowing for configurable tilesets and basic auto tiling capabilities.

Smart tile placement

📋 Features

  • Configure tiles via RON files
  • Generate tilesets that readily work with bevy_ecs_tilemap
  • Basic auto tiling
  • Tile variants
  • Smart tile spawning— automatically inserts the necessary components based on the tile config

Usage

Simply define your tiles in a config file:

(
  name: "My Tile",
  tile: Standard("textures/my_tile.png")
)

And load it in via a system:

use bevy::prelude::*;
use bevy_ecs_tilemap_tileset::prelude::*;

fn load_tiles(mut writer: EventWriter<TilesetLoadEvent>) {
	writer.send(
    TilesetLoadRequest::named(
    	"My Awesome Tileset", 
    	vec![TilesetDirs::from_dir("tiles")],
  	)
    .into()
  );
}

Then access the generated tileset from anywhere:

fn my_system(tilesets: Res<Tilesets>, /* other system params */) {
  
  // ...
  
  if let Some(tileset) = tilesets.get_by_name("My Awesome Tileset") {
    tileset.place_tile(
      "My Tile",
      position,
      map_id,
      layer_id,
      &mut commands,
      &mut map_query,
		);
  }
  
  // ...
  
}

Tile Types

Currently there are four main tile types:

🖼 Standard

Defines a basic tile.

// my-tile.ron

(
  name: "My Tile",
  tile: Standard("textures/my_tile.png")
)

🎞️ Animated

Defines an animated tile that can be generated with the GPUAnimated component from bevy_ecs_tilemap.

// my-animated-tile.ron

(
  name: "My Animated Tile",
  tile: Animated((
    speed: 2.25,
    frames: [
      "textures/animated-001.png",
      "textures/animated-002.png",
      "textures/animated-003.png",
    ]
  ))
)

🎲 Variant

Defines a tile that has a set of possible variants. A random variant is chosen at random when placed. These variants can either be Standard or Animated.

// my-variant-tile.ron

(
  name: "My Crazy Random Tile",
  tile: Variant([
    (
      weight: 1.0,
      tile: Standard("textures/variant-standard-001.png")
    ),
    (
      // Default weight: 1.0
      tile: Standard("textures/variant-standard-002.png")
    ),
    (
      weight: 0.0001, // Wow that's rare!
      tile: Animated((
      	// Default speed: 1.0
        frames: [
          "textures/variant-animated-001.png",
          "textures/variant-animated-002.png",
          "textures/variant-animated-003.png",
        ]
      ))
    )
  ])
)

🧠 Auto

Defines a tile that automatically chooses its active tile based on its neighbors. This behavior can be controlled with rules. These sub-tiles are themselves Variant tiles.

// my-auto-tile.ron

#![enable(implicit_some)]

(
  name: "My Auto Tile",
  tile: Auto([
    (
      rule: (
        north: true,
        east: false,
        west: true,
      ),
      variants: [
        (
          tile: Standard("textures/n_w-e-001.png")
        ),
        (
          weight: 2.0, 
          tile: Standard("textures/n_w-e-002.png")
        )
      ]
    ),
    (
      rule: (
        // Also supports short notation
        n: false,
        s: false,
        // And ordinal directions
        south_west: true,
        nw: false
      ),
      variants: [
        (
          tile: Standard("textures/sw-n_s_nw.png")
        )
      ]
    ),
  ])
)

Auto tiling

🌱 Areas of Growth

There are some things this crate could do better in. Here's a list of potential areas to grow:

  • Tileset
    • Config files ★
  • Auto Tile
    • Mirror/Rotation (designate a rule to be mirrored or rotated)
  • Loading
    • Load configs as assets (to allow for semi-hot reloading)

As well as just an overall improved and cleaner API.

ℹ️ About

This crate was made to serve my purposes for my own tile-based games. I really liked bevy_ecs_tilemap but wanted to extend it in a way that might not be a good fit for that crate internally (i.e. muddy their API and create bloat). This is not a perfect library by any means but it gets the job done as best it can— at least for my purposes.

Publishing

As for publishing, I'm hesitant to publish this as its own crate for a few reasons:

  • The idea of this being an extension to an extension of Bevy sounds messy
    • It may cause confusion in the community for those using bevy_ecs_tilemap
    • It limits users to this crate's version of bevy_ecs_tilemap (more-or-less)
  • The API needs a lot of improvement
    • Requesting and listening for the load to complete feels a bit clunky (this should be less of a hassle when tilset config files are added)
    • Removing auto tiles requires placing the logic in a specific SystemStage and sending out the RemoveAutoTileEvent event (I really hate this but I'm not sure how to resolve it)
  • Auto tiling itself can be slow for large amounts of tiles
    • In release, placing a single tile takes around 25–85µs (depending on the number of neighbors)
    • But updating a large amount can take much longer:
      • 100x100 : ~42ms
      • 500x500 : ~1.15s
      • 1000x1000 : ~4.9s
  • I can't think of a good name for it :(

However, I'm open to publishing this if people think it's a good idea to do so. If you think it should be published, feel free to open an issue regarding this!

📲 Installation

While I decide on publishing this crate or not, you can still install it to use or try out via git:

[dependencies]
bevy_ecs_tilemap_tileset = { git = "https://github.com/MrGVSV/bevy_ecs_tilemap_tileset", tag = "v0.1.0"}
Comments
  • Update to Bevy 0.9

    Update to Bevy 0.9

    Quick and simple update to Bevy 0.9. Depends on the bevy_tile_atlas 0.5 PR I opened in your other repo. (I tested it using a git tag in cargo.toml) Adds Resource derives, uses spawn instead of spawn_bundle and uses handle.id() instead of accessing the field directly.

    opened by Dauthdaert 0
  • Make `new` methods const on `TileId` and `PartialTileId`

    Make `new` methods const on `TileId` and `PartialTileId`

    The main reason for this is to allow IDs be declared as constants without having to write out the full struct:

    const MY_ID: TileId = TileId {
      group_id: 1,
      tileset_id: 5,
      auto_index: None,
      variant_index: None,
    };
    

    Which can be dangerous since auto_index and variant_index only exist with certain features enabled. It's also overkill if you just need to define the tile group and tileset. In which case, this new method is much simpler:

    const MY_ID: TileId = TileId::new(1, 5);
    
    enhancement 
    opened by MrGVSV 0
  • `bevy_tileset_map`

    `bevy_tileset_map`

    Preparation for a standalone release of the current sub-crate bevy_tileset_map (formerly bevy_ecs_tilemap_tileset).

    Includes major changes to the subcrate, such as the TilePlacer system param.

    opened by MrGVSV 0
  • Add Serialization/Deserialization

    Add Serialization/Deserialization

    Adds serialization and deserialization support to bevy_ecs_tilemap_tileset. This is done through the new TilemapSerializer system parameter.

    Saving

    /// Assumes bevy_ecs_tilemap has already been properly setup to have tiles read from it
    fn save_maps(serializer: TilemapSerializer) {
      // This saves all currently generated maps
      let maps = serializer.save_maps();
      
      // Write to disk using something like serde_json...
    }
    

    Loading

    /// Assumes bevy_ecs_tilemap has already been properly setup to have tiles placed into it
    fn load_maps(mut serializer: TilemapSerializer) {
      let path = FileAssetIo::get_root_path().join("assets/map.json");
      let data = std::fs::read_to_string(path).unwrap();
      let maps = serde_json::from_str::<SerializableTilemap>(&data).unwrap();
    
      serializer.load_maps(&maps);
    }
    
    opened by MrGVSV 0
  • Abstracted Auto Tiling

    Abstracted Auto Tiling

    This PR is built atop #2 and updates bevy_ecs_tilemap_tileset to support the Bevy 0.6 release.

    Auto Tiling

    Additionally, it abstracts the auto tiling functionality into bevy_tileset_core so that it may be implemented in a more generic way.

    This is done through the AutoTiler. This struct takes in data related to auto tiles and generates a list of requests that the implementor should process.

    The only thing an implementor needs to do to enable this default auto tiling is implement these three traits:

    • TileCoords - Represents a tile's coordinates
    • AutoTile - Represents the actual auto tile
    • AutoTilemap - Represents the tilemap (but only in regards to auto-tiles)

    With these traits implemented, the AutoTiler can be used alongside a Tileset to produce the auto tile output.

    opened by MrGVSV 0
  • Update to Bevy 0.6

    Update to Bevy 0.6

    Update bevy_tileset_tiles, bevy_tileset_core, and bevy_tileset to support the Bevy 0.6 release.

    Updates to bevy_ecs_tilemap_tileset will come in a separate PR as I also want to extract Auto Tiling and put most of the logic in the core crate.

    opened by MrGVSV 0
  • Re-structured project and added Tileset config files

    Re-structured project and added Tileset config files

    ✨ What's New ✨

    TL;DR

    • 📝 Tilesets can now be defined in RON files
      • Tilesets are now considered Assets, and can be loaded via the AssetServer
    • 🧹 Cleaned up API
      • Removed the awkward event loading system
      • Exposed more internal code for finer control
      • Split the code into separate crates
    • 🔐 Added the variants and auto-tile feature

    Project Structure

    Additionally, this project has now been split into multiple crates. All things related to tiles have been moved to bevy_tileset_tiles, the actual tileset logic has been put in bevy_tileset_core, and the integration with bevy_ecs_tilemap has been moved to bevy_ecs_tilemap_tileset.

    This was done to split the code into contained boundaries so they would be easier to maintain and generalize. bevy_tileset_tiles was best suited for its own crate. It can now be used on its own apart from the rest of this project if anyone ever wanted to.

    API Changes

    Some more details on some of the major API changes (though most if has changed one way or another).

    For loading tilesets, we've gone from this:

    fn load_tiles(mut writer: EventWriter<TilesetLoadEvent>) {
      writer.send(
        TilesetLoadRequest::named(
          "My Tileset",
          vec![TilesetDirs::from_dir("tiles")]
        ).into()
      );
    }
    

    to this:

    struct MyTileset(Handle<Tileset>);
    
    fn load_tileset(mut my_tileset: ResMut<MyTileset>, asset_server: Res<AssetServer>) {
      my_tileset.0 = asset_server.load("my_tileset.ron");
    }
    

    In the first snippet, besides being slightly more verbose, we had to provide a set of folders to load tiles from. This forces us to keep all of our tile definition files in the same folders. It also means we can't have any other RON files in those folders so they're not accidentally loaded (I think it actually just fails and moves to the next file, but still not ideal).

    In the second snippet, we move all of that logic and configuration to the actual tileset file, which looks like this:

    (
      name: Some("My Tileset"),
      id: 0,
      tiles: {
        0: "../tiles/dirt.ron",
        1: "../tiles/grass.ron",
        2: "../tiles/wall.ron",
      }
    )
    

    Here, we give the tileset an optional name (a UUID string is generated otherwise), a unique ID, and a collection of tiles. Tiles are mapped by an associated ID key, allowing tiles to be added or removed without drastically affecting possible serialization.

    Note: Serialization will probably be up to the implementation, but doing this ensures we make it easier to save and load tilemaps.

    And while this is good, we're still sort of forced to use whatever the config file gives us, right? Well, this is why some of the previously private internals have been exposed as part of the public API.

    This namely includes the TileHandle struct and its ilk. This means you can craft your own tiles at runtime:

    let tile = TileHandle::new_standard("My Tile", texture_handle);
    

    which can then be used to create a RawTileset via the existing TilesetBuilder. This RawTileset has nearly all the same methods as a regular Tileset but is not an Asset and has direct access to its TextureAtlas rather than just a handle.

    Exposing this and making it easier to use, should allow users to more readily add, remove, and create tiles based on their own runtime logic.

    Features

    To help clean things up even more and to provide users with more control over what they actually need, a couple of features have been introduced.

    The variants feature unlocks all the code related to Variant tiles.

    The auto-tile feature unlocks all the code related to Auto tiles and also enables the variants feature.

    If either feature is disabled, everything else will work as normal. Even loading tilesets that include tiles of disabled features will continue to load just fine— those tiles will simply be missing from the loaded Tileset.

    🔮 Next Steps

    Overall, I'm much happier with this code and will likely publish it. However, I will probably hold off on publishing the bevy_ecs_tilemap integration as I need to polish it up a bit more and I might also try to make a PR for it in its actual project.

    Additionally, with Bevy 0.6 around the corner, a lot needs to be updated. So that will eventually need to be taken care of as well.

    enhancement 
    opened by MrGVSV 0
Releases(v0.6.0)
  • v0.6.0(Nov 14, 2022)

    What's Changed

    • Update to Bevy 0.9 by @Dauthdaert in https://github.com/MrGVSV/bevy_tileset/pull/9

    New Contributors

    • @Dauthdaert made their first contribution in https://github.com/MrGVSV/bevy_tileset/pull/9

    Full Changelog: https://github.com/MrGVSV/bevy_tileset/compare/v0.5.0...v0.6.0

    Source code(tar.gz)
    Source code(zip)
  • v0.5.0(Sep 26, 2022)

    What's Changed

    • Add support for Bevy 0.8 by @eLVas in https://github.com/MrGVSV/bevy_tileset/pull/8

    New Contributors

    • @eLVas made their first contribution in https://github.com/MrGVSV/bevy_tileset/pull/8

    Full Changelog: https://github.com/MrGVSV/bevy_tileset/compare/v0.4.0...v0.5.0

    Source code(tar.gz)
    Source code(zip)
  • v0.4.0(Apr 16, 2022)

    What's Changed

    • Make new methods const on TileId and PartialTileId by @MrGVSV in https://github.com/MrGVSV/bevy_tileset/pull/6
    • Update to Bevy 0.7 by @MrGVSV in https://github.com/MrGVSV/bevy_tileset/pull/7

    Full Changelog: https://github.com/MrGVSV/bevy_tileset/compare/v0.3.1...v0.4.0

    Source code(tar.gz)
    Source code(zip)
  • v0.3.1(Feb 17, 2022)

    What's Changed

    • Removed bevy_tileset_map (formerly bevy_ecs_tilemap_tileset)
    • Tilesets system param now uses Res instead of ResMut

    Full Changelog: https://github.com/MrGVSV/bevy_tileset/compare/v0.3.0...v0.3.1

    Source code(tar.gz)
    Source code(zip)
  • v0.3.0(Jan 17, 2022)

    What's Changed

    • Update to Bevy 0.6 by @MrGVSV in https://github.com/MrGVSV/bevy_tileset/pull/2
    • Abstracted Auto Tiling by @MrGVSV in https://github.com/MrGVSV/bevy_tileset/pull/3
    • Add Serialization/Deserialization by @MrGVSV in https://github.com/MrGVSV/bevy_tileset/pull/4

    Full Changelog: https://github.com/MrGVSV/bevy_tileset/compare/v0.2.0...v0.3.0

    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Jan 6, 2022)

    What's Changed

    • Re-structured project and added Tileset config files by @MrGVSV in https://github.com/MrGVSV/bevy_tileset/pull/1

    New Contributors

    • @MrGVSV made their first contribution in https://github.com/MrGVSV/bevy_tileset/pull/1

    Full Changelog: https://github.com/MrGVSV/bevy_tileset/compare/v0.1.0...v0.2.0

    Source code(tar.gz)
    Source code(zip)
  • v0.1.0(Nov 28, 2021)

Owner
null
A visual novel engine that draws inspiration from RenPy and is meant to be a more performant replacement with feature parity.

VN Engine A visual novel engine that draws inspiration from RenPy and is meant to be a more performant replacement with feature parity. The engine is

Alexandros Panagiotakis 2 Sep 9, 2022
A visual novel engine that draws inspiration from RenPy and is meant to be a more performant replacement with feature parity.

VN Engine A visual novel engine that draws inspiration from RenPy and is meant to be a more performant replacement with feature parity. The engine is

Alexandros Panagiotakis 2 Sep 9, 2022
This tool allows you to open one or more notebooks in Visual Studio and go hog wild exploring your systems in Bevy.

Bevyrly Bevy is rly useful, but requires some hygiene! Pronounced as /ˈbɛvə(ɹ)li/, derives from Old English, combining befer ("beaver") and leah ("cle

null 4 Feb 28, 2024
🤹‍ 2D sprite rendering extension for the specs ECS system

specs-blit 2D sprite rendering extension for the Specs ECS system. All sprites are loaded onto a big array on the heap. Example // Setup the specs wor

Thomas Versteeg 8 Aug 14, 2022
A simple extension for `bevy-editor-pls` to support tilemap editing right inside the bevy app.

What is this This is a simple tilemap editor plugin, that hooks right into bevy_editor_pls to work with bevy_ecs_tilemap. It works completely within i

null 3 May 8, 2023
A tilemap rendering crate for bevy which is more ECS friendly.

bevy_ecs_tilemap A tilemap rendering plugin for bevy which is more ECS friendly by having an entity per tile. Features A tile per entity Fast renderin

John 414 Dec 30, 2022
Just when you thought Bevy couldn't get more ergonomic, Bvy shows up to change the game.

Just when you thought Bevy couldn't get more ergonomic, Bvy shows up to change the game. Is this a joke? You decide. Does it work? You can bet your As

Carter Anderson 40 Oct 28, 2022
Victorem - easy UDP game server and client framework for creating simple 2D and 3D online game prototype in Rust.

Victorem Easy UDP game server and client framework for creating simple 2D and 3D online game prototype in Rust. Example Cargo.toml [dependencies] vict

Victor Winbringer 27 Jan 7, 2023
Abstreet - Transportation planning and traffic simulation software for creating cities friendlier to walking, biking, and public transit

A/B Street Ever been stuck in traffic on a bus, wondering why is there legal street parking instead of a dedicated bus lane? A/B Street is a project t

A/B Street 6.8k Jan 9, 2023
"putzen" is German and means cleaning. It helps keeping your disk clean of build and dependency artifacts safely.

Putzen "putzen" is German and means cleaning. It helps keeping your disk clean of build and dependency artifacts safely. About In short, putzen solves

Sven Assmann 2 Jul 4, 2022
Plugins and helpful methods for using sepax2d with Bevy for 2d overlap detection and collision resolution.

bevy_sepax2d Plugins and helpful methods for using sepax2d with Bevy for 2d overlap detection and collision resolution. Compatible Versions bevy bevy_

null 7 Nov 14, 2022
This is the core library with the full abstraction and implementation of the Minecraft protocol and logic. (Currently WIP)

MineRust (WIP) This is the core library with the full abstraction and implementation of the Minecraft protocol and logic. This project is currently WI

MineRust Project Suite 2 Nov 20, 2022
A Rust wrapper and bindings of Allegro 5 game programming library

RustAllegro A thin Rust wrapper of Allegro 5. Game loop example extern crate allegro; extern crate allegro_font; use allegro::*; use allegro_font::*;

null 80 Dec 31, 2022
RTS game/engine in Rust and WebGPU

What is this? A real time strategy game/engine written with Rust and WebGPU. Eventually it will be able to run in a web browser thanks to WebGPU. This

Thomas SIMON 258 Dec 25, 2022
A curated list of wgpu code and resources.

Awesome wgpu A curated list of wgpu code and resources. PRs welcome. About wgpu https://github.com/gfx-rs/wgpu-rs matrix chat https://matrix.to/#/#wgp

Roman Frołow 283 Jan 3, 2023
grr and rust-gpu pbr rendering

grr-gltf Barebone gltf viewer using grr and rust-gpu. Currently only supports a single gltf model! Assets These files need to be downloaded and placed

Markus Siglreithmaier 28 Dec 2, 2022
A no-frills Tetris implementation written in Rust with the Piston game engine, and Rodio for music.

rustris A no-frills Tetris implementation written in Rust with the Piston game engine, and Rodio for music. (C) 2020 Ben Cantrick. This code is distri

Ben Cantrick 17 Aug 18, 2022
Pixel-Perfect, 2D Renderer for Bevy that Seamlessly Targets Desktop and Web

bevy_retro ( Screenshot of Bounty Bros. game made with Bevy Retro and Skip'n Go ) Bevy Retro is a 2D, pixel-perfect renderer for Bevy that can target

Katharos Technology 224 Dec 23, 2022
Text Renderer written in Rust using HarfBuzz for shaping, FreeType for rasterization and OpenGL for rendering.

Provok Text Renderer written in Rust using HarfBuzz for shaping, FreeType for rasterization and OpenGL for rendering. Input Provok is fed with a JSON

Ossama Hjaji 67 Dec 10, 2022