Newer
Older
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
`big-brain` is a [Utility AI](https://en.wikipedia.org/wiki/Utility_system)
library for games, built on the [`specs` ECS](https://docs.rs/specs).
It lets you define complex, intricate AI behaviors for your entities based on
their perception of the world. Definitions are almost entirely data-driven,
using plain `.ron` files, and you only need to program considerations
(entities that look at your game world), and actions (entities that perform
actual behaviors upon the world). No other code is needed for actual AI
behavior.
See [the documentation](https://docs.rs/big-brain) for more details.
## Example
First, you define actions and considerations, which are just plain old `specs`
`Component`s and `System`s.
### Considerations
`Consideration`s are entities that look at the world and evaluate into `Utility`s.
```rust
use specs::{Component, Entity, ReadStorage, System, WriteStorage};
use big_brain::{Consideration, Utility};
use crate::components;
#[derive(Debug, Component, Consideration)]
pub struct Hunger {
pub actor: Entity,
#[consideration(default)]
pub evaluator: PowerEvaluator,
#[consideration(param)]
pub weight: f32,
}
pub struct ConsiderHunger;
impl<'a> System<'a> for ConsiderHunger {
type SystemData = (
ReadStorage<'a, components::Hunger>,
WriteStorage<'a, Hunger>,
WriteStorage<'a, Utility>,
);
fn run(&mut self, (hungers, mut considerers, mut utilities): Self::SystemData) {
for (conser, util) in (&mut considerers, &mut utilities).join() {
if let Some(hunger) = hungers.get(conser.actor.clone()) {
*util = Utility {
value: conser.evaluator.evaluate(hunger.hunger),
weight: conser.weight,
};
}
}
}
}
```
### Actions
`Action`s are the actual things your entities will _do_.
```rust
use specs::{Component, Entity, System, WriteStorage};
use big_brain::{Action, ActionState};
use crate::components;
#[derive(Debug, Clone, Component, Action)]
pub struct Eat {
pub actor: Entity,
#[action(default)]
pub foo: f32,
#[action(param)]
pub reduce_by: f32,
}
pub struct EatSystem;
impl<'a> System<'a> for EatSystem {
type SystemData = (
WriteStorage<'a, components::Hunger>,
WriteStorage<'a, Eat>,
WriteStorage<'a, ActionState>,
);
fn run(&mut self, (mut hungers, mut eat_actions, mut states): Self::SystemData) {
for (state, eat_action) in (&mut states, &mut eat_actions).join() {
if let Some(hunger) = hungers.get_mut(eat_action.actor.clone()) {
match state {
ActionState::Requested => {
hunger.hunger -= eat_action.reduce_by;
*state = ActionState::Success;
}
ActionState::Cancelled => {
*state = ActionState::Failure;
}
_ => {}
}
}
}
}
}
```
### Thinker Definition
Finally, you can define the `Thinker`:
```ron
// behavior.ron
(
picker: {"FirstToScore": (threshold: 80.0)},
otherwise: Some({"Meander": ()}),
choices: [(
consider: [{"Bladder": (weight: 3.0)}],
// Thinkers are infinitely nestable! They're actually Actions themselves.
then: {"Thinker": (
picker: {"FirstToScore": (threshold: 80.0)},
choices: [(
consider: [{"Bladder": (weight: 3.0)}],
then: {"Pee": ()}
)]
)}
), (
consider: [{"Thirst": (weight: 2.0)}],
then: {"Drink": ()},
), (
consider: [{"Hunger": (weight: 2.0)}],
then: {"Eat": ()},
)],
)
```
## License
This project is licensed under [the Parity License](LICENSE.md). Third-party contributions are licensed under Apache-2.0 and belong to their respective authors.
The Parity License is a copyleft license that, unlike the GPL family, allows you to license derivative and connected works under permissive licenses like MIT or Apache-2.0. It's free to use provided the work you do is freely available!
For proprietary use, please [contact me](mailto:kzm@zkat.tech?subject=big-brain%20license), or just [sponsor me on GitHub](https://github.com/users/zkat/sponsorship) under the appropriate tier to [acquire a proprietary-use license](LICENSE-PATRON.md)! This funding model helps me make my work sustainable and compensates me for the work it took to write this crate!