1

I'm very new to game dev and to Rust, so I might be way on the wrong track. I'm using bevy 0.10.1, bevy_ecs_tilemap, bevy_rapier2d, and tiled to make a tilemap with collisions specified in the .tsx file. Some of my tiles use polygons to define the collision objects. I'm able to get the rectangular collisions to work, but the polygon collisions are in the wrong location and sometimes the wrong shape. Game showing collision shapes

if let Some(object_layer) = layer_tile.collision.clone() {
                            let shapes = object_layer
                                .object_data()
                                .iter()
                                .filter_map(|object_data| {
                                    let pos = Vect::new(object_data.x / 2., -object_data.y / 2.);
                                    let rot = object_data.rotation;
                                    let shape = match &object_data.shape {
                                        tiled::ObjectShape::Rect { width, height } => {
                                            Collider::cuboid(width / 2., height / 2.)
                                        }
                                        tiled::ObjectShape::Ellipse { width, height } => {
                                            Collider::capsule_x(width / 2., height / 2.)
                                        }
                                        tiled::ObjectShape::Polyline { points } => {
                                            Collider::polyline(
                                                points
                                                    .iter()
                                                    .map(|(x, y)| Vect::new(*x, *y))
                                                    .collect(),
                                                None,
                                            )
                                        }
                                        tiled::ObjectShape::Polygon { points } => {
                                            Collider::convex_hull(
                                                &points
                                                    .iter()
                                                    .map(|(x, y)| Vect::new(*x, *y))
                                                    .collect::<Vec<_>>(),
                                            )?
                                        }
                                        _ => {
                                            return None;
                                        }
                                    };
                                    Some((pos, rot, shape))
                                })
                                .collect::<Vec<_>>();
                            let world_pos = tile_pos.center_in_world(&grid_size, &map_type);
                            let transform =
                                get_tilemap_center_transform(&map_size, &grid_size, &map_type, 0.)
                                    * Transform::from_xyz(
                                        world_pos.x + offset_x,
                                        world_pos.y - offset_y,
                                        0.,
                                    );
                            if shapes.len() == 1 {
                                let (pos, rot, collider) = shapes[0].clone();
                                let transform = transform
                                    * Transform {
                                        translation: Vec3::new(pos.x, pos.y, 0.),
                                        rotation: Quat::from_rotation_x(rot),
                                        ..default()
                                    };
                                commands
                                    .entity(tile_entity)
                                    .insert((collider, TransformBundle::from_transform(transform)));
                            } else if shapes.len() > 1 {
                                commands.entity(tile_entity).insert((
                                    Collider::compound(shapes),
                                    TransformBundle::from_transform(transform),
                                ));
                            }
                        }

How do I convert tiled polygon collision data into Rapier colliders? Or am I combining tools that don't belong together?

Eva
  • 4,397
  • 5
  • 43
  • 65

1 Answers1

0

After much trial and error, I figured out how to do it. The polygons were upside-down and I needed to treat the rectangles different from the polygons. (My tilemap currently doesn't have ellipses or polylines, so I'm assuming they work the same as the other shapes.)

if let Some(object_layer) = layer_tile.collision.clone() {
                            let shapes = object_layer
                                .object_data()
                                .iter()
                                .filter_map(|object_data| {
                                    let pos = Vect::new(object_data.x, -object_data.y);
                                    let rot = object_data.rotation;
                                    match &object_data.shape {
                                        tiled::ObjectShape::Rect { width, height } => {
                                            let shape = Collider::cuboid(width / 2., height / 2.);
                                            Some((
                                                pos + Vec2::new(
                                                    (-grid_size.x + width) / 2.,
                                                    (grid_size.y - height) / 2.,
                                                ),
                                                rot,
                                                shape,
                                            ))
                                        }
                                        tiled::ObjectShape::Ellipse { width, height } => {
                                            let shape =
                                                Collider::capsule_x(width / 2., height / 2.);
                                            Some((
                                                pos + Vec2::new(
                                                    (-grid_size.x + width) / 2.,
                                                    (grid_size.y - height) / 2.,
                                                ),
                                                rot,
                                                shape,
                                            ))
                                        }
                                        tiled::ObjectShape::Polyline { points } => {
                                            let shape = Collider::polyline(
                                                points
                                                    .iter()
                                                    .map(|(x, y)| Vect::new(*x, -*y))
                                                    .collect(),
                                                None,
                                            );
                                            Some((
                                                pos + Vec2::new(
                                                    -grid_size.x / 2.,
                                                    grid_size.y / 2.,
                                                ),
                                                rot,
                                                shape,
                                            ))
                                        }
                                        tiled::ObjectShape::Polygon { points } => {
                                            let shape = Collider::convex_hull(
                                                &points
                                                    .iter()
                                                    .map(|(x, y)| Vect::new(*x, -*y))
                                                    .collect::<Vec<_>>(),
                                            )?;
                                            Some((
                                                pos + Vec2::new(
                                                    -grid_size.x / 2.,
                                                    grid_size.y / 2.,
                                                ),
                                                rot,
                                                shape,
                                            ))
                                        }
                                        _ => {
                                            return None;
                                        }
                                    }
                                })
                                .collect::<Vec<_>>();
                            let world_pos = tile_pos.center_in_world(&grid_size, &map_type);
                            let transform =
                                get_tilemap_center_transform(&map_size, &grid_size, &map_type, 0.)
                                    * Transform::from_xyz(
                                        world_pos.x + offset_x,
                                        world_pos.y - offset_y,
                                        0.,
                                    );
                            if shapes.len() == 1 {
                                let (pos, rot, collider) = shapes[0].clone();
                                let transform = transform
                                    * Transform {
                                        translation: Vec3::new(pos.x, pos.y, 0.),
                                        rotation: Quat::from_rotation_x(rot),
                                        ..default()
                                    };
                                commands
                                    .entity(tile_entity)
                                    .insert((collider, TransformBundle::from_transform(transform)));
                            } else if shapes.len() > 1 {
                                commands.entity(tile_entity).insert((
                                    Collider::compound(shapes),
                                    TransformBundle::from_transform(transform),
                                ));
                            }
                        }
Eva
  • 4,397
  • 5
  • 43
  • 65