16 #include "aiBehaviors.h" 18 static const float _PI = 3.14;
20 AIBehaviors::AIBehaviors() {
21 _steering_force =
LVecBase3(0.0, 0.0, 0.0);
22 _behaviors_flags = _behaviors_flags & _none;
23 _previous_conflict =
false;
33 _path_follow_obj = NULL;
34 _path_find_obj = NULL;
35 _obstacle_avoidance_obj = NULL;
47 AIBehaviors::~AIBehaviors() {
64 if(_previous_conflict ==
false) {
66 _seek_force *= _seek_obj->_seek_weight;
72 _flee_force = _steering_force.
length() * dirn * _flee_obj->_flee_weight;
76 _pursue_force *= _pursue_obj->_pursue_weight;
82 _evade_force = _steering_force.
length() * dirn * _evade_obj->_evade_weight;
90 _wander_force *= _wander_obj->_wander_weight;
93 _previous_conflict =
true;
101 _previous_conflict =
false;
118 if(force_type ==
"seek") {
119 old_force = _seek_force;
120 _seek_force = old_force + force;
123 if(force_type ==
"flee") {
124 old_force = _flee_force;
125 _flee_force = old_force + force;
128 if(force_type ==
"pursue") {
129 old_force = _pursue_force;
131 _pursue_force = new_force * _pursue_obj->_pursue_direction;
134 if(force_type ==
"evade") {
135 old_force = _evade_force;
138 _evade_force = new_force * force;
141 if(force_type ==
"arrival") {
142 _arrival_force = force;
145 if(force_type ==
"flock") {
146 old_force = _flock_force;
147 _flock_force = old_force + force;
150 if(force_type ==
"wander") {
151 old_force = _wander_force;
152 _wander_force = old_force + force;
155 if(force_type ==
"obstacle_avoidance") {
156 old_force = _obstacle_avoidance_force;
157 _obstacle_avoidance_force = old_force +force;
177 force = _seek_obj->
do_seek() * _seek_obj->_seek_weight;
185 if(
is_on(_flee_activate)) {
187 _flee_itr->flee_activate();
193 if(_flee_itr->_flee_activate_done) {
195 force = _flee_itr->do_flee() * _flee_itr->_flee_weight;
198 force = _flee_itr->do_flee();
207 force = _pursue_obj->
do_pursue() * _pursue_obj->_pursue_weight;
215 if(
is_on(_evade_activate)) {
217 _evade_itr->evade_activate();
223 if(_evade_itr->_evade_activate_done) {
225 force = (_evade_itr->do_evade()) * (_evade_itr->_evade_weight);
228 force = _evade_itr->do_evade();
235 if(
is_on(_arrival_activate)) {
239 if(
is_on(_arrival)) {
244 if(
is_on(_flock_activate)) {
260 force = _wander_obj->
do_wander() * _wander_obj->_wander_weight;
268 if(
is_on(_obstacle_avoidance_activate)) {
272 if(
is_on(_obstacle_avoidance)) {
282 if(_path_follow_obj!=NULL) {
283 if(_path_follow_obj->_start) {
290 _steering_force += _seek_force * int(
is_on(_seek)) + _flee_force * int(
is_on(_flee)) +
291 _pursue_force * int(
is_on(_pursue)) + _evade_force * int(
is_on(_evade)) +
292 _flock_force * int(
is_on(_flock)) + _wander_force * int(
is_on(_wander)) +
293 _obstacle_avoidance_force * int(
is_on(_obstacle_avoidance));
295 if(_steering_force.
length() > _ai_char->get_max_force()) {
297 _steering_force = _steering_force * _ai_char->get_max_force();
300 if(
is_on(_arrival)) {
301 if(_seek_obj != NULL) {
304 _steering_force = ((_steering_force.
length() - _arrival_force.
length()) * dirn);
307 if(_pursue_obj != NULL) {
310 _steering_force = ((_steering_force.
length() - _arrival_force.
length()) * _arrival_obj->_arrival_direction);
313 return _steering_force;
340 if(_seek_obj != NULL) {
358 if(_pursue_obj != NULL) {
376 if(_arrival_obj != NULL) {
386 if(_flock_group != NULL) {
395 if(_wander_obj != NULL) {
404 if(_obstacle_avoidance_obj !=NULL) {
406 delete _obstacle_avoidance_obj;
407 _obstacle_avoidance_obj = NULL;
413 if(_pursue_obj != NULL && _path_follow_obj != NULL) {
417 delete _path_follow_obj;
418 _path_follow_obj = NULL;
423 if(_pursue_obj != NULL && _path_follow_obj != NULL) {
427 delete _path_follow_obj;
428 _path_follow_obj = NULL;
433 cout<<
"Invalid option!"<<endl;
461 if(_seek_obj != NULL) {
476 if(_pursue_obj != NULL) {
491 if(_arrival_obj != NULL) {
499 if(_flock_group != NULL) {
507 if(_wander_obj != NULL) {
514 if(_obstacle_avoidance_obj != NULL) {
516 turn_off(
"obstacle_avoidance_activate");
522 if(_pursue_obj != NULL && _path_follow_obj != NULL) {
524 _path_follow_obj->_start =
false;
529 if(_pursue_obj != NULL && _path_follow_obj != NULL) {
531 _path_follow_obj->_start =
false;
536 cout<<
"Invalid option!"<<endl;
563 if(_seek_obj != NULL) {
577 if(_pursue_obj != NULL) {
591 if(_arrival_obj != NULL) {
598 if(_flock_group != NULL) {
605 if(_wander_obj != NULL) {
612 if(_obstacle_avoidance_obj != NULL) {
619 if(_pursue_obj != NULL && _path_follow_obj != NULL) {
621 _path_follow_obj->_start =
true;
626 if(_pursue_obj != NULL && _path_follow_obj != NULL) {
628 _path_follow_obj->_start =
false;
633 cout<<
"Invalid option!"<<endl;
647 _seek_obj =
new Seek(_ai_char, target_object, seek_wt);
652 _seek_obj =
new Seek(_ai_char, pos, seek_wt);
665 _flee_obj =
new Flee(_ai_char, target_object, panic_distance, relax_distance, flee_wt);
672 _flee_obj =
new Flee(_ai_char, pos, panic_distance, relax_distance, flee_wt);
687 _pursue_obj =
new Pursue(_ai_char, target_object, pursue_wt);
700 _evade_obj =
new Evade(_ai_char, target_object, panic_distance, relax_distance, evade_wt);
716 _arrival_obj =
new Arrival(_ai_char, distance);
717 _arrival_obj->_arrival_type =
true;
721 _arrival_obj =
new Arrival(_ai_char, distance);
722 _arrival_obj->_arrival_type =
false;
726 cout<<
"Note: A Seek or Pursue behavior is required to use Arrival behavior."<<endl;
775 unsigned int neighbor_count = 0;
785 for(
unsigned int i = 0; i < _flock_group->_ai_char_list.size(); i++) {
786 if(_flock_group->_ai_char_list[i]->_name != _ai_char->_name) {
789 LVecBase3 dist_vect = _flock_group->_ai_char_list[i]->_ai_char_np.get_pos() - _ai_char->_ai_char_np.
get_pos();
790 LVecBase3 ai_char_heading = _ai_char->get_velocity();
794 if(dist_vect.dot(ai_char_heading) > ((dist_vect.
length()) * (ai_char_heading.
length()) * cos(_flock_group->_flock_vcone_angle * (_PI / 180)))
795 && (dist_vect.
length() < _flock_group->_flock_vcone_radius)) {
797 LVecBase3 ai_char_to_units = _ai_char->_ai_char_np.
get_pos() - _flock_group->_ai_char_list[i]->_ai_char_np.get_pos();
798 float to_units_dist = ai_char_to_units.
length();
800 separation_force += (ai_char_to_units / to_units_dist);
803 LVecBase3 neighbor_heading = _flock_group->_ai_char_list[i]->get_velocity();
805 total_neighbor_heading += neighbor_heading;
806 total_center_of_mass += _flock_group->_ai_char_list[i]->_ai_char_np.get_pos();
814 if(neighbor_count > 0) {
816 avg_neighbor_heading = total_neighbor_heading / neighbor_count;
817 LVector3 ai_char_heading = _ai_char->get_velocity();
819 avg_neighbor_heading -= ai_char_heading;
821 alignment_force = avg_neighbor_heading;
824 avg_center_of_mass = total_center_of_mass / neighbor_count;
825 LVecBase3 cohesion_dir = avg_center_of_mass - _ai_char->_ai_char_np.
get_pos();
827 cohesion_force = cohesion_dir * _ai_char->_movt_force;
838 return (separation_force * _flock_group->_separation_wt + avg_neighbor_heading * _flock_group->_alignment_wt
839 + cohesion_force * _flock_group->_cohesion_wt);
851 _wander_obj =
new Wander(_ai_char, wander_radius, flag, aoe, wander_weight);
865 _obstacle_avoidance_obj =
new ObstacleAvoidance(_ai_char, obstacle_avoidance_weight);
866 turn_on(
"obstacle_avoidance_activate");
878 _path_follow_obj =
new PathFollow(_ai_char, follow_wt);
900 _path_follow_obj->
start(type);
913 _path_find_obj =
new PathFind(_ai_char);
985 if(_seek_obj->_seek_done) {
1001 if(_flee_itr->_flee_done ==
true) {
1023 if(
is_on(_pursue)) {
1024 if(_pursue_obj->_pursue_done) {
1045 if(_evade_itr->_evade_done ==
true) {
1067 if(
is_on(_arrival)) {
1068 if(_arrival_obj->_arrival_done) {
1106 if(
is_on(_wander)) {
1119 if(_obstacle_avoidance_obj) {
1120 if(
is_on(_obstacle_avoidance)) {
1133 if(_path_follow_obj) {
1134 if(
is_on(
"pathfollow")) {
1135 if(_pursue_obj->_pursue_done) {
1152 if(_path_find_obj) {
1153 if(
is_on(
"pathfind")) {
1154 if(_pursue_obj->_pursue_done) {
1171 if(_seek_obj || _flee_obj || _pursue_obj || _evade_obj || _arrival_obj || _flock_group || _wander_obj || _obstacle_avoidance_obj || _path_follow_obj) {
1173 ||
is_on(_obstacle_avoidance) ||
is_on(
"pathfollow") ||
is_on(
"pathfinding")) {
1186 cout<<
"Invalid value!"<<endl;
1200 if(ai_type ==
"all") {
1203 else if(ai_type ==
"seek") {
1206 else if(ai_type ==
"flee") {
1209 else if(ai_type ==
"pursue") {
1212 else if(ai_type ==
"evade") {
1215 else if(ai_type ==
"arrival") {
1218 else if(ai_type ==
"flock") {
1221 else if(ai_type ==
"wander") {
1224 else if(ai_type ==
"obstacle_avoidance") {
1227 else if(ai_type ==
"pathfollow") {
1230 else if(ai_type ==
"any") {
1233 else if(ai_type ==
"flee_activate") {
1236 else if(ai_type ==
"evade_activate") {
1239 else if(ai_type ==
"arrival_activate") {
1242 else if(ai_type ==
"flock_activate") {
1245 else if(ai_type ==
"obstacle_avoidance_activate") {
1248 else if(ai_type ==
"path_finding") {
1265 _behaviors_flags |= _seek;
1269 _behaviors_flags |= _flee;
1273 _behaviors_flags |= _pursue;
1277 _behaviors_flags |= _evade;
1281 _behaviors_flags |= _arrival;
1285 _behaviors_flags |= _flock;
1289 _behaviors_flags |= _wander;
1293 _behaviors_flags |= _obstacle_avoidance;
1297 _behaviors_flags |= _flee_activate;
1301 _behaviors_flags |= _evade_activate;
1305 _behaviors_flags |= _arrival_activate;
1309 _behaviors_flags |= _flock_activate;
1313 _behaviors_flags |= _obstacle_avoidance_activate;
1317 cout<<
"Invalid option!"<<endl;
1332 _behaviors_flags ^= _seek;
1334 _seek_force =
LVecBase3(0.0f, 0.0f, 0.0f);
1339 _behaviors_flags ^= _flee;
1341 _flee_force =
LVecBase3(0.0f, 0.0f, 0.0f);
1345 if(
is_on(_pursue)) {
1346 _behaviors_flags ^= _pursue;
1348 _pursue_force =
LVecBase3(0.0f, 0.0f, 0.0f);
1353 _behaviors_flags ^= _evade;
1355 _evade_force =
LVecBase3(0.0f, 0.0f, 0.0f);
1359 if (
is_on(_arrival)) {
1360 _behaviors_flags ^= _arrival;
1362 _arrival_force =
LVecBase3(0.0f, 0.0f, 0.0f);
1367 _behaviors_flags ^= _flock;
1369 _flock_force =
LVecBase3(0.0f, 0.0f, 0.0f);
1373 if(
is_on(_wander)) {
1374 _behaviors_flags ^= _wander;
1376 _wander_force =
LVecBase3(0.0f, 0.0f, 0.0f);
1380 if(
is_on(_obstacle_avoidance)) {
1381 _behaviors_flags ^= _obstacle_avoidance;
1383 _obstacle_avoidance_force =
LVecBase3(0.0f, 0.0f, 0.0f);
1391 if (
is_on(_flee_activate)) {
1392 _behaviors_flags ^= _flee_activate;
1397 if (
is_on(_evade_activate)) {
1398 _behaviors_flags ^= _evade_activate;
1403 if (
is_on(_arrival_activate)) {
1404 _behaviors_flags ^= _arrival_activate;
1409 if (
is_on(_flock_activate)) {
1410 _behaviors_flags ^= _flock_activate;
1415 if (
is_on(_obstacle_avoidance_activate)) {
1416 _behaviors_flags ^= _obstacle_avoidance_activate;
1425 cout<<
"Invalid option!"<<endl;
1437 return (_behaviors_flags & bt) == bt;
1448 if(ai_type ==
"pathfollow") {
1449 if(_path_follow_obj) {
1450 return (
is_on(_pursue) && _path_follow_obj->_start);
1457 if(ai_type ==
"pathfinding") {
1458 if(_path_follow_obj && _path_find_obj) {
1459 return (
is_on(_pursue) && _path_follow_obj->_start);
1477 return ((_behaviors_flags | bt) == bt);
1488 if(ai_type ==
"pathfollow") {
1489 if(_path_follow_obj && _path_follow_obj->_start) {
1497 if(ai_type ==
"pathfinding") {
1498 if(_path_find_obj && _path_follow_obj && _path_follow_obj->_start) {
1506 cout<<
"You passed an invalid string, defaulting return value to false!"<<endl;
string behavior_status(string ai_type)
This function returns the status of an AI Type whether it is active, paused or disabled.
void pause_ai(string ai_type)
This function pauses individual or all the AIs.
void arrival(double distance=10.0)
This function activates arrival.
void add_to_path(LVecBase3 pos)
This function adds positions to the path to follow.
This is the base class for all three-component vectors and points.
LVecBase3 calculate_prioritized()
This function updates the main steering force for the ai character using the accumulate function and ...
bool is_off(_behavior_type bt)
This function returns true if an aiBehavior is off.
void dynamic_avoid(NodePath obstacle)
This function starts the pathfinding obstacle navigation for the passed in obstacle.
void start(string type)
This function initiates the path follow behavior.
void do_follow()
This function allows continuous path finding by ai chars.
void flock(float flock_wt)
This function activates flock.
float _flock_weight
Since Flock is a collective behavior the variables are declared within the AIBehaviors class...
void evade(NodePath target_object, double panic_distance=10.0, double relax_distance=10.0, float evade_wt=1.0)
This function activates evade_activate.
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
void init_path_find(const char *navmesh_filename)
This function activates path finding in the character.
void add_to_path(LVecBase3 pos)
This function adds the positions generated from a pathfind or a simple path follow behavior to the _p...
bool is_conflict()
Checks for conflict between steering forces.
void add_dynamic_obstacle(NodePath obstacle)
This function starts the pathfinding obstacle navigation for the passed in obstacle.
int char_to_int(string ai_type)
This function is used to derive int values from the ai types strings.
LVecBase3 do_arrival()
This function performs the arrival and returns an arrival force which is used in the calculate_priori...
ListEvade _evade_list
This list is used if the ai character needs to evade from multiple onjects.
LVecBase3 do_flock()
This function contains the logic for flocking behavior.
void add_static_obstacle(NodePath obstacle)
This function allows the user to dynamically add obstacles to the game environment.
void add_obstacle_to_mesh(NodePath obstacle)
This function allows the user to dynamically add obstacles to the game environment.
void turn_off(string ai_type)
This function turns off any aiBehavior which is passed as a string.
void wander(double wander_radius=5.0, int flag=0, double aoe=0.0, float wander_weight=1.0)
This function activates wander.
This class contains all the members and functions that are required to form an interface between the ...
void flee(NodePath target_object, double panic_distance=10.0, double relax_distance=10.0, float flee_wt=1.0)
This function activates flee_activate and creates an object of the Flee class.
void path_find(LVecBase3 pos, string type="normal")
This function checks for the source and target in the navigation mesh for its availability and then f...
void remove_ai(string ai_type)
This function removes individual or all the AIs.
LPoint3 get_pos() const
Retrieves the translation component of the transform.
void turn_on(string ai_type)
This function turns on any aiBehavior which is passed as a string.
void obstacle_avoidance_activate()
This function activates obstacle_avoidance if a obstacle is detected.
float length() const
Returns the length of the vector, by the Pythagorean theorem.
bool is_on(_behavior_type bt)
This function returns true if an aiBehavior is on.
void accumulate_force(string force_type, LVecBase3 force)
This function updates the individual steering forces for each of the ai characters.
void path_follow(float follow_wt)
This function activates path following.
void start_follow(string type="normal")
This function starts the path follower.
void obstacle_avoidance(float feeler_length=1.0)
This function activates obstacle avoidance for a given character.
void seek(NodePath target_object, float seek_wt=1.0)
This function activates seek and makes an object of the Seek class.
LVecBase3 do_pursue()
This function performs the pursue and returns a pursue force which is used in the calculate_prioritiz...
void path_find_to(LVecBase3 pos, string type="normal")
This function checks for the source and target in the navigation mesh for its availability and then f...
void flock_activate()
This function checks whether any other behavior exists to work with flock.
LVecBase3 do_wander()
This function performs the wander and returns the wander force which is used in the calculate_priorit...
bool normalize()
Normalizes the vector in place.
LVecBase3 do_obstacle_avoidance()
This function returns the force necessary by the AICharacter to avoid the nearest obstacle detected b...
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
LVecBase3 do_seek()
This function performs the seek and returns a seek force which is used in the calculate_prioritized f...
void set_path_find(const char *navmesh_filename)
This function starts the path finding process after reading the given navigation mesh.
ListFlee _flee_list
This list is used if the ai character needs to flee from multiple onjects.
void pursue(NodePath target_object, float pursue_wt=1.0)
This function activates pursue.
void resume_ai(string ai_type)
This function resumes individual or all the AIs.
void arrival_activate()
This function checks for whether the target is within the arrival distance.