Skip to content
Snippets Groups Projects
tile.rs 3.5 KiB
Newer Older
use std::{collections::HashMap, path::Path};
alexdevteam's avatar
alexdevteam committed

use xml::attribute::OwnedAttribute;
alexdevteam's avatar
alexdevteam committed

use crate::{
    animation::{parse_animation, Frame},
alexdevteam's avatar
alexdevteam committed
    error::TiledError,
    image::Image,
    layers::ObjectLayerData,
alexdevteam's avatar
alexdevteam committed
    properties::{parse_properties, Properties},
    util::{get_attrs, parse_tag, XmlEventResult},
Alejandro Perea's avatar
Alejandro Perea committed
    Tileset,
alexdevteam's avatar
alexdevteam committed
};

pub type TileId = u32;

#[derive(Debug, PartialEq, Clone, Default)]
Alejandro Perea's avatar
Alejandro Perea committed
pub(crate) struct TileData {
    image: Option<Image>,
    properties: Properties,
    collision: Option<ObjectLayerData>,
    animation: Option<Vec<Frame>>,
    tile_type: Option<String>,
    probability: f32,
alexdevteam's avatar
alexdevteam committed
}

#[derive(Debug)]
Alejandro Perea's avatar
Alejandro Perea committed
pub struct Tile<'tileset> {
    pub(crate) tileset: &'tileset Tileset,
    pub(crate) data: &'tileset TileData,
}

impl<'tileset> Tile<'tileset> {
    pub(crate) fn new(tileset: &'tileset Tileset, data: &'tileset TileData) -> Self {
        Self { tileset, data }
    }

    /// Get the tileset this tile is from.
    pub fn tileset(&self) -> &'tileset Tileset {
        self.tileset
    }

    /// Get a reference to the tile's image.
    pub fn image(&self) -> Option<&Image> {
        self.data.image.as_ref()
    }

    /// Get a reference to the tile's properties.
    pub fn properties(&self) -> &Properties {
        &self.data.properties
    }

    /// Get a reference to the tile's collision.
    pub fn collision(&self) -> Option<&ObjectLayerData> {
        self.data.collision.as_ref()
    }

    /// Get a reference to the tile's animation frames.
    pub fn animation(&self) -> Option<&[Frame]> {
        self.data.animation.as_ref().map(Vec::as_slice)
    }

    /// Get a reference to the tile's type.
    pub fn tile_type(&self) -> Option<&str> {
        self.data.tile_type.as_deref()
    }

    /// Get the tile's probability.
    pub fn probability(&self) -> f32 {
        self.data.probability
    }
}

impl TileData {
    pub(crate) fn new(
        parser: &mut impl Iterator<Item = XmlEventResult>,
alexdevteam's avatar
alexdevteam committed
        attrs: Vec<OwnedAttribute>,
        path_relative_to: &Path,
Alejandro Perea's avatar
Alejandro Perea committed
    ) -> Result<(TileId, TileData), TiledError> {
alexdevteam's avatar
alexdevteam committed
        let ((tile_type, probability), id) = get_attrs!(
            attrs,
            optionals: [
                ("type", tile_type, |v:String| v.parse().ok()),
                ("probability", probability, |v:String| v.parse().ok()),
            ],
            required: [
                ("id", id, |v:String| v.parse::<u32>().ok()),
            ],
            TiledError::MalformedAttributes("tile must have an id with the correct type".to_string())
        );

alexdevteam's avatar
alexdevteam committed
        let mut properties = HashMap::new();
        let mut objectgroup = None;
        let mut animation = None;
        parse_tag!(parser, "tile", {
            "image" => |attrs| {
                image = Some(Image::new(parser, attrs, path_relative_to)?);
alexdevteam's avatar
alexdevteam committed
                Ok(())
            },
            "properties" => |_| {
                properties = parse_properties(parser)?;
                Ok(())
            },
            "objectgroup" => |attrs| {
                objectgroup = Some(ObjectLayerData::new(parser, attrs, None)?.0);
alexdevteam's avatar
alexdevteam committed
                Ok(())
            },
            "animation" => |_| {
                animation = Some(parse_animation(parser)?);
                Ok(())
            },
        });
alexdevteam's avatar
alexdevteam committed
            id,
Alejandro Perea's avatar
Alejandro Perea committed
            TileData {
                image,
                properties,
                collision: objectgroup,
                animation,
                tile_type,
                probability: probability.unwrap_or(1.0),
            },
        ))
alexdevteam's avatar
alexdevteam committed
    }
}