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

start map v2 #8

Merged
merged 6 commits into from
May 12, 2023
Merged
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: 2 additions & 0 deletions macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ pub fn include_map(input: TokenStream) -> TokenStream {
{
use m3_map::Map;
use m3_map::tiles::MapBaseTile;
use m3_map::Player;
use m3_map::tiles::ObjectTile;
// include the bytes so that the compiler knows to recompile when the
// map or tilesets changes
const _: &[u8] = ::core::include_bytes!(#path);
Expand Down
128 changes: 123 additions & 5 deletions map/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
use self_rust_tokenize::SelfRustTokenize;
use std::path::Path;
use std::{iter, path::Path};
use thiserror::Error;
use tiled::{LayerType, Loader};

pub mod tiles;
use tiles::{InvalidTileID, MapBaseTile};
use tiles::{InvalidTileID, MapBaseTile, ObjectTile, PlayerTile, Tile};

#[derive(Clone, Debug, SelfRustTokenize)]
pub struct Player {
pub start: (u8, u8),
pub goal: Option<(u8, u8)>
}

#[derive(Clone, Debug, SelfRustTokenize)]
pub struct Map {
pub width: u8,
pub height: u8,
pub base_layer: Vec<Vec<MapBaseTile>>
pub base_layer: Vec<Vec<MapBaseTile>>,
pub object_layer: Vec<Vec<Option<ObjectTile>>>,
pub global_goal: Option<(u8, u8)>,
pub player_1: Player,
pub player_2: Option<Player>,
pub player_3: Option<Player>,
pub player_4: Option<Player>
}

#[derive(Error, Debug)]
Expand All @@ -28,15 +40,24 @@ pub enum MapError {
#[error("Map is to hight. Max size is 255x255 tiles")]
ToHight,
#[error("{0}")]
InvalidTileId(#[from] InvalidTileID)
InvalidTileId(#[from] InvalidTileID),
#[error("Map needs at least one player")]
NoPlayer
}

impl Map {
// this is ugly. Should i refactor this?
pub fn from_tmx(path: impl AsRef<Path>) -> Result<Self, MapError> {
let map = Loader::new().load_tmx_map(path)?;
let width: u8 = map.width.try_into().map_err(|_| MapError::ToWidth)?;
let height: u8 = map.height.try_into().map_err(|_| MapError::ToHight)?;
let mut base_layer = Vec::with_capacity(height as usize);
let mut object_layer = Vec::with_capacity(height as usize);
let mut global_goal = None;
let mut player_1 = None;
let mut player_2 = None;
let mut player_3 = None;
let mut player_4 = None;
for (i, layer) in map.layers().enumerate() {
match i {
0 => match layer.layer_type() {
Expand All @@ -55,13 +76,79 @@ impl Map {
},
_ => return Err(MapError::WrongLayer(i, "TileLayer".to_owned()))
},
1 => match layer.layer_type() {
LayerType::Tiles(tile_layer) => {
for x in 0..width {
let mut column = Vec::with_capacity(width as usize);
for y in 0..height {
let tile = match tile_layer.get_tile(x.into(), y.into()) {
Some(tile) => Some(ObjectTile::try_from(tile.id())?),
None => None
};
column.push(tile);
}
object_layer.push(column);
}
},
_ => return Err(MapError::WrongLayer(i, "TileLayer".to_owned()))
},
2 => match layer.layer_type() {
LayerType::Tiles(tile_layer) => {
for x in 0..width {
for y in 0..height {
if let Some(tile) =
tile_layer.get_tile(x.into(), y.into())
{
let tile = PlayerTile::try_from(tile.id())?;
match tile {
PlayerTile::Car1 => {
player_1 = Some(Player {
start: (x, y),
goal: None
})
},
PlayerTile::Car2 => {
player_2 = Some(Player {
start: (x, y),
goal: None
})
},
PlayerTile::Car3 => {
player_3 = Some(Player {
start: (x, y),
goal: None
})
},
PlayerTile::Car4 => {
player_4 = Some(Player {
start: (x, y),
goal: None
})
},
PlayerTile::GlobalGoal => {
global_goal = Some((x, y))
},
}
}
}
}
},
_ => return Err(MapError::WrongLayer(i, "TileLayer".to_owned()))
},
_ => return Err(MapError::ToManyLayers)
}
}
let player_1 = player_1.ok_or(MapError::NoPlayer)?;
Ok(Map {
width,
height,
base_layer
base_layer,
object_layer,
global_goal,
player_1,
player_2,
player_3,
player_4
})
}

Expand All @@ -74,4 +161,35 @@ impl Map {
.map(move |(y, item)| (x as u8, y as u8, item))
})
}

/// return an iterator over all ObjectTiles and its x and y postion
pub fn iter_object_layer(&self) -> impl Iterator<Item = (u8, u8, ObjectTile)> + '_ {
self.object_layer.iter().enumerate().flat_map(|(x, y_vec)| {
y_vec
.iter()
.enumerate()
.filter_map(move |(y, item)| item.map(|item| (x as u8, y as u8, item)))
})
}

/// return an iterator over all player goals tiles and its x and y postion
pub fn iter_player_goals(&self) -> impl Iterator<Item = (u8, u8, PlayerTile)> + '_ {
iter::once(self.global_goal)
.flat_map(|goal| goal.map(|(x, y)| (x, y, PlayerTile::GlobalGoal)))
}

/// return an iterator over all static Tiles and its x and y postion.
/// starting from the lowest layer
pub fn iter_all(&self) -> impl Iterator<Item = (u8, u8, Tile)> + '_ {
let base = self
.iter_base_layer()
.map(|(x, y, tile)| (x, y, Tile::MapBaseTile(tile.to_owned())));
let objects = self
.iter_object_layer()
.map(|(x, y, tile)| (x, y, Tile::MapObjectTile(tile.to_owned())));
let goals = self
.iter_player_goals()
.map(|(x, y, tile)| (x, y, Tile::PlayerTile(tile)));
base.chain(objects).chain(goals)
}
}
4 changes: 2 additions & 2 deletions map/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ pub struct Opt {

fn main() {
let opt = Opt::parse();
let result = Map::from_tmx(&opt.file);
let result = Map::from_tmx(opt.file);
match result {
Err(err) => {
eprintln!("ERROR: {err}");
std::process::exit(1);
},
Ok(map) => println!("{map:#?}")
Ok(map) => println!("{map:#?}\nmap is valid")
}
}
60 changes: 53 additions & 7 deletions map/src/tiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@ use num_enum::TryFromPrimitive;
use self_rust_tokenize::SelfRustTokenize;
use thiserror::Error;

pub enum Tile {
MapBaseTile(MapBaseTile),
MapObjectTile(ObjectTile),
PlayerTile(PlayerTile)
}

#[derive(Debug, Copy, Clone, Error)]
pub enum InvalidTileID {
#[error("invalid tiel id {0}")]
InvalidId(u32)
}

///Store all Tiles, with can be used at the map background
#[derive(
Clone, Copy, Debug, Default, Eq, SelfRustTokenize, PartialEq, TryFromPrimitive,
Expand All @@ -10,19 +22,53 @@ use thiserror::Error;
pub enum MapBaseTile {
//numbers must match them from the Tiled tilesets
#[default]
Grass = 0,
Grass = 0
}

impl TryFrom<u32> for MapBaseTile {
type Error = InvalidTileID;
fn try_from(value: u32) -> Result<MapBaseTile, Self::Error> {
let value_u8: u8 = value
.try_into()
.map_err(|_| Self::Error::InvalidId(value))?;
Self::try_from_primitive(value_u8).map_err(|_| Self::Error::InvalidId(value))
}
}

///Store all Tiles, with can be place the layer above the background
#[derive(Clone, Copy, Debug, Eq, SelfRustTokenize, PartialEq, TryFromPrimitive)]
#[repr(u8)]
pub enum ObjectTile {
//numbers must match them from the Tiled tilesets
Stone = 1
}

#[derive(Debug, Copy, Clone, Error)]
pub enum InvalidTileID {
#[error("invalid tiel id {0}")]
InvalidId(u32)
impl TryFrom<u32> for ObjectTile {
type Error = InvalidTileID;
fn try_from(value: u32) -> Result<ObjectTile, Self::Error> {
let value_u8: u8 = value
.try_into()
.map_err(|_| Self::Error::InvalidId(value))?;
Self::try_from_primitive(value_u8).map_err(|_| Self::Error::InvalidId(value))
}
}

impl TryFrom<u32> for MapBaseTile {
///Store all Tiles, with can be place the layer above the background
#[derive(Clone, Copy, Debug, Eq, SelfRustTokenize, PartialEq, TryFromPrimitive)]
#[repr(u8)]
pub enum PlayerTile {
//numbers must match them from the Tiled tilesets
Car1 = 0,
Car2 = 1,
Car3 = 2,
Car4 = 3,
//goal, which can be used by all players
GlobalGoal = 4
}

impl TryFrom<u32> for PlayerTile {
type Error = InvalidTileID;
fn try_from(value: u32) -> Result<MapBaseTile, Self::Error> {
fn try_from(value: u32) -> Result<PlayerTile, Self::Error> {
let value_u8: u8 = value
.try_into()
.map_err(|_| Self::Error::InvalidId(value))?;
Expand Down
5 changes: 1 addition & 4 deletions pc/assets/img/BaseTiles/BaseTiles.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.10.1" name="BaseTiles" tilewidth="256" tileheight="256" tilecount="2" columns="0">
<tileset version="1.10" tiledversion="1.10.1" name="BaseTiles" tilewidth="256" tileheight="256" tilecount="1" columns="0">
<grid orientation="orthogonal" width="1" height="1"/>
<tile id="0">
<image width="256" height="256" source="grass.png"/>
</tile>
<tile id="1">
<image width="256" height="256" source="stone.png"/>
</tile>
</tileset>
Binary file removed pc/assets/img/BaseTiles/Grass mit Rand.png
Binary file not shown.
Binary file removed pc/assets/img/BaseTiles/Grass mit Rand2.png
Binary file not shown.
Binary file modified pc/assets/img/BaseTiles/grass.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed pc/assets/img/BaseTiles/stone.png
Binary file not shown.
7 changes: 7 additions & 0 deletions pc/assets/img/ObjectTiles/ObjectTiles.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.10.1" name="ObjectTiles" tilewidth="256" tileheight="256" tilecount="1" columns="0">
<grid orientation="orthogonal" width="1" height="1"/>
<tile id="1">
<image width="256" height="256" source="stone.png"/>
</tile>
</tileset>
19 changes: 19 additions & 0 deletions pc/assets/img/Player/Player.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.10.1" name="Player" tilewidth="256" tileheight="256" tilecount="5" columns="0">
<grid orientation="orthogonal" width="1" height="1"/>
<tile id="0">
<image width="256" height="256" source="player1_car.png"/>
</tile>
<tile id="1">
<image width="256" height="256" source="player2_car.png"/>
</tile>
<tile id="2">
<image width="256" height="256" source="player3_car.png"/>
</tile>
<tile id="3">
<image width="256" height="256" source="player4_car.png"/>
</tile>
<tile id="4">
<image width="256" height="256" source="goal.png"/>
</tile>
</tileset>
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
Binary file removed pc/assets/img/player1_car.png
Binary file not shown.
40 changes: 34 additions & 6 deletions pc/assets/level/001.tmx
Original file line number Diff line number Diff line change
@@ -1,17 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="16" height="9" tilewidth="256" tileheight="256" infinite="0" nextlayerid="2" nextobjectid="1">
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="16" height="9" tilewidth="256" tileheight="256" infinite="0" nextlayerid="4" nextobjectid="1">
<tileset firstgid="1" source="../img/BaseTiles/BaseTiles.tsx"/>
<layer id="1" name="Tile Layer 1" width="16" height="9">
<tileset firstgid="2" source="../img/ObjectTiles/ObjectTiles.tsx"/>
<tileset firstgid="4" source="../img/Player/Player.tsx"/>
<layer id="1" name="Base" width="16" height="9">
<data encoding="csv">
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,2,2,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,2,2,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
</data>
</layer>
<layer id="2" name="Objects" width="16" height="9">
<data encoding="csv">
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,
0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,3,0,0,3,3,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,3,3,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
</data>
</layer>
<layer id="3" name="Player" width="16" height="9">
<data encoding="csv">
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,
0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,4,0,0,0,0,0,0,0,0,0,0,7,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
</data>
</layer>
</map>
4 changes: 2 additions & 2 deletions pc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ use tetra::{
Context, ContextBuilder, State
};
type Vec2 = vek::vec::repr_c::vec2::Vec2<f32>;
use log::info;
use m3_macro::include_map;
use m3_map::Map;
use once_cell::sync::Lazy;
use tetra::{
graphics::{DrawParams, Texture},
time::get_delta_time
};
use log::{info};

mod tiles;
use tiles::Textures;
Expand Down Expand Up @@ -60,7 +60,7 @@ impl State for GameState {
(window_size.0 / map.width as i32) as f32,
(window_size.1 / map.height as i32) as f32
);
for (x, y, tile) in map.iter_base_layer() {
for (x, y, tile) in map.iter_all() {
let texture = tile.texture(&self.textures);
texture.draw(
ctx,
Expand Down
Loading