use bevy::{
ecs::system::SystemParam,
prelude::*,
};
pub struct CameraSpotPlugin;
impl Plugin for CameraSpotPlugin {
fn build(&self, app: &mut App) {
app .register_type::<CurrentSpot>()
.register_type::<Option<CameraSpot>>()
.register_type::<CameraSpot>()
.register_type::<IsCameraSpot>()
.init_resource::<CurrentSpot>();
}
}
#[derive(Resource, Default, Debug, Reflect)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[reflect(Resource)]
pub struct CurrentSpot {
spot: Option<CameraSpot>,
}
impl CurrentSpot {
pub fn new(spot: CameraSpot) -> Self {
Self { spot: Some(spot) }
}
pub fn get(&self) -> &CameraSpot {
self.spot.as_ref().unwrap()
}
pub fn name(&self) -> &str {
self.get().name()
}
pub fn is_some(&self) -> bool {
self.spot.is_some()
}
}
#[derive(Debug, Reflect)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CameraSpot {
name: String,
entity: Entity,
transform: Transform,
}
impl CameraSpot {
pub fn new(name: &str, entity: Entity, transform: Transform) -> Self {
Self {
name: name.to_owned(),
entity,
transform,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn entity(&self) -> Entity {
self.entity
}
pub fn set_entity(&mut self, entity: Entity) {
self.entity = entity;
}
pub fn transform(&self) -> Transform {
self.transform
}
}
#[derive(Component, Debug, Default, Reflect)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[reflect(Component)]
pub struct IsCameraSpot;
#[derive(SystemParam)]
pub struct CameraSpots<'w, 's> {
named: Query<'w, 's, (Entity, &'static Name), Without<IsCameraSpot>>,
spots: Query<'w, 's, (Entity, &'static Name, &'static GlobalTransform), With<IsCameraSpot>>,
}
impl<'w, 's> CameraSpots<'w, 's> {
pub fn get(&self, spot: &str) -> Option<CameraSpot> {
for (entity, spot_name, gtf) in &self.spots {
if spot == spot_name.as_str() {
return Some(CameraSpot::new(spot_name, entity, gtf.compute_transform()));
}
}
None
}
pub fn for_interactive(&self, entity: Entity) -> Option<CameraSpot> {
if let Ok((_, name)) = self.named.get(entity) {
return self.get(format! {"Camera_{name}"}.as_str());
}
None
}
pub fn for_spot(&self, spot: &CameraSpot) -> Option<Entity> {
if let Some((_, target)) = spot.name().split_once("Camera_") {
for (entity, name) in &self.named {
if name.as_str() == target {
return Some(entity);
}
}
}
None
}
}