-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathbevy_basic.rs
119 lines (96 loc) · 4.31 KB
/
bevy_basic.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// This is a really basic example of how to use dogoap with bevy_dogoap for use in Bevy
// It sets up two states on a entity, is_hungry and is_tired
// Then it sets up two possible actions:
// - SleepAction, which sets is_tired to false
// - EatAction, which requires is_tired to be false, and sets is_hungry to true
// We run three app.update() instead of app.run(), then print the final state after
// those three updates, so there is some sort of end to it all...
// Final state should be that is_hungry is false, and is_tired is false
use bevy::{log::LogPlugin, prelude::*};
// bevy_dogoap exposes a `prelude` that contains everything you might need
use bevy_dogoap::prelude::*;
// This is a DatumComponent that can hold one value
#[derive(Component, Clone, DatumComponent)]
struct IsHungry(bool);
#[derive(Component, Clone, DatumComponent)]
struct IsTired(bool);
// This is our ActionComponent that gets added whenever the planner thinks
// the entity need to perform the action in order to reach the goal
#[derive(Component, Reflect, Clone, Default, ActionComponent)]
struct EatAction;
#[derive(Component, Reflect, Clone, Default, ActionComponent)]
struct SleepAction;
fn startup(mut commands: Commands) {
// This is the goal we want the planner to help us reach
let goal = Goal::from_reqs(&[IsHungry::is(false), IsTired::is(false)]);
// Our first action, the eat action, that sets is_hungry to false
// but requires is_tired to be set to false first
let eat_action = EatAction::new()
.add_precondition(IsTired::is(false))
.add_mutator(IsHungry::set(false));
// Our first action, the sleep action, that sets is_tired to false
// No preconditions in order to sleep
let sleep_action = SleepAction::new().add_mutator(IsTired::set(false));
// This create_planner! macro doesn't yet exists
let (planner, components) = create_planner!({
actions: [
(EatAction, eat_action),
(SleepAction, sleep_action)
],
state: [IsHungry(true), IsTired(true)],
goals: [goal],
});
// To spawn the planner, we first create a new entity
// You can also use an existing entity if you have one at hand
// This will usually be whatever Entity you use for your NPC
commands.spawn((Name::new("Planner"), planner, components));
}
// These two systems are regular Bevy systems. Looks for Entities that have
// both EatAction and IsHungry, and when it finds one, replace the IsHungry
// component with one that says `false`
fn handle_eat_action(
mut commands: Commands,
mut query: Query<(Entity, &EatAction, &mut IsHungry)>,
) {
for (entity, _eat_action, mut need) in query.iter_mut() {
*need = IsHungry(false);
commands.entity(entity).remove::<EatAction>();
info!("IsHungry been set to false and removed EatAction");
}
}
// Same goes for the sleep_action, but with SleepAction and IsTired
fn handle_sleep_action(
mut commands: Commands,
mut query: Query<(Entity, &SleepAction, &mut IsTired)>,
) {
for (entity, _sleep_action, mut need) in query.iter_mut() {
*need = IsTired(false);
commands.entity(entity).remove::<SleepAction>();
info!("IsTired been set to false and removed SleepAction");
}
}
fn main() {
let mut app = App::new();
app.add_plugins(MinimalPlugins);
// Make sure to include the DogoapPlugin which manages the planner for us
app.add_plugins(DogoapPlugin);
// We configure the logplugin to output debug info for both dogoap and bevy_dogoap
app.add_plugins(LogPlugin {
filter: "dogoap=debug,bevy_dogoap=debug".to_string(),
..default()
});
// We need to register our components as DatumComponent, otherwise planner won't be able to find them
register_components!(app, vec![IsHungry, IsTired]);
app.add_systems(Startup, startup);
app.add_systems(Update, (handle_eat_action, handle_sleep_action));
// Run three frames to advance
for _i in 0..3 {
app.update();
}
// Lets inspect the final state of our (one) Planner we have in the World
let mut query = app.world_mut().query::<&Planner>();
let planner = query.get_single(&app.world()).unwrap();
// This should confirm that is_hungry and is_tired have been set to `false`
println!("Final state in our planner:");
println!("{:#?}", planner.state);
}