use crate::camera::MainCamera; use bevy::prelude::*; use bevy_sprite3d::Sprite3dPlugin; #[derive(Component, Reflect, Default, PartialEq, Eq)] #[reflect(Component)] pub enum Billboard { #[default] All, XZ, } pub fn plugin(app: &mut App) { if !app.is_plugin_added::() { app.add_plugins(Sprite3dPlugin); } app.register_type::(); app.add_systems(Update, (face_camera, face_camera_no_parent)); } fn face_camera( cam_query: Query<&GlobalTransform, With>, mut query: Query< (&mut Transform, &ChildOf, &InheritedVisibility, &Billboard), Without, >, parent_transform: Query<&GlobalTransform>, ) { let Ok(cam_transform) = cam_query.single() else { return; }; for (mut transform, parent, visible, billboard) in query.iter_mut() { if !matches!(*visible, InheritedVisibility::VISIBLE) { continue; } let Ok(parent_global) = parent_transform.get(parent.parent()) else { continue; }; let target = cam_transform.reparented_to(parent_global); let target = match *billboard { Billboard::All => target.translation, Billboard::XZ => Vec3::new( target.translation.x, transform.translation.y, target.translation.z, ), }; transform.look_at(target, Vec3::Y); } } fn face_camera_no_parent( cam_query: Query<&GlobalTransform, With>, mut query: Query<(&mut Transform, &Billboard), (Without, Without)>, ) { let Ok(cam_transform) = cam_query.single() else { return; }; for (mut transform, billboard) in query.iter_mut() { let target = cam_transform.translation(); let target = match *billboard { Billboard::All => cam_transform.translation(), Billboard::XZ => Vec3::new(target.x, transform.translation.y, target.z), }; transform.look_at(target, Vec3::Y); } }