Skip to content
Snippets Groups Projects
camera.rs 1.98 KiB
Newer Older
Louis's avatar
Louis committed
use bevy::ecs::query::ReadOnlyWorldQuery;
use bevy::ecs::system::SystemParam;
use bevy::prelude::*;

use crate::MapQuery;

pub fn lock_camera_to_level<CameraSelector: ReadOnlyWorldQuery>(
	map_query: MapQuery,
	mut camera_query: Query<(&mut Transform, &OrthographicProjection), CameraSelector>,
) {
	let bounds = match map_query.get_camera_bounds() {
		Some(bounds) => bounds,
		None => return,
	};

	for (mut transform, proj) in &mut camera_query {
		let rect = proj.area;
		let width = rect.width();
		let height = rect.height();
Louis's avatar
Louis committed

		let val_x = bounds
			.get_min_x(width)
			.max(bounds.get_max_x(width).min(transform.translation.x));
		let val_y = bounds
			.get_min_y(height)
			.max(bounds.get_max_y(height).min(transform.translation.y));

		transform.translation = Vec3::new(val_x, val_y, transform.translation.z);
	}
}

#[derive(SystemParam)]
pub struct CameraBounder<'w, 's, Filter: ReadOnlyWorldQuery + 'static> {
	map_query: MapQuery<'w, 's>,
	query: Query<'w, 's, &'static OrthographicProjection, Filter>,
}
impl<'w, 's, Filter: ReadOnlyWorldQuery + 'static> CameraBounder<'w, 's, Filter> {
	pub fn get_extremeties(&self) -> Option<Rect> {
		if let Some(bounds) = self.map_query.get_camera_bounds() {
			if let Ok(proj) = self.query.get_single() {
				let rect = proj.area;
				let width = rect.width();
				let height = rect.height();
Louis's avatar
Louis committed

				Some(Rect::new(
					bounds.get_min_x(width),
					bounds.get_min_y(height),
					bounds.get_max_x(width),
					bounds.get_max_y(height),
				))
			} else {
				None
			}
		} else {
			None
		}
	}
	pub fn bind(&self, point: Vec2) -> Vec2 {
		if let Some(bounds) = self.get_extremeties() {
			bounds.min.max(point).min(bounds.max)
		} else {
			point
		}
	}
}

#[cfg(test)]
mod test {
	use bevy::math::{Rect, Vec2};

	#[test]
	fn min_max_vec() {
		let initial_point = Vec2::new(3.0, 5.0);
		let expected_point = Vec2::new(3.0, 3.0);
		let bounds = Rect::new(1.0, 1.0, 3.0, 3.0);

		assert_eq!(
			expected_point,
			bounds.min.max(initial_point).min(bounds.max)
		);
	}
}