use bevy::{color::palettes::css::*, prelude::*, time::common_conditions::on_timer}; use bevy_dogoap::prelude::*; use rand::Rng; use std::{collections::HashMap, time::Duration}; // This is a basic example on how you can use Dogoap while moving your agent around /// This is our marker components, so we can keep track of the various in-game entities #[derive(Component)] struct Cell { speed: f32, age: usize, } #[derive(Component)] struct DeadCell; #[derive(Component)] struct Food; #[derive(Component)] struct MoveTo(Vec3, Entity); // // Various actions our Cell can perform // // When cell is at food, the cell can consume the food, decreasing hunger #[derive(Component, Clone, Reflect, Default, ActionComponent)] struct EatAction; // When we're not hungry, our cell can replicate itself #[derive(Component, Clone, Reflect, Default, ActionComponent)] struct ReplicateAction; // This will make the cell seek out the closest food #[derive(Component, Clone, Reflect, Default, ActionComponent)] struct GoToFoodAction; // // All of our State fields // #[derive(Component, Clone, DatumComponent)] struct Hunger(f64); #[derive(Component, Clone, DatumComponent)] struct AtFood(bool); #[derive(Component, Clone, DatumComponent)] struct IsReplicating(bool); // UI elements #[derive(Component)] struct StateDebugText; fn spawn_cell(commands: &mut Commands, position: Vec3, speed: f32) { let goal = Goal::from_reqs(&[IsReplicating::is(true)]); let eat_action = EatAction::new() .add_precondition(AtFood::is(true)) .add_mutator(Hunger::decrease(10.0)) .add_mutator(AtFood::set(true)) .set_cost(1); let replicate_action = ReplicateAction::new() .add_precondition(Hunger::is_less(10.0)) .add_mutator(IsReplicating::set(true)) .add_mutator(Hunger::increase(25.0)) .set_cost(10); let go_to_food_action = GoToFoodAction::new() .add_precondition(AtFood::is(false)) .add_mutator(AtFood::set(true)) .add_mutator(Hunger::increase(1.0)) .set_cost(2); let mut rng = rand::thread_rng(); let starting_hunger = rng.gen_range(20.0..45.0); let (mut planner, components) = create_planner!({ actions: [ (EatAction, eat_action), (GoToFoodAction, go_to_food_action), (ReplicateAction, replicate_action) ], state: [Hunger(starting_hunger), AtFood(false), IsReplicating(false)], goals: [goal], }); planner.remove_goal_on_no_plan_found = false; // Don't remove the goal planner.always_plan = true; // Re-calculate our plan whenever we can planner.current_goal = Some(goal.clone()); let text_style = TextStyle { font_size: 12.0, ..default() }; commands .spawn(( Name::new("Cell"), Cell { speed, age: 0 }, planner, components, Transform::from_translation(position), GlobalTransform::from_translation(position), InheritedVisibility::default(), )) .with_children(|subcommands| { subcommands.spawn(( Text2dBundle { transform: Transform::from_translation(Vec3::new(10.0, -10.0, 10.0)), text: Text::from_section("", text_style.clone()) .with_justify(JustifyText::Left), text_anchor: bevy::sprite::Anchor::TopLeft, ..default() }, StateDebugText, )); }); } fn startup(mut commands: Commands, windows: Query<&Window>) { let window = windows.get_single().expect("Expected only one window! Wth"); let window_height = window.height() / 2.0; let window_width = window.width() / 2.0; let mut rng = rand::thread_rng(); for _i in 0..1 { let y = rng.gen_range(-window_height..window_height); let x = rng.gen_range(-window_width..window_width); spawn_cell(&mut commands, Vec3::from_array([x, y, 1.0]), 128.0); } // Begin with three food for _i in 0..30 { let y = rng.gen_range(-window_height..window_height); let x = rng.gen_range(-window_width..window_width); commands.spawn(( Name::new("Food"), Food, Transform::from_translation(Vec3::new(x, y, 0.0)), )); } // Misc stuff we want somewhere commands.spawn(Camera2dBundle::default()); } fn spawn_random_food( windows: Query<&Window>, mut commands: Commands, q_food: Query>, ) { let window = windows.get_single().expect("Expected only one window! Wth"); let window_height = window.height() / 2.0; let window_width = window.width() / 2.0; if q_food.iter().len() < 100 { let mut rng = rand::thread_rng(); let y = rng.gen_range(-window_height..window_height); let x = rng.gen_range(-window_width..window_width); commands.spawn(( Name::new("Food"), Food, Transform::from_translation(Vec3::new(x, y, 0.0)), )); } } fn handle_move_to( mut commands: Commands, time: Res