Skip to content
Snippets Groups Projects
camera.rs 2.5 KiB
Newer Older
Louis's avatar
Louis committed
use bevy::app::App;
use bevy::math::{Vec2, Vec3Swizzles};
use bevy::prelude::{
Louis's avatar
Louis committed
	Camera2dBundle, Commands, Component, CoreStage, Entity, OrthographicProjection, Plugin, Query,
	Transform, With,
Louis's avatar
Louis committed
};
Louis's avatar
Louis committed
use bevy::render::camera::ScalingMode;
Louis's avatar
Louis committed
use iyes_loopless::prelude::AppLooplessStateExt;

use crate::system::flow::AppState;
Louis's avatar
v2  
Louis committed
use crate::system::load_config::virtual_size;
Louis's avatar
Louis committed

/// A flag component to indicate which entity should be followed by the camera
#[derive(Component)]
pub struct ChaseCam;
/// A flag component to indicate a camera that should be used for rendering world entities and sprites
#[derive(Component)]
pub struct GameCamera;

/// System that creates a default orthographic camera, with correct tags for querying
pub fn spawn_orthographic_camera(mut commands: Commands) {
Louis's avatar
v2  
Louis committed
	let (target_width, target_height) = virtual_size();
Louis's avatar
Louis committed
	commands
Louis's avatar
Louis committed
		.spawn_bundle(Camera2dBundle {
			projection: OrthographicProjection {
				left: -(target_width / 2.0),
				right: (target_width / 2.0),
				top: (target_height / 2.0),
				bottom: -(target_height / 2.0),
				scaling_mode: ScalingMode::Auto {
					min_width: target_width,
					min_height: target_height,
				},
				..Default::default()
			},
			..Default::default()
		})
Louis's avatar
Louis committed
		.insert(GameCamera);
}

/// System that takes the average location of all chase camera entities, and updates the location
/// of all world cameras to track the average location.
///
/// e.g. If a player entity is chased, and a mouse tracking entity is chased, the world cameras will
/// by updated to the midpoint between the player and the mouse
pub fn sync_chase_camera_location(
	mut commands: Commands,
	chased_query: Query<&Transform, With<ChaseCam>>,
	camera_query: Query<(Entity, &Transform), With<GameCamera>>,
) {
	let mut average_location = Vec2::new(0.0, 0.0);
	let mut count = 0;
	for location in chased_query.iter() {
		average_location += location.translation.xy();
		count += 1;
	}

	if count > 0 {
		average_location /= count as f32;
	}

	for (entity, location) in camera_query.iter() {
		commands.entity(entity).insert(Transform {
			translation: average_location.extend(location.translation.z),
			..*location
		});
	}
}

/// A marker struct for spawning and managing cameras. Cameras will be created on startup, and
/// will constantly have their positions synced
pub struct CameraManagementPlugin;

impl Plugin for CameraManagementPlugin {
	fn build(&self, app: &mut App) {
		app.add_enter_system(AppState::Preload, spawn_orthographic_camera)
			.add_system_to_stage(CoreStage::PreUpdate, sync_chase_camera_location);
	}
}