diff --git a/src/tile.rs b/src/tile.rs index 80d6f979ea1c89f462b013c3f5ef7c4b20369aae..22e5620039ddce3fb1c857701b84417547c6df62 100644 --- a/src/tile.rs +++ b/src/tile.rs @@ -14,7 +14,7 @@ use crate::{ #[derive(Debug, PartialEq, Clone)] pub struct Tile { pub id: u32, - pub images: Vec<Image>, + pub image: Option<Image>, pub properties: Properties, pub objectgroup: Option<ObjectGroup>, pub animation: Option<Vec<Frame>>, @@ -39,13 +39,13 @@ impl Tile { TiledError::MalformedAttributes("tile must have an id with the correct type".to_string()) ); - let mut images = Vec::new(); + let mut image = Option::None; let mut properties = HashMap::new(); let mut objectgroup = None; let mut animation = None; parse_tag!(parser, "tile", { "image" => |attrs| { - images.push(Image::new(parser, attrs)?); + image = Some(Image::new(parser, attrs)?); Ok(()) }, "properties" => |_| { @@ -63,7 +63,7 @@ impl Tile { }); Ok(Tile { id, - images, + image: image, properties, objectgroup, animation, diff --git a/src/tileset.rs b/src/tileset.rs index 264c78609159edb108e366d6319f583aa3c26cfc..41fb009e8cb4f8a9fefb202a64ecb281596a88ea 100644 --- a/src/tileset.rs +++ b/src/tileset.rs @@ -24,9 +24,14 @@ pub struct Tileset { pub spacing: u32, pub margin: u32, pub tilecount: Option<u32>, - /// The Tiled spec says that a tileset can have mutliple images so a `Vec` - /// is used. Usually you will only use one. - pub images: Vec<Image>, + pub columns: u32, + /// A tileset can either: + /// * have a single spritesheet `image` in `tileset` ("regular" tileset); + /// * have zero images in `tileset` and one `image` per `tile` ("image collection" tileset). + /// + /// - Source: [tiled issue #2117](https://github.com/mapeditor/tiled/issues/2117) + /// - Source: [`columns` documentation](https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#tileset) + pub image: Option<Image>, pub tiles: Vec<Tile>, pub properties: Properties, } @@ -54,12 +59,13 @@ impl Tileset { parser: &mut EventReader<R>, attrs: &Vec<OwnedAttribute>, ) -> Result<Tileset, TiledError> { - let ((spacing, margin, tilecount), (first_gid, name, width, height)) = get_attrs!( + let ((spacing, margin, tilecount, columns), (first_gid, name, width, height)) = get_attrs!( attrs, optionals: [ ("spacing", spacing, |v:String| v.parse().ok()), ("margin", margin, |v:String| v.parse().ok()), ("tilecount", tilecount, |v:String| v.parse().ok()), + ("columns", columns, |v:String| v.parse().ok()), ], required: [ ("firstgid", first_gid, |v:String| v.parse().ok()), @@ -70,12 +76,12 @@ impl Tileset { TiledError::MalformedAttributes("tileset must have a firstgid, name tile width and height with correct types".to_string()) ); - let mut images = Vec::new(); + let mut image = Option::None; let mut tiles = Vec::new(); let mut properties = HashMap::new(); parse_tag!(parser, "tileset", { "image" => |attrs| { - images.push(Image::new(parser, attrs)?); + image = Some(Image::new(parser, attrs)?); Ok(()) }, "properties" => |_| { @@ -88,6 +94,15 @@ impl Tileset { }, }); + let columns = match columns { + Some(col) => col, + None => match &image { + None => return Err(TiledError::MalformedAttributes( + "No <image> and no <columns> in <tileset>".to_string())), + Some(image) => image.width as u32 / width, + }, + }; + Ok(Tileset { tile_width: width, tile_height: height, @@ -96,7 +111,8 @@ impl Tileset { first_gid, name, tilecount, - images, + columns, + image, tiles, properties, }) @@ -159,12 +175,13 @@ impl Tileset { parser: &mut EventReader<R>, attrs: &Vec<OwnedAttribute>, ) -> Result<Tileset, TiledError> { - let ((spacing, margin, tilecount), (name, width, height)) = get_attrs!( + let ((spacing, margin, tilecount, columns), (name, width, height)) = get_attrs!( attrs, optionals: [ ("spacing", spacing, |v:String| v.parse().ok()), ("margin", margin, |v:String| v.parse().ok()), ("tilecount", tilecount, |v:String| v.parse().ok()), + ("columns", columns, |v:String| v.parse().ok()), ], required: [ ("name", name, |v| Some(v)), @@ -174,24 +191,33 @@ impl Tileset { TiledError::MalformedAttributes("tileset must have a firstgid, name tile width and height with correct types".to_string()) ); - let mut images = Vec::new(); + let mut image = Option::None; let mut tiles = Vec::new(); let mut properties = HashMap::new(); parse_tag!(parser, "tileset", { "image" => |attrs| { - images.push(Image::new(parser, attrs)?); - Ok(()) - }, - "tile" => |attrs| { - tiles.push(Tile::new(parser, attrs)?); + image = Some(Image::new(parser, attrs)?); Ok(()) }, "properties" => |_| { properties = parse_properties(parser)?; Ok(()) }, + "tile" => |attrs| { + tiles.push(Tile::new(parser, attrs)?); + Ok(()) + }, }); + let columns = match columns { + Some(col) => col, + None => match &image { + None => return Err(TiledError::MalformedAttributes( + "No <image> and no <columns> in <tileset>".to_string())), + Some(image) => image.width as u32 / width, + }, + }; + Ok(Tileset { first_gid: first_gid, name: name, @@ -199,8 +225,9 @@ impl Tileset { tile_height: height, spacing: spacing.unwrap_or(0), margin: margin.unwrap_or(0), - tilecount: tilecount, - images: images, + columns, + tilecount, + image, tiles: tiles, properties, })