this repo has no description
at main 135 lines 4.1 kB view raw
1use bevy::prelude::*; 2use bevy_bae::prelude::*; 3use fake::{Fake, locales::EN}; 4 5use crate::{ 6 berries::{Berry, NewBerry}, 7 sample_arena, 8}; 9 10const SPEED: f32 = 100.0; 11 12pub fn ghost_plugin(app: &mut App) { 13 app.add_systems(Startup, setup); 14} 15 16#[derive(Component)] 17pub struct Ghost; 18 19pub fn setup(mut commands: Commands, asset_server: Res<AssetServer>) { 20 commands.spawn(Camera2d); 21 let mut rng = rand::rng(); 22 23 commands.spawn(( 24 Sprite::from_image(asset_server.load("arena.png")), 25 Transform::from_scale(Vec2::splat(18.0).extend(0.0)), 26 )); 27 28 for _ in 1..100 { 29 commands.spawn(( 30 Plan::new(), 31 Ghost, 32 BerriesEaten(0), 33 Name::new(fake::faker::name::raw::FirstName(EN).fake::<String>()), 34 Sprite::from_image(asset_server.load("ghost.png")), 35 Sequence, 36 tasks!( 37 Operator::new(find_closest_berry), 38 Operator::new(go_to_berry), 39 Operator::new(collect_berry) 40 ), 41 Transform::from_translation(sample_arena(&mut rng).extend(0.1)), 42 )); 43 } 44} 45 46#[derive(Component)] 47#[relationship(relationship_target = TargetedBerry)] 48pub struct TargetBerry(pub Entity); 49 50#[derive(Component)] 51#[relationship_target(relationship = TargetBerry)] 52pub struct TargetedBerry(Entity); 53 54#[derive(Component)] 55pub struct BerriesEaten(pub usize); 56 57fn find_closest_berry( 58 In(input): In<OperatorInput>, 59 mut commands: Commands, 60 berries: Query<(Entity, &Transform), (With<Berry>, Without<TargetedBerry>)>, 61 ghosts: Query<&Transform, With<Ghost>>, 62) -> OperatorStatus { 63 let pos = ghosts.get(input.entity).unwrap().translation.xy(); 64 let mut closest: Option<Entity> = None; 65 let mut closest_dist = 0.0; 66 for (entity, transform) in berries { 67 let dist = transform.translation.xy().distance_squared(pos); 68 if closest.is_none() || dist < closest_dist { 69 closest = Some(entity); 70 closest_dist = dist; 71 } 72 } 73 74 if let Some(entity) = closest { 75 commands.entity(input.entity).insert(TargetBerry(entity)); 76 return OperatorStatus::Success; 77 } 78 OperatorStatus::Ongoing 79} 80 81fn go_to_berry( 82 In(input): In<OperatorInput>, 83 mut ghosts: Query<(&mut Transform, &TargetBerry, &BerriesEaten), With<Ghost>>, 84 berries: Query<&Transform, (With<Berry>, Without<Ghost>)>, 85 new_berries: Query<&Transform, (With<Berry>, Without<TargetedBerry>, Without<Ghost>)>, 86 time: Res<Time>, 87 mut news: MessageReader<NewBerry>, 88 mut commands: Commands, 89) -> Result<OperatorStatus> { 90 let (mut trans, target_entity, eaten) = ghosts.get_mut(input.entity)?; 91 92 let target = berries.get(target_entity.0)?; 93 94 for new in news.read() { 95 let Ok(new_trans) = new_berries.get(new.0) else { 96 continue; 97 }; 98 99 if (new_trans 100 .translation 101 .xy() 102 .distance_squared(trans.translation.xy()) 103 - target 104 .translation 105 .xy() 106 .distance_squared(trans.translation.xy())) 107 < 30.0 108 { 109 commands.entity(input.entity).insert(TargetBerry(new.0)); 110 return Ok(OperatorStatus::Ongoing); 111 } 112 } 113 114 let dir = (target.translation.xy() - trans.translation.xy()).normalize(); 115 let mov = dir * (SPEED * (1.0 + (eaten.0 as f32 + 1.0).log10())) * time.delta_secs(); 116 if (target.translation.xy() - (trans.translation.xy() + mov)).length() < mov.length() { 117 trans.translation = target.translation; 118 return Ok(OperatorStatus::Success); 119 } 120 trans.translation += mov.extend(0.0); 121 122 Ok(OperatorStatus::Ongoing) 123} 124 125fn collect_berry( 126 In(input): In<OperatorInput>, 127 mut ghosts: Query<(&TargetBerry, &mut BerriesEaten), With<Ghost>>, 128 mut commands: Commands, 129) -> Result<OperatorStatus> { 130 let (berry, mut eaten) = ghosts.get_mut(input.entity)?; 131 eaten.0 += 1; 132 commands.entity(berry.0).despawn(); 133 commands.entity(input.entity).remove::<TargetBerry>(); 134 Ok(OperatorStatus::Success) 135}