Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add stagger map support #405

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ ldtk_rust = { version = "0.6" }
rand = "0.8"
env_logger = "0.9"
serde_json = { version = "1.0" }
tiled = { version = "0.10.2", default-features = false }
tiled = { git = "https://github.com/mapeditor/rs-tiled.git", branch = "current" }

[dev-dependencies.bevy]
version = "0.10"
Expand Down
11 changes: 11 additions & 0 deletions assets/hexagonal.tmx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.10.0" orientation="hexagonal" renderorder="right-down" width="18" height="10" tilewidth="48" tileheight="54" infinite="0" hexsidelength="26" staggeraxis="y" staggerindex="even" nextlayerid="2" nextobjectid="1">
<tileset firstgid="1" name="t1" tilewidth="48" tileheight="54" tilecount="1" columns="1">
<image source="hex-tile-1.png" width="48" height="54"/>
</tileset>
<layer id="1" name="Layer 1" width="18" height="10">
<data encoding="base64" compression="zstd">
KLUv/WDQAeUBAFAAAQEAAQEBAQEBHaCAfWADSeohACiwECWHwVncQwOrX2HuohFAI8zdiZaXlO5S+myG50vazEDnIKfTOw==
</data>
</layer>
</map>
100 changes: 87 additions & 13 deletions examples/helpers/tiled.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// * When the 'atlas' feature is enabled tilesets using a collection of images will be skipped.
// * Only finite tile layers are loaded. Infinite tile layers and object layers will be skipped.

use std::io::BufReader;
use std::path::Path;

use bevy::{
asset::{AssetLoader, AssetPath, LoadedAsset},
Expand All @@ -27,6 +27,7 @@ use bevy::{
use bevy_ecs_tilemap::prelude::*;

use anyhow::Result;
use tiled::{StaggerAxis, StaggerIndex};

#[derive(Default)]
pub struct TiledMapPlugin;
Expand Down Expand Up @@ -65,6 +66,58 @@ pub struct TiledMapBundle {
pub global_transform: GlobalTransform,
}

// Because bevy assetloader is pre load bytes for our
// so we do not need reopen tmx file which supply from rs-tiled.
struct BytesResourceReader<'a>(&'a [u8], &'a Path);

impl<'a> tiled::ResourceReader for BytesResourceReader<'a> {
type Resource = &'a [u8];
type Error = std::io::Error;
fn read_from(&mut self, path: &Path) -> std::result::Result<Self::Resource, Self::Error> {
if path == self.1 {
Ok(self.0)
} else {
// It is not safe for rust-lang to really open file and return bytes
// So we just send file no found.
Err(std::io::Error::new(std::io::ErrorKind::NotFound, "file not found"))
}
}
}

// This cache do not cache anything because we use bevy cache
// not rs-tiled's cache system.
struct NoopResourceCache;

impl tiled::ResourceCache for NoopResourceCache {
fn get_tileset(
&self,
_path: impl AsRef<tiled::ResourcePath>,
) -> Option<std::sync::Arc<tiled::Tileset>> {
None
}

fn get_template(
&self,
_path: impl AsRef<tiled::ResourcePath>,
) -> Option<std::sync::Arc<tiled::Template>> {
None
}

fn insert_tileset(
&mut self,
_path: impl AsRef<tiled::ResourcePath>,
_tileset: std::sync::Arc<tiled::Tileset>,
) {
}

fn insert_template(
&mut self,
_path: impl AsRef<tiled::ResourcePath>,
_template: std::sync::Arc<tiled::Template>,
) {
}
}

pub struct TiledLoader;

impl AssetLoader for TiledLoader {
Expand All @@ -81,9 +134,10 @@ impl AssetLoader for TiledLoader {
.parent()
.expect("The asset load context was empty.");

let mut loader = tiled::Loader::new();
let map = loader
.load_tmx_map_from(BufReader::new(bytes), load_context.path())
// BytesResourceReader ONLY read from bytes.
let mm = BytesResourceReader(bytes, load_context.path());
let map = tiled::Loader::with_cache_and_reader(NoopResourceCache, mm)
.load_tmx_map(load_context.path())
.map_err(|e| anyhow::anyhow!("Could not load TMX map: {e}"))?;

let mut dependencies = Vec::new();
Expand Down Expand Up @@ -121,10 +175,9 @@ impl AssetLoader for TiledLoader {
}
}
Some(img) => {
let tile_path = tmx_dir.join(&img.source);
let asset_path = AssetPath::new(tile_path, None);
let asset_path = AssetPath::new(img.source.clone(), None);
let texture: Handle<Image> = load_context.get_handle(asset_path.clone());
dependencies.push(asset_path);
dependencies.push(img.source.clone().into());

TilemapTexture::Single(texture.clone())
}
Expand Down Expand Up @@ -232,7 +285,7 @@ pub fn process_loaded_maps(
let offset_x = layer.offset_x;
let offset_y = layer.offset_y;

let tiled::LayerType::TileLayer(tile_layer) = layer.layer_type() else {
let tiled::LayerType::Tiles(tile_layer) = layer.layer_type() else {
log::info!(
"Skipping layer {} because only tile layers are supported.",
layer.id()
Expand All @@ -259,9 +312,28 @@ pub fn process_loaded_maps(
};

let map_type = match tiled_map.map.orientation {
tiled::Orientation::Hexagonal => {
TilemapType::Hexagon(HexCoordSystem::Row)
}
tiled::Orientation::Hexagonal => match tiled_map.map.stagger_axis {
StaggerAxis::X => match tiled_map.map.stagger_index {
StaggerIndex::Even => {
// TODO: Why Even is Odd?
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is because of how bevy handles Y coordinates. In tiled map editor Y down goes into the positive and in bevy Y down goes into the negative. When we load the tiles in we end up flipping the entire tilemap along the Y axis using: mapped_y = tiled_map.map.height - 1 - y;. Because of this we also need to "flip" the stagger.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. I'm not sure what to do about that other than add a comment to explain the situation.

TilemapType::Hexagon(HexCoordSystem::ColumnOdd)
}
StaggerIndex::Odd => {
// TODO: Why Odd is Even?
TilemapType::Hexagon(HexCoordSystem::ColumnEven)
}
},
StaggerAxis::Y => match tiled_map.map.stagger_index {
StaggerIndex::Even => {
// TODO: Why Even is Odd?
TilemapType::Hexagon(HexCoordSystem::RowOdd)
}
StaggerIndex::Odd => {
// TODO: Why Odd is Even?
TilemapType::Hexagon(HexCoordSystem::RowEven)
}
},
},
tiled::Orientation::Isometric => {
TilemapType::Isometric(IsoCoordSystem::Diamond)
}
Expand All @@ -277,8 +349,10 @@ pub fn process_loaded_maps(
for x in 0..map_size.x {
for y in 0..map_size.y {
let mut mapped_y = y;
if tiled_map.map.orientation == tiled::Orientation::Orthogonal {
mapped_y = (tiled_map.map.height - 1) - y;
if tiled_map.map.orientation == tiled::Orientation::Orthogonal
|| tiled_map.map.orientation == tiled::Orientation::Hexagonal
{
mapped_y = tiled_map.map.height - 1 - y;
}

let mapped_x = x as i32;
Expand Down