use bevy::app::App; use bevy::math::{Vec2, Vec3Swizzles}; use bevy::prelude::{ Camera2dBundle, Commands, Component, CoreStage, Entity, Plugin, Query, Transform, With, }; use iyes_loopless::prelude::AppLooplessStateExt; use crate::system::flow::AppState; /// 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) { commands .spawn_bundle(Camera2dBundle::default()) .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); } }