stararawn / bevy_ecs_tilemap Goto Github PK
View Code? Open in Web Editor NEWA tilemap rendering crate for bevy which is more ECS friendly.
License: MIT License
A tilemap rendering crate for bevy which is more ECS friendly.
License: MIT License
We should have despawn_layer
and similar functions be on <T1,T2> where T1:Into<u16>,T2:Into<u16>
and not on <T:Into<u16>>
, I expect the types for the layer_id
and the map_id
to be different ones and the API can not accommodate that currently.
This will make it easier for users to clearly understand the effects of changes to their code when experimenting with the examples.
I've imported a iso map using Tiled and was trying to center the map but I would need the map dimensions for that.
Since I might use a lot of different maps and not always know its size it would be nice to have a method like .dimensions()
.
Is there any method like this available? If not I think it would be a nice simple feature.
Edit: I tried to get the asset from the Handle<TiledMap>
but asset is usually not loaded and working with references to the TiledMapBundle is a bit tricky.
Hello, I'd like to use your library with a map I made using Tiled. In Tiled I have added collision shapes to some of the tiles, they are stored as object
s in an objectgroup
on a tile
in the tmx
file in the following hierarchy:
<map ...>
<tileset ...>
...
<tile id="1">
<objectgroup ...>
<object ... />
</objectgroup>
</tile>
</tileset>
</map>
I saw that you're using the tiled library when the tiled_map
feature is enabled, the data structures in the tiled
Rust library seem to map pretty directly to the XML in the tmx
file so the hierarchy is similar. Given this, I had a couple of questions:
tiled
library following map creation?const TILE_HEIGHT: f32 = 16.;
const TILE_WIDTH: f32 = 16.;
fn add_collision_to_tiles(
mut query: Query<(Entity, &mut Tile, &UVec2)>
) {
// use `tiled` library to parse original map file
let tiled_info = tiled::parse(...);
// iterate over tiles in map at startup and add collision information
for (entity, mut tile, position) in query.iter_mut() {
... // add ColliderBundle and RigidBodyBundle to entity
}
}
Where ColliderBundle
and RigidBodyBundle
are from bevy_rapier2d.
The ldtk tilemap texture index code uses the src
field to calculate the tilemap index based on the pixel dimensions. There seems to be a bug in the current implementation that offsets the index by 1 for the first row, and 2 for every row after that in the tilemap.
Here's an image showing the current behavior:
There seems to be an index for the tilemap in the t
field in the same struct. Changing the above code to access the t
field instead results in the following, seemingly correct output for the tilemap.
layer_builder.set_tile(
pos,
Tile {
texture_index: tile.t as u16,
..Default::default()
}.into()
).unwrap();
I don't know enough about tdlk to know if this is correct, but it seemed useful to file an issue for
Currently MapSettings::new()
is locked to the TilemapMeshType::Square
map type.
It would be nice to have a MapSettings::new_with_map_type()
that would accept the different TilemapMeshType
options.
The following map makes the library crash with an out of bounds error failing_map.zip
Also, it looks like the y calculations when dealing with ldtk maps are off by 1 unit
I've had a lot of people ask me very similar questions along the lines of:
How can I access tiled/ldtk data on load.
I don't mind answering those questions, but I don't think bevy_ecs_tilemap should support things like:
Which makes me think that the ldtk/tiled features should be removed in favor of using clearly defined examples.
bevy_ecs_tilemap
.bevy_ecs_tilemap
into a collision library. I would like to avoid that at all costs.I want to reach out to the community first before I go ahead and make this change. Anyone who wants to voice any concerns/comments feel free!
Texture size is actually 96 x 16, but is listed as 96 x 256.
This silently works for the monochrome tiles, but changes made do not show up properly.
See also: #87 ;)
I've just started learning rust, so sorry in advance if my explanation is not too helpful. I am running into an issue when adopting or running your examples.
`
cargo run --release --example iso
Finished release [optimized] target(s) in 0.37s
Running "/tmp/bevy_ecs_tilemap/target/release/examples/iso"
[2021-05-02T14:50:04Z WARN gfx_backend_vulkan] Skipping memory type with unknown flags DEVICE_LOCAL | DEVICE_COHERENT_AMD | DEVICE_UNCACHED_AMD
[2021-05-02T14:50:04Z WARN gfx_backend_vulkan] Skipping memory type with unknown flags HOST_VISIBLE | HOST_COHERENT | DEVICE_COHERENT_AMD | DEVICE_UNCACHED_AMD
[2021-05-02T14:50:04Z WARN gfx_backend_vulkan] Skipping memory type with unknown flags DEVICE_LOCAL | HOST_VISIBLE | HOST_COHERENT | DEVICE_COHERENT_AMD | DEVICE_UNCACHED_AMD
[2021-05-02T14:50:04Z WARN gfx_backend_vulkan] Skipping memory type with unknown flags HOST_VISIBLE | HOST_COHERENT | HOST_CACHED | DEVICE_COHERENT_AMD | DEVICE_UNCACHED_AMD
[2021-05-02T14:50:04Z INFO winit::platform_impl::platform::x11::window] Guessed window scale factor: 1
[2021-05-02T14:50:04Z INFO bevy_ecs_tilemap::chunk] Re-meshing chunk at: MapVec2 { x: 0, y: 0 } layer id of: 0
[2021-05-02T14:50:04Z INFO bevy_ecs_tilemap::chunk] Re-meshing chunk at: MapVec2 { x: 0, y: 1 } layer id of: 0
[2021-05-02T14:50:04Z INFO bevy_ecs_tilemap::chunk] Re-meshing chunk at: MapVec2 { x: 1, y: 0 } layer id of: 0
[2021-05-02T14:50:04Z INFO bevy_ecs_tilemap::chunk] Re-meshing chunk at: MapVec2 { x: 1, y: 1 } layer id of: 0
[2021-05-02T14:50:04Z INFO bevy_ecs_tilemap::chunk] Re-meshing chunk at: MapVec2 { x: 1, y: 1 } layer id of: 1
[2021-05-02T14:50:04Z INFO bevy_ecs_tilemap::chunk] Re-meshing chunk at: MapVec2 { x: 1, y: 0 } layer id of: 1
[2021-05-02T14:50:04Z INFO bevy_ecs_tilemap::chunk] Re-meshing chunk at: MapVec2 { x: 0, y: 0 } layer id of: 1
[2021-05-02T14:50:04Z INFO bevy_ecs_tilemap::chunk] Re-meshing chunk at: MapVec2 { x: 0, y: 1 } layer id of: 1
[2021-05-02T14:50:04Z INFO bevy_ecs_tilemap::chunk] Re-meshing chunk at: MapVec2 { x: 1, y: 0 } layer id of: 2
[2021-05-02T14:50:04Z INFO bevy_ecs_tilemap::chunk] Re-meshing chunk at: MapVec2 { x: 0, y: 1 } layer id of: 2
[2021-05-02T14:50:04Z INFO bevy_ecs_tilemap::chunk] Re-meshing chunk at: MapVec2 { x: 0, y: 0 } layer id of: 2
[2021-05-02T14:50:04Z INFO bevy_ecs_tilemap::chunk] Re-meshing chunk at: MapVec2 { x: 1, y: 1 } layer id of: 2
thread 'main' panicked at 'attempt to create unaligned or null slice', /usr/lib/rust/1.51.0/lib/rustlib/src/rust/library/core/src/slice/raw.rs:90:5
note: run with RUST_BACKTRACE=1
environment variable to display a backtrace
Segmentation fault
`
This happens with Rust 1.51.0 (no nightly) and line map.build(&mut commands, &mut meshes, material_handle.clone(), map_entity, true);
seems to be the offending line.
That is as far as my Rust debugging skills go at the moment though. Any idea what might be the issue here?
I tried using ? to return from a function that returns an anyhow::Result<()> but it couldn't convert the Result because Error is not implemented.
(Link)
The docs mention that "The boolean is for visibility". What boolean is being referred to? The random_map
example also seems to reference a boolean that isn't there.
I am trying to use this lib but I could not find a way to set my TextureAtlasHandler with my textures in it. Is it possible?
[edit]
I found that the Tile has a property for texture_index but could not find any property to set the atlas.
/// The texture index in the atlas or array.
pub texture_index: u16,
If you give the tilemap a negative transform, it seems to fail to render anymore chunks at some point (near the transition from negative to positive?).
The screenshot below shows tiles rendering out to roughly 1000px or so on the x-axis, when the code should be generating over 8000px of tiles.
Here is a code sample to demonstrate.
use bevy::prelude::*;
use bevy_ecs_tilemap::prelude::*;
// With a world size of 8 chunks, a chunk size of 64 tiles, and a tile size of 16 pixels,
// we should get a tilemap of 8,192 pixels wide and high. Much larger than the default
// window size of 1280, 720.
const WORLD_CHUNK_SIZE: u32 = 8;
const CHUNK_TILE_SIZE: u32 = 64;
// Code is otherwise identical to examples/map.rs for simplicity's sake.
fn startup(
mut commands: Commands,
asset_server: Res<AssetServer>,
windows: Res<Windows>,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
) {
let window = windows.get_primary().unwrap();
let window_width = window.width();
let window_height = window.height();
commands.spawn_bundle(OrthographicCameraBundle::new_2d());
let texture_handle = asset_server.load("tiles.png");
let material_handle = materials.add(ColorMaterial::texture(texture_handle));
let mut map = Map::new(MapSettings::new(
UVec2::new(WORLD_CHUNK_SIZE, WORLD_CHUNK_SIZE),
UVec2::new(CHUNK_TILE_SIZE, CHUNK_TILE_SIZE),
Vec2::new(16.0, 16.0),
Vec2::new(96.0, 256.0),
0,
));
let map_entity = commands.spawn().id();
map.build(
&mut commands,
&mut meshes,
material_handle,
map_entity,
true,
);
// Set up the origin point of the tilemap to be the bottom-left
// corner of the camera, such that it _should_ fill the entire viewport and more.
// Adding a 5 pixel offset to show that it isn't rendering off the left/bottom
// of the camera.
let origin_x = -(window_width / 2.0) + 5.0;
let origin_y = -(window_height / 2.0) + 5.0;
commands.entity(map_entity).insert_bundle(MapBundle {
map,
transform: Transform::from_xyz(origin_x, origin_y, 0.0),
..Default::default()
});
}
fn main() {
App::build()
.add_plugins(DefaultPlugins)
.add_plugin(TilemapPlugin)
.add_startup_system(startup.system())
.run();
}
Many methods on MapQuery expose a generic, which must impl Into<u16>
.
This is a great pattern, to allow people to use smarter, clearer types rather than passing around magical u16 values for the map and layer. However, the standard use of this (or at least, how I want to use it!) is to implement two enums (or other data types): one for the map, and one for the layer. However the generic type used must be the same in both instances, causing this pattern to create a compile error.
Swapping to two seperate generic types with the same bounds will resolve this problem.
When the Map entity is despawned with .despawn_recursive(), all tile entities belonging to that tilemap continue to exist even though they are no longer visible. As far as I can tell, this is due to the tile entities not being marked as children of the Map entity.
The isometric example only allows for flat tiles at the moment. I have a fix ready for the renderer but am still working on placing the correct tiles. For this I have to look into how the tile atlas works so I can place the correct adjacent tiles. This may make the example a lot more complicated.
After loading an ldtk map, requesting a layer size outputs the wrong value. For example, in a map of size 15x8, the following line:
println!("Layer size is {}", layer.settings.map_size);
Outputs:
Layer size is [1, 1]
I'd say the problem has to do with lines 137 and 138 in ldtk.rs, where the map size is divided unnecessarily.
I had this working in 0.2.0 and it's broken in 0.3.0. I'm not sure if this is a bug or a problem with the way I'm using it. I have a 700px by 700px png that I'm cutting into 140px by 140px tiles and then manually inserting them into the map. When doing so, the tile I'm expecting at texture_index 4 is missing and replaced with the tile from texture_index 5. This happens with every fifth tile, so instead of getting 25 tiles, I only have 20.
fn setup(
mut commands: Commands,
mut materials: ResMut<Assets<ColorMaterial>>,
mut meshes: ResMut<Assets<Mesh>>,
assets: Res<AssetServer>,
) {
commands.spawn_bundle(OrthographicCameraBundle::new_2d());
let map = assets.load("maps/5x5.jpg");
let map_material = materials.add(map.into());
let tile_map_entity = commands.spawn().id();
let tile_map_settings = MapSettings::new(
UVec2::new(5, 5),
UVec2::new(1, 1),
Vec2::new(140., 140.),
Vec2::new(700., 700.),
0
);
let mut tile_map = Map::new(tile_map_settings);
tile_map.build(
&mut commands,
&mut meshes,
map_material,
tile_map_entity,
false,
);
let _ = tile_map.add_tile(&mut commands, UVec2::new(0, 4), Tile { texture_index: 0, ..Default::default() }, true);
let _ = tile_map.add_tile(&mut commands, UVec2::new(1, 4), Tile { texture_index: 1, ..Default::default() }, true);
let _ = tile_map.add_tile(&mut commands, UVec2::new(2, 4), Tile { texture_index: 2, ..Default::default() }, true);
let _ = tile_map.add_tile(&mut commands, UVec2::new(3, 4), Tile { texture_index: 3, ..Default::default() }, true);
let _e = tile_map.add_tile(&mut commands, UVec2::new(4, 4), Tile { texture_index: 4, ..Default::default() }, true);
commands.entity(tile_map_entity).insert_bundle(MapBundle {
map: tile_map,
..Default::default()
});
}
Initializing LayerSettings
with the new
method is not very explicit or type safe, and map_id
and layer_id
types use unclear types.
New users will see
LayerSettings::new(
UVec2::new(2, 2),
UVec2::new(8, 8),
Vec2::new(16.0, 16.0),
Vec2::new(96.0, 256.0),
),
in https://github.com/StarArawn/bevy_ecs_tilemap/blob/main/examples/map.rs and be at a loss for what the magic numbers do.
There are a few possible improvements that immediately come to mind:
map_size
etc.impl Into<u16>
to increase clarity and safety.Currently Map
isn't Clone
(and I don't think it should be, or at least not for this issue's purposes)
and Map::new()
currently takes:
size,
chunk_size,
tile_size,
texture_size,
(layer_id isn't relevant to this issue)
My suggestion would be to create a MapSettings
struct that is Clone
/Copy
:
///The settings for tilemap layers
#[derive(Debug, Clone, Copy)]
pub struct MapSettings {
pub map_size: MapVec2,
pub chunk_size: MapVec2,
pub tile_size: Vec2,
pub texture_size: Vec2,
}
To enable making similar maps with the same settings more convenient(for example if you need layers with the same settings). The current impl kind of forces the user to create functions to reduce boilerplate which I think should be avoided)
This also enables storing these structs as/in resources for reusability
Map::new()
would then take MapSettings
instead of the 4 different values
*I don't mean you need to actually store this inside of Map
instead of the current configuration.
you can and maybe should keep Map
as is and only change Map::new()
to make it more convenient for users. I'm not sure.. it might be nice to copy the settings of a Map
if it's possible, idk if there'd be uses for that, maybe for bevy_tiled
maps..?
like the title says, if all goes well and we only use .spawn_bundle()
and nothing else per tile entity In new_and_build()
, we should have very good perf, but if and when BundleBuilder
(bevyengine/bevy#2157 (comment)) would be added,
if it plays well with spawn_batch()
we should get even better perf because that would mean only one memory allocation for entities per layer if I understand correctly.
While working on a tile-coordinates-from-mouse-click utility, @plof27 and I noticed that coordinates of the hex tiles become progressively more inaccurate the farther from the origin you get. You can see the utility function we used for conversions at the link.
We noticed this using a point-up, Hextype::Row
layout. It works perfectly for x, but gets progressively worse on the y-axis as you get further from the origin. I suspect this is a layout bug as a result; particularly as it was still an issue using an alternate pixel-based renderer.
Hello,
First of all thanks for this great plugin. I was thinking of using it for a multiplayer game in combination with the Tiled support that you recently added. One prerequisite for this is that the plugin should work in headless mode (i.e., without all the graphical plugins). I was wondering whether that's something that you envisioned / considered, and/or if you think this belongs elsewhere.
I like the idea of having a Tile Component in the ECS framework, and I can use it to attach some game logic on it. For multiplayer, the authorative node / server (depending on the terminology you use :) ) should be able to simulate the game (headless). So basically all the infrastructure of loading from a Tiled file + the ECS infrastructure that this crate provides is very useful, however because it links directly with the rendering, headless won't work. Specifically, this is the error I get when I don't load in the default bevy plugins in combination with this plugin:
thread 'main' panicked at 'resource does not exist: bevy_asset::assets::Assets<bevy_render::pipeline::pipeline::PipelineDescriptor>', /home/mfiers/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.5.0/src/world/mod.rs:674:32
Which is to be expected. The way I solved this in my game prototype was to fully split logic from rendering into two separate plugins - which seems to be a good practice in game development anyways. The headless node only needs to run the logic plugin, whereas the client runs both logic + rendering plugins. (the rendering plugin then has a system that extends all entities and attaches the necessary sprites/texture components onto all entities that don't have one yet).
I'm curious to hear your thoughts about this! Let me know if this discussion/issue belongs in the right place here as a github issue.
Currently I am implementing custom logic to load entities from ldtk. I am going to try adding this generically in my fork.
the package bevy_play
depends on bevy_ecs_tilemap
, with features: ldtk
but bevy_ecs_tilemap
does not have these features.
[package]
name = "bevy_play"
version = "0.1.0"
edition = "2018"
[dependencies]
bevy = { version = "0.5"}
bevy_ecs_tilemap = {version = "0.4.0", features = ["ldtk"]}
Existing methods assume 8 compass-direction neighbors.
Relatedly, some use cases may instead only want to find the four NESW neighbors instead.
There seems to be a delay on tiles getting updated, especially noticeable when the framerate is low.
Here's a screen recording of my test project showing it by having the same source data being rendered by bevy_ecs_tilemap and bevy_tilemap side by side. Bevy_ecs_tilemap is the one on the left. I've added a "slowdown" system that intentionally tanks the framerate down to about 8fps to make the delay noticeable, but I'm also seeing this in my actual game when running it in debug mode.
As you can see here, bevy_ecs_tilemap is consistently lagging behind with a small but noticeable delay, and it also seems to skip updates when moving the cursor fast. (tiles seemingly updating 2 at a time on the left)
I wasn't able to reproduce this at all with just a single tile, so it seems to be dependent on the number of tiles being rendered as well.
Here's the code to the test project reproducing it.
Controls are WASD to move and update tile at the new position, X to switch sprite index.
bevy_ecs_tilemap_frame_delay_repro.zip
Having a chunk_size or a map_size that isn't both square and a power of 2 creates many empty entities.
Eg.
let layer_settings = LayerSettings::new(
UVec2::new(1, 1),
UVec2::new(4, 2),
Vec2::new(16.0, 16.0),
Vec2::new(96.0, 256.0),
);
will create 8 empty entities (I assume for padding), while
let layer_settings = LayerSettings::new(
UVec2::new(1, 1),
UVec2::new(4, 4),
Vec2::new(16.0, 16.0),
Vec2::new(96.0, 256.0),
);
will not create any empty entities.
I don't really care about the extra memory usage, but it makes the WorldInspectorPlugin from https://github.com/jakobhellermann/bevy-inspector-egui unusable on mid-large maps that aren't perfect power of 2 squares because it pollutes the inspector with a ton of garbage empty entities, and as far as I know you also can't filter them out using a query.
eg. I use .add_plugin(WorldInspectorPlugin::new().filter::<Without<Tile>>())
due to performance issues with huge lists of entities in bevy-inspector-egui, but due to the empty entities I'm left with a ton of entities I can't filter out without making maps bigger and/or non rectangular so they're all perfect power of 2 squares.
Setting the texture size manually (on a per-layer basis) is somewhat error-prone, and silently results in strange errors and aberrations if the user gets it wrong.
Ideally, this would be detected automatically based on the tile assets chosen (and the material handle passed in).
It seems like whenever a tile is added using map.add_tile() to a position that did not already have a tile, the new tile is not rendered until another .add_tile() is performed on a position that already contains a tile.
This can be worked around by simply calling .add_tile() with the exact same parameters twice in a row, but I assume this is not intentional.
This is an important perf and usability optimization when interfacing with external arrays (which are always indexed by usize
slices).
Currently, you must repeatedly waste operations performing this conversion and littering the code base with as usize
.
When attempting to load maps that are larger than 512px in any dimensions the program returns a panic.
thread 'main' panicked at 'called
Result::unwrap()on an
Errvalue: OutOfBounds', /home/kl/.cargo/git/checkouts/bevy_ecs_tilemap-8c720d5970222b21/2a60b2a/src/ldtk.rs:177:27 note: run with
RUST_BACKTRACE=1environment variable to display a backtrace Segmentation fault (core dumped)
I have tried to see what is exactly wrong, but cant seem to figure it out.
I've been working on updating the asefile crate to support Aseprite's Tilemap features. Ultimately, I'd like to have an asset pipeline for tiles directly from Aseprite into bevy_ecs_tilemap.
I'd be happy to contribute work on this as a feature flag to this library. Otherwise, I can make a separate crate.
When you attempt to call get_tile_entity with an index that is out of bounds, it panics instead of returning MapTileError. (eg. on a 12x12 tile map a tile_position of (17, 0) will cause it to panic. (16, 0) will also panic, but (15, 0) won't panic).
It would be nice to have mouse events translated to tiles. At the minimum, a helper function which takes mouse coordinates and returns a tile. However, even better, a system which:
I'm not sure how -- or if at all -- this should interact with non-tile sprites or other UI elements. I can image cases where it'd be nice to at least know that a click is "obstructed" by an object which is above the map.
I've tried to importing a tmx from Tiled where the map his 16x8 but with a tileset of 16x16 to give it a isometric look.
The problem is that bevy is rendering the tiles with 16px of height between them, maybe because the of tile dimensions idk :P.
Really like the project btw.
It would be really useful to be able to select Isometric Staggered or Isometric Diamond (like the current iso example) when creating a map.
For reference:
Isometric tilemap types
Sorry if this is a noob question.
I was just researching about the best way to traverse the tiles using aStar algorithm. In the past I just kept the grid data in an array or hashmap, but now with the entity system, whats the best resource non intensive way to do this?
here: https://github.com/StarArawn/bevy_ecs_tilemap/blob/main/src/layer_builder.rs#L69
the 'static
bound on F
is unnecessary(the bench example still works and all).
i removed it on a branch in my fork of the library, but the branch is after this pr: #81 and i'm not sure how that would work with git..
After creating a tilemap, I only see one chunk rendering when I am expecting four chunks.
fn setup_tilemap(
// -- snip --
) {
// 2 chunks wide, 2 chunks tall. Expecting 4 chunks total.
let map_size = UVec2::new(2, 2);
// Each chunk is 16 tiles wide and 9 tiles tall.
let chunk_size = UVec2::new(16, 9);
let layer_settings = LayerSettings::new(
map_size,
chunk_size,
Vec2::new(16., 16.),
Vec2::new(192.0, 16.0),
);
// -- snip --
}
Ingame this only renders one 16x9 chunk:
Here is a gist with the complete tilemap setup function.
Let me know what other information I can provide.
Would it make sense to make a generic map loader trait and implement for example the loading of Tiled maps similar to your other repo bevy_tiled?
I'm working on a dwarf fortress style map with multiple z-level used to represent a 3rd dimension while keeping everything 2d.
Currently, I'm using a different layer for each z_level. When I want to change the current z_level I simply hide any layers above the current one. My problem is that, to do this I have to set every tile in each layer to be not visible. I know there's a despawn_layer (technically, depsawn_layer ๐), but when I used it I couldn't figure out how to rebuild a layer at run time and I also don't think I should do that any way.
Essentially, what I want is a way to set an entire layer to not visible without having to loop on every tile.
Also, what's the best place to ask a question about this crate? Should I just ask in the bevy discord channel?
Unlike in a top-down or side view game, In many (most?) isometric games, objects represented by a tile may be taller than the actual tile space. (Like, a tree or a wall.)
From chat:
StarToaster
I have given some thought on how to achieve that. A couple of steps need to happen for that to work:
- Allow isometric tiles to render larger then the actual tile grid size as this allows tiles to kind of overlap each other. You would also use the rendered size for mouse picking.
- Each layer is rendered top down by splitting each horizontal row into is own layer this insures that tiles are rendered correctly. > Another option would be to also calculate the z-index as being Y. This adds the further benefit of allowing sprites on the isometric tile map to render "behind" tiles. This is very similar to how some isometric games actually function(project hospital is one example).
I don't know when I'll be able to find the time to add those things to bevy_ecs_tilemap, it certain is possible for someone to mostly do all of this currently except for point 1.
I'm a little out of my depth here, so apologies in advance for any mistakes.
I have a Texture Atlas with 16x16 tiles separated by a 1px gap in the x and y.
I'm using LayerSettings like this:
let mut layer_settings = LayerSettings::new(
MapSize(2, 2),
ChunkSize(1, 1),
TileSize(16.0, 16.0),
TextureSize(628.0, 475.0),
);
layer_settings.tile_spacing = Vec2::new(1.0, 1.0);
That middle grass tile in the bottom left has an index of 963. I'm selecting it like this:
let mut tile_bundle = TileBundle::default();
tile_bundle.tile.texture_index = 963u16;
But when that runs, it outputs this:
I've experimented a bit, and I can get a lot closer to what I want by using (columns * tile_size) and (rows * tile_size) as the TextureSize x and y, and removing the tile_spacing. But that leaves me with a 1px gap between tiles:
So I went into src/render/square-tilemap.vert and changed
int columns = int(texture_size.x) / int(tile_size.x);
float sprite_sheet_x = floor(float(texture_index % columns)) * (tile_size.x + spacing.x) - spacing.x;
float sprite_sheet_y = floor((texture_index / columns)) * (tile_size.y + spacing.y) - spacing.y;
to
vec2 slot_size = tile_size + spacing;
int columns = int(floor((texture_size.x + spacing.x) / slot_size.x));
float sprite_sheet_x = floor(mod(float(texture_index), float(columns)) * (slot_size.x));
float sprite_sheet_y = floor((texture_index / columns)) * (slot_size.y);
This pretty much works, although it breaks if tile_index = columns.
Maybe this should be a pull request, but I'm very much not confident in my changes. I think I'm right that columns should account for spacing. I'm not sure if the Texture Atlas I'm using is up to standard. And I could be misunderstanding tile_spacing entirely. Any assistance would be appreciated.
I am trying to make use of this library to load a ldtk map.
I added the following line to the cargo.toml:
bevy_ecs_tilemap = { version = "0.4.0", features = ["ldtk"] }
and I am getting the following error:
the package
bevy-multidepends on
bevy_ecs_tilemap, with features:
ldtkbut
bevy_ecs_tilemap does not have these features.
Also, docs.rs it does not show any feature flags.
Is there any reason why the tiled and ldtk are not published, or am I doing something wrong?
For action games, the sprite entities would be 'free-floating' entities rendered on top of the map, but the game would still want to track their position relative to the map itself. It probably doesn't make sense to have the map store those entities or references to them, but it would be useful to have the map translate a position (given as a DVec2
) and return a Transform
or DVec2
object that corresponds to the screen coordinates of that location given the map projection and scale and vice versa.
I understand that loading LDTK is still new in this project, but I'd like to report the issue I'm having.
I've got an open example at https://github.com/Aposhian/bevy-sandbox where you can run cargo run --example ldtk
see the behavior I am talking about.
When I load the LDTK level, there is undesired spacing between tiles, and some of the tiles do not render with the proper texture. I wonder if this either due to my texture atlas being irregular, or my .ldtk
file being misconfigured.
In the LDTK editor, it looks like this:
But Bevy is rendering it like this:
I have created a small test with a bg layer of tiles, and a second sparse layer on top with a player tile that moves with the keys. Upon moving from one chunk to another the player tile stops moving until the position returns to the original chunk.
I'm just updating the UVec2 position, and using notify_chunk_for_tile() from mapquery. Should I be going about this in a different way?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.