use bevy::prelude::*;
use crate::MapRoot;
use bevy_map_core::MapProject;
#[derive(Component, Debug, Clone)]
pub struct CameraBounds {
pub min: Vec2,
pub max: Vec2,
pub padding: f32,
}
impl Default for CameraBounds {
fn default() -> Self {
Self {
min: Vec2::ZERO,
max: Vec2::new(1000.0, 1000.0),
padding: 0.0,
}
}
}
impl CameraBounds {
pub fn from_level(width: u32, height: u32, tile_size: f32) -> Self {
Self {
min: Vec2::ZERO,
max: Vec2::new(width as f32 * tile_size, height as f32 * tile_size),
padding: 0.0,
}
}
pub fn with_padding(mut self, padding: f32) -> Self {
self.padding = padding;
self
}
}
pub fn clamp_camera_to_bounds(
mut cameras: Query<(&mut Transform, &CameraBounds, &Projection), With<Camera2d>>,
) {
for (mut transform, bounds, projection) in cameras.iter_mut() {
let Projection::Orthographic(ortho) = projection else {
continue;
};
let half_width = ortho.area.width() / 2.0;
let half_height = ortho.area.height() / 2.0;
let min_x = bounds.min.x + half_width + bounds.padding;
let max_x = bounds.max.x - half_width - bounds.padding;
let min_y = bounds.min.y + half_height + bounds.padding;
let max_y = bounds.max.y - half_height - bounds.padding;
if max_x > min_x {
transform.translation.x = transform.translation.x.clamp(min_x, max_x);
} else {
transform.translation.x = (bounds.min.x + bounds.max.x) / 2.0;
}
if max_y > min_y {
transform.translation.y = transform.translation.y.clamp(min_y, max_y);
} else {
transform.translation.y = (bounds.min.y + bounds.max.y) / 2.0;
}
}
}
pub fn setup_camera_bounds_from_map(
mut commands: Commands,
map_query: Query<&MapRoot, Added<MapRoot>>,
map_assets: Res<Assets<MapProject>>,
camera_query: Query<Entity, (With<Camera2d>, Without<CameraBounds>)>,
) {
for map_root in map_query.iter() {
let Some(project) = map_assets.get(&map_root.handle) else {
continue;
};
let level = &project.level;
let tile_size = map_root.textures.tile_size;
for camera_entity in camera_query.iter() {
commands
.entity(camera_entity)
.insert(CameraBounds::from_level(
level.width,
level.height,
tile_size,
));
info!(
"Set camera bounds to {}x{} pixels ({}x{} tiles)",
level.width as f32 * tile_size,
level.height as f32 * tile_size,
level.width,
level.height
);
}
}
}