-
Notifications
You must be signed in to change notification settings - Fork 20
Expand file tree
/
Copy pathbevy_basic.rs
More file actions
124 lines (103 loc) · 4.49 KB
/
Copy pathbevy_basic.rs
File metadata and controls
124 lines (103 loc) · 4.49 KB
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
120
121
122
123
124
//! 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 a bunch of `app.update()` instead of `app.run()`, then print the final state after
//! those 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 needs 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::action()
.with_precondition(IsTired::is(false))
.with_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::action().with_mutator(IsTired::set(false));
// Create the planner that
// - registers our actions
// - initializes the state
// - registers our goal(s)
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("NPC"), 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, &mut IsHungry), With<EatAction>>,
) {
for (entity, 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, &mut IsTired), With<SleepAction>>,
) {
for (entity, 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::default());
// 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, [IsHungry, IsTired]);
register_actions!(app, [EatAction, SleepAction]);
app.add_systems(Startup, startup);
app.add_systems(FixedUpdate, (handle_eat_action, handle_sleep_action));
app.finish();
// Run a bunch of frames to advance
for _i in 0..30 {
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.single(app.world()).unwrap();
// This should confirm that is_hungry and is_tired have been set to `false`
info!("Final state in our planner:");
info!("{:#?}", planner.state);
}