Adjust collision to use drawn bounding boxes
parent
5f8bd8c87b
commit
bb8fc323f5
|
@ -19,3 +19,4 @@ linked-hash-map = "0.5.6"
|
||||||
convert_case = "0.6.0"
|
convert_case = "0.6.0"
|
||||||
roxmltree = "0.18.0"
|
roxmltree = "0.18.0"
|
||||||
regex = "1.9.5"
|
regex = "1.9.5"
|
||||||
|
euclid = "0.22.9"
|
|
@ -1,4 +1,5 @@
|
||||||
use std::{error::Error, fs::read_to_string, path::Path, borrow::Cow};
|
use std::{error::Error, fs::read_to_string, path::Path, borrow::Cow};
|
||||||
|
use euclid::default::Rect;
|
||||||
use image::{DynamicImage, GenericImageView};
|
use image::{DynamicImage, GenericImageView};
|
||||||
use linked_hash_map::LinkedHashMap;
|
use linked_hash_map::LinkedHashMap;
|
||||||
use roxmltree::Node;
|
use roxmltree::Node;
|
||||||
|
@ -9,6 +10,7 @@ pub struct TiledTilemap {
|
||||||
pub tileset: Vec<TiledTileset>,
|
pub tileset: Vec<TiledTileset>,
|
||||||
pub layers: Vec<Layer>,
|
pub layers: Vec<Layer>,
|
||||||
pub objects: Vec<Object>,
|
pub objects: Vec<Object>,
|
||||||
|
pub collision: Vec<Rect<u16>>,
|
||||||
pub width: usize,
|
pub width: usize,
|
||||||
pub height: usize
|
pub height: usize
|
||||||
}
|
}
|
||||||
|
@ -48,9 +50,6 @@ pub enum Layer {
|
||||||
Tile {
|
Tile {
|
||||||
system_plane: SystemPlane,
|
system_plane: SystemPlane,
|
||||||
tiles: Vec<u32>
|
tiles: Vec<u32>
|
||||||
},
|
|
||||||
Collision {
|
|
||||||
tiles: Vec<u32>
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +103,6 @@ fn get_layer( layer: Node, map_width: usize, map_height: usize ) -> Result<Optio
|
||||||
system_plane: SystemPlane::MdPlaneB,
|
system_plane: SystemPlane::MdPlaneB,
|
||||||
tiles
|
tiles
|
||||||
} ) ),
|
} ) ),
|
||||||
"collision" => Ok( Some( Layer::Collision { tiles } ) ),
|
|
||||||
_ => {
|
_ => {
|
||||||
print_warning( &format!( "on layer {}: invalid reskit-layer value {}; ignoring this layer", layer_name, layer_type ) );
|
print_warning( &format!( "on layer {}: invalid reskit-layer value {}; ignoring this layer", layer_name, layer_type ) );
|
||||||
Ok( None )
|
Ok( None )
|
||||||
|
@ -343,16 +341,43 @@ pub fn get_tiled_tilemap( path: &str, object_fields: &Vec<&str> ) -> Result<Tile
|
||||||
.filter_map( | option | option )
|
.filter_map( | option | option )
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Print warning if there is no collision layer
|
|
||||||
if let None = layers.iter().find( | layer | matches!( layer, Layer::Collision { tiles: _ } ) ) {
|
|
||||||
print_warning( "tile map has no \"collision\" layer: this probably is not what you want" );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the entity-component system
|
// Get the entity-component system
|
||||||
let object_group = map.descendants().find( | node | node.tag_name() == "objectgroup".into() );
|
let object_group = map.descendants().find( | node |
|
||||||
|
node.tag_name() == "objectgroup".into() &&
|
||||||
|
node.descendants().find( | node | node.attribute( "name" ) == Some( "reskit-layer" ) && node.attribute( "value" ) == Some( "object" ) ).is_some()
|
||||||
|
);
|
||||||
let objects = if let Some( object_group ) = object_group {
|
let objects = if let Some( object_group ) = object_group {
|
||||||
get_objs( &object_group, object_fields )?
|
get_objs( &object_group, object_fields )?
|
||||||
} else {
|
} else {
|
||||||
|
print_warning( "no object layer in this file, this is probably not what you want..." );
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get collision
|
||||||
|
let collision_group = map.descendants().find( | node |
|
||||||
|
node.tag_name() == "objectgroup".into() &&
|
||||||
|
node.descendants().find( | node | node.attribute( "name" ) == Some( "reskit-layer" ) && node.attribute( "value" ) == Some( "collision" ) ).is_some()
|
||||||
|
);
|
||||||
|
let collision = if let Some( collision_group ) = collision_group {
|
||||||
|
let mut result = Vec::new();
|
||||||
|
let objects = collision_group.descendants().filter( | node | node.tag_name() == "object".into() );
|
||||||
|
|
||||||
|
for object in objects {
|
||||||
|
let x: u16 = object.attribute( "x" ).ok_or( "invalid file: no \"x\" attribute in collision bounding box" )?.parse()?;
|
||||||
|
let y: u16 = object.attribute( "y" ).ok_or( "invalid file: no \"y\" attribute in collision bounding box" )?.parse()?;
|
||||||
|
let width: u16 = object.attribute( "width" ).ok_or( "invalid file: no \"width\" attribute in collision bounding box" )?.parse()?;
|
||||||
|
let height: u16 = object.attribute( "height" ).ok_or( "invalid file: no \"height\" attribute in collision bounding box" )?.parse()?;
|
||||||
|
|
||||||
|
result.push( euclid::rect( x, y, width, height ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.is_empty() {
|
||||||
|
print_warning( "collision layer present but no bounding boxes are defined, this is probably not what you want..." );
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
} else {
|
||||||
|
print_warning( "no collision layer in this file, this is probably not what you want..." );
|
||||||
Vec::new()
|
Vec::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -361,6 +386,7 @@ pub fn get_tiled_tilemap( path: &str, object_fields: &Vec<&str> ) -> Result<Tile
|
||||||
tileset,
|
tileset,
|
||||||
layers,
|
layers,
|
||||||
objects,
|
objects,
|
||||||
|
collision,
|
||||||
width,
|
width,
|
||||||
height
|
height
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,17 +199,22 @@ pub fn get_tilemap( tilemap: &TiledTilemap ) -> Result<Vec<u8>, Box<dyn Error>>
|
||||||
pub fn get_collision_map( tilemap: &TiledTilemap ) -> Result<Vec<u8>, Box<dyn Error>> {
|
pub fn get_collision_map( tilemap: &TiledTilemap ) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||||
let mut result: Vec<u8> = Vec::new();
|
let mut result: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
let collision: Option<&Layer> = tilemap.layers.iter().find( | layer | matches!( layer, Layer::Collision { tiles: _ } ) );
|
// 2 bytes: Number of bounding boxes
|
||||||
if let Some( collision ) = collision {
|
result.extend( ( tilemap.collision.len() as u16 ).to_be_bytes() );
|
||||||
let collision = match collision {
|
|
||||||
Layer::Collision { tiles } => tiles,
|
|
||||||
_ => return Err( "internal error: invalid object type" )?
|
|
||||||
};
|
|
||||||
|
|
||||||
for collision_data in collision {
|
// For (Number of bounding boxes):
|
||||||
let collision_data: u8 = if *collision_data > 0 { 1 } else { 0 };
|
for bounding_box in &tilemap.collision {
|
||||||
result.push( collision_data );
|
// 2 bytes: X dimension
|
||||||
}
|
result.extend( bounding_box.origin.x.to_be_bytes() );
|
||||||
|
|
||||||
|
// 2 bytes: Y dimension
|
||||||
|
result.extend( bounding_box.origin.y.to_be_bytes() );
|
||||||
|
|
||||||
|
// 2 bytes: X2 dimension (x + width)
|
||||||
|
result.extend( ( bounding_box.origin.x + bounding_box.size.width ).to_be_bytes() );
|
||||||
|
|
||||||
|
// 2 bytes: Y2 dimension (y + height)
|
||||||
|
result.extend( ( bounding_box.origin.y + bounding_box.size.height ).to_be_bytes() );
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok( result )
|
Ok( result )
|
||||||
|
|
Loading…
Reference in New Issue