|
use bevy::{
|
|
ecs::{
|
|
bundle::Bundle,
|
|
component::Component,
|
|
entity::Entity,
|
|
system::{ In, Query, Res },
|
|
query::With,
|
|
},
|
|
sprite::SpriteSheetBundle,
|
|
time::Time,
|
|
transform::components::Transform,
|
|
};
|
|
use bevy_ecs_ldtk::{ prelude::LdtkEntity, EntityInstance };
|
|
use seldom_state::{ prelude::StateMachine, trigger::IntoTrigger as _ };
|
|
|
|
use super::{ ColliderBundle, PredefinedPath };
|
|
use crate::components::line_of_sight::LineOfSight;
|
|
|
|
#[derive(Copy, Clone, Eq, PartialEq, Debug, Default, Component)]
|
|
pub struct Enemy;
|
|
|
|
#[derive(Default, Bundle, LdtkEntity)]
|
|
pub struct EnemyBundle {
|
|
#[sprite_sheet_bundle]
|
|
pub sprite_sheet_bundle: SpriteSheetBundle,
|
|
#[from_entity_instance]
|
|
pub collider_bundle: ColliderBundle,
|
|
pub enemy: Enemy,
|
|
#[ldtk_entity]
|
|
pub predefined_path: PredefinedPath,
|
|
pub line_of_sight: LineOfSight<super::player::Player>,
|
|
#[with(make_state_machine)]
|
|
pub state_machine: StateMachine,
|
|
pub state: Idle,
|
|
}
|
|
|
|
|
|
|
|
|
|
fn make_state_machine(_: &EntityInstance) -> StateMachine {
|
|
|
|
let near_player = move |
|
|
In(entity): In<Entity>,
|
|
player_query: Query<(Entity, &Transform), With<super::Player>>,
|
|
transforms: Query<&Transform>
|
|
| {
|
|
let Ok((player, player_transform)) = player_query.get_single() else {
|
|
return Err(f32::INFINITY);
|
|
};
|
|
let distance = player_transform.translation
|
|
.truncate()
|
|
.distance(transforms.get(entity).unwrap().translation.truncate());
|
|
|
|
|
|
match distance <= 300.0 {
|
|
true => Ok((distance, player)),
|
|
false => Err(distance),
|
|
}
|
|
};
|
|
|
|
|
|
|
|
StateMachine::default()
|
|
|
|
|
|
.trans_builder(
|
|
near_player,
|
|
|
|
|_old_state: &Idle, (_distance, target)| {
|
|
Some(Follow {
|
|
target: target,
|
|
speed: 100.0,
|
|
})
|
|
}
|
|
)
|
|
|
|
|
|
|
|
.trans::<Follow, _>(near_player.not(), Idle)
|
|
|
|
.set_trans_logging(true)
|
|
}
|
|
|
|
|
|
#[derive(Clone, Component, Default)]
|
|
#[component(storage = "SparseSet")]
|
|
pub struct Idle;
|
|
|
|
|
|
#[derive(Clone, Component)]
|
|
#[component(storage = "SparseSet")]
|
|
pub struct Follow {
|
|
pub target: Entity,
|
|
pub speed: f32,
|
|
}
|
|
|
|
|
|
|
|
pub fn follow(
|
|
mut transforms: Query<&mut Transform>,
|
|
follows: Query<(Entity, &Follow)>,
|
|
time: Res<Time>
|
|
) {
|
|
for (entity, follow) in &follows {
|
|
|
|
let target_translation = transforms.get(follow.target).unwrap().translation;
|
|
let follow_transform = &mut transforms.get_mut(entity).unwrap();
|
|
let follow_translation = follow_transform.translation;
|
|
|
|
|
|
follow_transform.translation +=
|
|
(target_translation - follow_translation).normalize_or_zero() *
|
|
follow.speed *
|
|
time.delta_seconds();
|
|
}
|
|
}
|
|
|