Newer
Older
use xml::attribute::OwnedAttribute;
error::{Error, Result},
properties::{parse_properties, Properties},
util::{get_attrs, map_wrapper, parse_tag, XmlEventResult},
LayerTile, LayerTileData, MapTilesetGid,
/// A structure describing an [`Object`]'s shape.
///
/// Also see the [TMX docs](https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#tmx-object).
pub enum ObjectShape {
Rect { width: f32, height: f32 },
Ellipse { width: f32, height: f32 },
Polyline { points: Vec<(f32, f32)> },
Polygon { points: Vec<(f32, f32)> },
Point(f32, f32),
}
/// Raw data belonging to an object. Used internally and for tile collisions.
///
/// Also see the [TMX docs](https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#tmx-object).
/// The name of the object, which is arbitrary and set by the user.
/// The type of the object, which is arbitrary and set by the user.
/// The width of the object, if applicable. This refers to the attribute in `object`.
/// Since it is duplicate or irrelevant information in all cases, use the equivalent
/// member in [`ObjectShape`] instead.
#[deprecated(since = "0.10.0", note = "Use [`ObjectShape`] members instead")]
/// The height of the object, if applicable. This refers to the attribute in `object`.
/// Since it is duplicate or irrelevant information in all cases, use the equivalent
/// member in [`ObjectShape`] instead.
#[deprecated(since = "0.10.0", note = "Use [`ObjectShape`] members instead")]
/// The X coordinate of this object in pixels.
/// The Y coordinate of this object in pixels.
/// The clockwise rotation of this object around (x,y) in degrees.
/// Whether the object is shown or hidden.
/// The object's custom properties as set by the user.
impl ObjectData {
/// ID of the object, which is unique per map since Tiled 0.11.
///
/// On older versions this value is defaulted to 0.
#[inline]
pub fn id(&self) -> u32 {
self.id
}
/// Returns the data of the tile that this object is referencing, if it exists.
#[inline]
pub fn tile_data(&self) -> Option<LayerTileData> {
self.tile
}
}
impl ObjectData {
/// If it is known that the object has no tile images in it (i.e. collision data)
/// then we can pass in [`None`] as the tilesets
pub(crate) fn new(
parser: &mut impl Iterator<Item = XmlEventResult>,
tilesets: Option<&[MapTilesetGid]>,
) -> Result<ObjectData> {
let ((id, tile, n, t, w, h, v, r), (x, y)) = get_attrs!(
attrs,
optionals: [
("id", id, |v:String| v.parse().ok()),
("gid", tile, |v:String| v.parse().ok()
.and_then(|bits| LayerTileData::from_bits(bits, tilesets?))),
("name", name, |v:String| v.parse().ok()),
("type", obj_type, |v:String| v.parse().ok()),
("width", width, |v:String| v.parse().ok()),
("height", height, |v:String| v.parse().ok()),
("visible", visible, |v:String| v.parse().ok().map(|x:i32| x == 1)),
("rotation", rotation, |v:String| v.parse().ok()),
],
required: [
("x", x, |v:String| v.parse().ok()),
("y", y, |v:String| v.parse().ok()),
],
Error::MalformedAttributes("objects must have an x and a y number".to_string())
let visible = v.unwrap_or(true);
let width = w.unwrap_or(0f32);
let height = h.unwrap_or(0f32);
let rotation = r.unwrap_or(0f32);
let name = n.unwrap_or_default();
let obj_type = t.unwrap_or_default();
let mut shape = None;
let mut properties = HashMap::new();
parse_tag!(parser, "object", {
"ellipse" => |_| {
shape = Some(ObjectShape::Ellipse {
shape = Some(ObjectData::new_polyline(attrs)?);
shape = Some(ObjectData::new_polygon(attrs)?);
Ok(())
},
"properties" => |_| {
properties = parse_properties(parser)?;
Ok(())
},
});
let shape = shape.unwrap_or(ObjectShape::Rect { width, height });
Ok(ObjectData {
id,
tile,
fn new_polyline(attrs: Vec<OwnedAttribute>) -> Result<ObjectShape> {
("points", points, Some),
Error::MalformedAttributes("A polyline must have points".to_string())
let points = ObjectData::parse_points(s)?;
fn new_polygon(attrs: Vec<OwnedAttribute>) -> Result<ObjectShape> {
("points", points, Some),
Error::MalformedAttributes("A polygon must have points".to_string())
let points = ObjectData::parse_points(s)?;
Ok(ObjectShape::Polygon { points })
fn parse_points(s: String) -> Result<Vec<(f32, f32)>> {
pairs
.map(|point| point.split(','))
.map(|components| {
let v: Vec<&str> = components.collect();
if v.len() != 2 {
return Err(Error::MalformedAttributes(
"one of a polyline's points does not have an x and y coordinate"
.to_string(),
));
}
let (x, y) = (v[0].parse().ok(), v[1].parse().ok());
match (x, y) {
(Some(x), Some(y)) => Ok((x, y)),
_ => Err(Error::MalformedAttributes(
"one of polyline's points does not have i32eger coordinates".to_string(),
)),
}
})
.collect()
map_wrapper!(
#[doc = "Wrapper over an [`ObjectData`] that contains both a reference to the data as well as
to the map it is contained in."]
Object => ObjectData
);
impl<'map> Object<'map> {
/// Returns the tile that the object is using as image, if any.
pub fn get_tile(&self) -> Option<LayerTile<'map>> {
.as_ref()
.map(|tile| LayerTile::new(self.map, tile))
}