22#include "pathFollow.h"
31static const float _PI = 3.14;
33AIBehaviors::AIBehaviors() {
34 _steering_force = LVecBase3(0.0, 0.0, 0.0);
35 _behaviors_flags = _behaviors_flags & _none;
36 _previous_conflict =
false;
41 _pursue_obj =
nullptr;
43 _arrival_obj =
nullptr;
44 _wander_obj =
nullptr;
45 _flock_group =
nullptr;
46 _path_follow_obj =
nullptr;
47 _path_find_obj =
nullptr;
48 _obstacle_avoidance_obj =
nullptr;
60AIBehaviors::~AIBehaviors() {
73 if(_previous_conflict ==
false) {
75 _seek_force *= _seek_obj->_seek_weight;
79 LVecBase3 dirn = _flee_force;
81 _flee_force = _steering_force.length() * dirn * _flee_obj->_flee_weight;
85 _pursue_force *= _pursue_obj->_pursue_weight;
89 LVecBase3 dirn = _evade_force;
91 _evade_force = _steering_force.length() * dirn * _evade_obj->_evade_weight;
95 _flock_force *= _flock_weight;
99 _wander_force *= _wander_obj->_wander_weight;
102 _previous_conflict =
true;
110 _previous_conflict =
false;
124 if(force_type ==
"seek") {
125 old_force = _seek_force;
126 _seek_force = old_force + force;
129 if(force_type ==
"flee") {
130 old_force = _flee_force;
131 _flee_force = old_force + force;
134 if(force_type ==
"pursue") {
135 old_force = _pursue_force;
136 double new_force = old_force.length() + force.length();
137 _pursue_force = new_force * _pursue_obj->_pursue_direction;
140 if(force_type ==
"evade") {
141 old_force = _evade_force;
142 double new_force = old_force.length() + force.length();
144 _evade_force = new_force * force;
147 if(force_type ==
"arrival") {
148 _arrival_force = force;
151 if(force_type ==
"flock") {
152 old_force = _flock_force;
153 _flock_force = old_force + force;
156 if(force_type ==
"wander") {
157 old_force = _wander_force;
158 _wander_force = old_force + force;
161 if(force_type ==
"obstacle_avoidance") {
162 old_force = _obstacle_avoidance_force;
163 _obstacle_avoidance_force = old_force +force;
180 force = _seek_obj->
do_seek() * _seek_obj->_seek_weight;
188 if(
is_on(_flee_activate)) {
189 for(_flee_itr = _flee_list.begin(); _flee_itr != _flee_list.end(); _flee_itr++) {
190 _flee_itr->flee_activate();
195 for(_flee_itr = _flee_list.begin(); _flee_itr != _flee_list.end(); _flee_itr++) {
196 if(_flee_itr->_flee_activate_done) {
198 force = _flee_itr->do_flee() * _flee_itr->_flee_weight;
201 force = _flee_itr->do_flee();
210 force = _pursue_obj->
do_pursue() * _pursue_obj->_pursue_weight;
218 if(
is_on(_evade_activate)) {
219 for(_evade_itr = _evade_list.begin(); _evade_itr != _evade_list.end(); _evade_itr++) {
220 _evade_itr->evade_activate();
225 for(_evade_itr = _evade_list.begin(); _evade_itr != _evade_list.end(); _evade_itr++) {
226 if(_evade_itr->_evade_activate_done) {
228 force = (_evade_itr->do_evade()) * (_evade_itr->_evade_weight);
231 force = _evade_itr->do_evade();
238 if(
is_on(_arrival_activate)) {
242 if(
is_on(_arrival)) {
247 if(
is_on(_flock_activate)) {
263 force = _wander_obj->
do_wander() * _wander_obj->_wander_weight;
271 if(
is_on(_obstacle_avoidance_activate)) {
275 if(
is_on(_obstacle_avoidance)) {
285 if(_path_follow_obj!=
nullptr) {
286 if(_path_follow_obj->_start) {
293 _steering_force += _seek_force * int(
is_on(_seek)) + _flee_force * int(
is_on(_flee)) +
294 _pursue_force * int(
is_on(_pursue)) + _evade_force * int(
is_on(_evade)) +
295 _flock_force * int(
is_on(_flock)) + _wander_force * int(
is_on(_wander)) +
296 _obstacle_avoidance_force * int(
is_on(_obstacle_avoidance));
298 if(_steering_force.length() > _ai_char->get_max_force()) {
299 _steering_force.normalize();
300 _steering_force = _steering_force * _ai_char->get_max_force();
303 if(
is_on(_arrival)) {
304 if(_seek_obj !=
nullptr) {
305 LVecBase3 dirn = _steering_force;
307 _steering_force = ((_steering_force.length() - _arrival_force.length()) * dirn);
310 if(_pursue_obj !=
nullptr) {
311 LVecBase3 dirn = _steering_force;
313 _steering_force = ((_steering_force.length() - _arrival_force.length()) * _arrival_obj->_arrival_direction);
316 return _steering_force;
338 if(_seek_obj !=
nullptr) {
347 while (!_flee_list.empty()) {
350 _flee_list.pop_front();
356 if(_pursue_obj !=
nullptr) {
359 _pursue_obj =
nullptr;
365 while (!_evade_list.empty()) {
368 _evade_list.pop_front();
374 if(_arrival_obj !=
nullptr) {
378 _arrival_obj =
nullptr;
384 if(_flock_group !=
nullptr) {
387 _flock_group =
nullptr;
393 if(_wander_obj !=
nullptr) {
396 _wander_obj =
nullptr;
402 if(_obstacle_avoidance_obj !=
nullptr) {
404 delete _obstacle_avoidance_obj;
405 _obstacle_avoidance_obj =
nullptr;
411 if(_pursue_obj !=
nullptr && _path_follow_obj !=
nullptr) {
414 _pursue_obj =
nullptr;
415 delete _path_follow_obj;
416 _path_follow_obj =
nullptr;
421 if(_pursue_obj !=
nullptr && _path_follow_obj !=
nullptr) {
424 _pursue_obj =
nullptr;
425 delete _path_follow_obj;
426 _path_follow_obj =
nullptr;
431 cout<<
"Invalid option!"<<endl;
454 if(_seek_obj !=
nullptr) {
461 for(_flee_itr = _flee_list.begin(); _flee_itr != _flee_list.end(); _flee_itr++) {
469 if(_pursue_obj !=
nullptr) {
476 for(_evade_itr = _evade_list.begin(); _evade_itr != _evade_list.end(); _evade_itr++) {
484 if(_arrival_obj !=
nullptr) {
492 if(_flock_group !=
nullptr) {
500 if(_wander_obj !=
nullptr) {
507 if(_obstacle_avoidance_obj !=
nullptr) {
509 turn_off(
"obstacle_avoidance_activate");
515 if(_pursue_obj !=
nullptr && _path_follow_obj !=
nullptr) {
517 _path_follow_obj->_start =
false;
522 if(_pursue_obj !=
nullptr && _path_follow_obj !=
nullptr) {
524 _path_follow_obj->_start =
false;
529 cout<<
"Invalid option!"<<endl;
552 if(_seek_obj !=
nullptr) {
559 for(_flee_itr = _flee_list.begin(); _flee_itr != _flee_list.end(); _flee_itr++) {
566 if(_pursue_obj !=
nullptr) {
573 for(_evade_itr = _evade_list.begin(); _evade_itr != _evade_list.end(); _evade_itr++) {
580 if(_arrival_obj !=
nullptr) {
587 if(_flock_group !=
nullptr) {
594 if(_wander_obj !=
nullptr) {
601 if(_obstacle_avoidance_obj !=
nullptr) {
608 if(_pursue_obj !=
nullptr && _path_follow_obj !=
nullptr) {
610 _path_follow_obj->_start =
true;
615 if(_pursue_obj !=
nullptr && _path_follow_obj !=
nullptr) {
617 _path_follow_obj->_start =
false;
622 cout<<
"Invalid option!"<<endl;
632 _seek_obj =
new Seek(_ai_char, target_object, seek_wt);
637 _seek_obj =
new Seek(_ai_char, pos, seek_wt);
646 _flee_obj =
new Flee(_ai_char, target_object, panic_distance, relax_distance, flee_wt);
647 _flee_list.insert(_flee_list.end(), *_flee_obj);
652void AIBehaviors::flee(LVecBase3 pos,
double panic_distance,
double relax_distance,
float flee_wt) {
653 _flee_obj =
new Flee(_ai_char, pos, panic_distance, relax_distance, flee_wt);
654 _flee_list.insert(_flee_list.end(), *_flee_obj);
664 _pursue_obj =
new Pursue(_ai_char, target_object, pursue_wt);
673 _evade_obj =
new Evade(_ai_char, target_object, panic_distance, relax_distance, evade_wt);
674 _evade_list.insert(_evade_list.end(), *_evade_obj);
685 _arrival_obj =
new Arrival(_ai_char, distance);
686 _arrival_obj->_arrival_type =
true;
690 _arrival_obj =
new Arrival(_ai_char, distance);
691 _arrival_obj->_arrival_type =
false;
695 cout<<
"Note: A Seek or Pursue behavior is required to use Arrival behavior."<<endl;
704 _flock_weight = flock_wt;
732 unsigned int neighbor_count = 0;
733 LVecBase3 separation_force = LVecBase3(0.0, 0.0, 0.0);
734 LVecBase3 alignment_force = LVecBase3(0.0, 0.0, 0.0);
735 LVecBase3 cohesion_force = LVecBase3(0.0, 0.0, 0.0);
736 LVecBase3 avg_neighbor_heading = LVecBase3(0.0, 0.0, 0.0);
737 LVecBase3 total_neighbor_heading = LVecBase3(0.0, 0.0, 0.0);
738 LVecBase3 avg_center_of_mass = LVecBase3(0.0, 0.0, 0.0);
739 LVecBase3 total_center_of_mass = LVecBase3(0.0, 0.0, 0.0);
743 for(
unsigned int i = 0; i < _flock_group->_ai_char_list.size(); i++) {
744 if(_flock_group->_ai_char_list[i]->_name != _ai_char->_name) {
747 LVecBase3 dist_vect = _flock_group->_ai_char_list[i]->_ai_char_np.get_pos() - _ai_char->_ai_char_np.
get_pos();
748 LVecBase3 ai_char_heading = _ai_char->get_velocity();
749 ai_char_heading.normalize();
752 if(dist_vect.dot(ai_char_heading) > ((dist_vect.length()) * (ai_char_heading.length()) * cos(_flock_group->_flock_vcone_angle * (_PI / 180)))
753 && (dist_vect.length() < _flock_group->_flock_vcone_radius)) {
755 LVecBase3 ai_char_to_units = _ai_char->_ai_char_np.
get_pos() - _flock_group->_ai_char_list[i]->_ai_char_np.get_pos();
756 float to_units_dist = ai_char_to_units.length();
757 ai_char_to_units.normalize();
758 separation_force += (ai_char_to_units / to_units_dist);
762 LVecBase3 neighbor_heading = _flock_group->_ai_char_list[i]->get_velocity();
763 neighbor_heading.normalize();
764 total_neighbor_heading += neighbor_heading;
765 total_center_of_mass += _flock_group->_ai_char_list[i]->_ai_char_np.get_pos();
773 if(neighbor_count > 0) {
775 avg_neighbor_heading = total_neighbor_heading / neighbor_count;
776 LVector3 ai_char_heading = _ai_char->get_velocity();
777 ai_char_heading.normalize();
778 avg_neighbor_heading -= ai_char_heading;
779 avg_neighbor_heading.normalize();
780 alignment_force = avg_neighbor_heading;
783 avg_center_of_mass = total_center_of_mass / neighbor_count;
784 LVecBase3 cohesion_dir = avg_center_of_mass - _ai_char->_ai_char_np.
get_pos();
785 cohesion_dir.normalize();
786 cohesion_force = cohesion_dir * _ai_char->_movt_force;
792 return(LVecBase3(0.0, 0.0, 0.0));
798 return (separation_force * _flock_group->_separation_wt + avg_neighbor_heading * _flock_group->_alignment_wt
799 + cohesion_force * _flock_group->_cohesion_wt);
807 _wander_obj =
new Wander(_ai_char, wander_radius, flag, aoe, wander_weight);
817 _obstacle_avoidance_obj =
new ObstacleAvoidance(_ai_char, obstacle_avoidance_weight);
818 turn_on(
"obstacle_avoidance_activate");
826 _path_follow_obj =
new PathFollow(_ai_char, follow_wt);
841 _path_follow_obj->
start(type);
850 _path_find_obj =
new PathFind(_ai_char);
902 if(_seek_obj->_seek_done) {
917 for(_flee_itr = _flee_list.begin(); _flee_itr != _flee_list.end(); _flee_itr++) {
918 if(_flee_itr->_flee_done ==
true) {
922 if(i == _flee_list.size()) {
941 if(_pursue_obj->_pursue_done) {
961 for(_evade_itr = _evade_list.begin(); _evade_itr != _evade_list.end(); _evade_itr++) {
962 if(_evade_itr->_evade_done ==
true) {
966 if(i == _evade_list.size()) {
984 if(
is_on(_arrival)) {
985 if(_arrival_obj->_arrival_done) {
1023 if(
is_on(_wander)) {
1036 if(_obstacle_avoidance_obj) {
1037 if(
is_on(_obstacle_avoidance)) {
1050 if(_path_follow_obj) {
1051 if(
is_on(
"pathfollow")) {
1052 if(_pursue_obj->_pursue_done) {
1069 if(_path_find_obj) {
1070 if(
is_on(
"pathfind")) {
1071 if(_pursue_obj->_pursue_done) {
1088 if(_seek_obj || _flee_obj || _pursue_obj || _evade_obj || _arrival_obj || _flock_group || _wander_obj || _obstacle_avoidance_obj || _path_follow_obj) {
1090 ||
is_on(_obstacle_avoidance) ||
is_on(
"pathfollow") ||
is_on(
"pathfinding")) {
1103 cout<<
"Invalid value!"<<endl;
1113 if(ai_type ==
"all") {
1116 else if(ai_type ==
"seek") {
1119 else if(ai_type ==
"flee") {
1122 else if(ai_type ==
"pursue") {
1125 else if(ai_type ==
"evade") {
1128 else if(ai_type ==
"arrival") {
1131 else if(ai_type ==
"flock") {
1134 else if(ai_type ==
"wander") {
1137 else if(ai_type ==
"obstacle_avoidance") {
1140 else if(ai_type ==
"pathfollow") {
1143 else if(ai_type ==
"any") {
1146 else if(ai_type ==
"flee_activate") {
1149 else if(ai_type ==
"evade_activate") {
1152 else if(ai_type ==
"arrival_activate") {
1155 else if(ai_type ==
"flock_activate") {
1158 else if(ai_type ==
"obstacle_avoidance_activate") {
1161 else if(ai_type ==
"path_finding") {
1174 _behaviors_flags |= _seek;
1178 _behaviors_flags |= _flee;
1182 _behaviors_flags |= _pursue;
1186 _behaviors_flags |= _evade;
1190 _behaviors_flags |= _arrival;
1194 _behaviors_flags |= _flock;
1198 _behaviors_flags |= _wander;
1202 _behaviors_flags |= _obstacle_avoidance;
1206 _behaviors_flags |= _flee_activate;
1210 _behaviors_flags |= _evade_activate;
1214 _behaviors_flags |= _arrival_activate;
1218 _behaviors_flags |= _flock_activate;
1222 _behaviors_flags |= _obstacle_avoidance_activate;
1226 cout<<
"Invalid option!"<<endl;
1237 _behaviors_flags ^= _seek;
1239 _seek_force = LVecBase3(0.0f, 0.0f, 0.0f);
1244 _behaviors_flags ^= _flee;
1246 _flee_force = LVecBase3(0.0f, 0.0f, 0.0f);
1250 if(
is_on(_pursue)) {
1251 _behaviors_flags ^= _pursue;
1253 _pursue_force = LVecBase3(0.0f, 0.0f, 0.0f);
1258 _behaviors_flags ^= _evade;
1260 _evade_force = LVecBase3(0.0f, 0.0f, 0.0f);
1264 if (
is_on(_arrival)) {
1265 _behaviors_flags ^= _arrival;
1267 _arrival_force = LVecBase3(0.0f, 0.0f, 0.0f);
1272 _behaviors_flags ^= _flock;
1274 _flock_force = LVecBase3(0.0f, 0.0f, 0.0f);
1278 if(
is_on(_wander)) {
1279 _behaviors_flags ^= _wander;
1281 _wander_force = LVecBase3(0.0f, 0.0f, 0.0f);
1285 if(
is_on(_obstacle_avoidance)) {
1286 _behaviors_flags ^= _obstacle_avoidance;
1288 _obstacle_avoidance_force = LVecBase3(0.0f, 0.0f, 0.0f);
1296 if (
is_on(_flee_activate)) {
1297 _behaviors_flags ^= _flee_activate;
1302 if (
is_on(_evade_activate)) {
1303 _behaviors_flags ^= _evade_activate;
1308 if (
is_on(_arrival_activate)) {
1309 _behaviors_flags ^= _arrival_activate;
1314 if (
is_on(_flock_activate)) {
1315 _behaviors_flags ^= _flock_activate;
1320 if (
is_on(_obstacle_avoidance_activate)) {
1321 _behaviors_flags ^= _obstacle_avoidance_activate;
1330 cout<<
"Invalid option!"<<endl;
1338 return (_behaviors_flags & bt) == bt;
1345 if(ai_type ==
"pathfollow") {
1346 if(_path_follow_obj) {
1347 return (
is_on(_pursue) && _path_follow_obj->_start);
1354 if(ai_type ==
"pathfinding") {
1355 if(_path_follow_obj && _path_find_obj) {
1356 return (
is_on(_pursue) && _path_follow_obj->_start);
1370 return ((_behaviors_flags | bt) == bt);
1377 if(ai_type ==
"pathfollow") {
1378 if(_path_follow_obj && _path_follow_obj->_start) {
1386 if(ai_type ==
"pathfinding") {
1387 if(_path_find_obj && _path_follow_obj && _path_follow_obj->_start) {
1395 cout<<
"You passed an invalid string, defaulting return value to false!"<<endl;
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void accumulate_force(std::string force_type, LVecBase3 force)
This function updates the individual steering forces for each of the ai characters.
void init_path_find(const char *navmesh_filename)
This function activates path finding in the character.
void pursue(NodePath target_object, float pursue_wt=1.0)
This function activates pursue.
void add_dynamic_obstacle(NodePath obstacle)
This function starts the pathfinding obstacle navigation for the passed in obstacle.
void resume_ai(std::string ai_type)
This function resumes individual or all the AIs.
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 turn_on(std::string ai_type)
This function turns on any aiBehavior which is passed as a string.
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.
void turn_off(std::string ai_type)
This function turns off any aiBehavior which is passed as a string.
void add_static_obstacle(NodePath obstacle)
This function allows the user to dynamically add obstacles to the game environment.
void obstacle_avoidance(float feeler_length=1.0)
This function activates obstacle avoidance for a given character.
void path_find_to(LVecBase3 pos, std::string type="normal")
This function checks for the source and target in the navigation mesh for its availability and then f...
bool is_off(_behavior_type bt)
This function returns true if an aiBehavior is off.
void path_follow(float follow_wt=1.0f)
This function activates path following.
void start_follow(std::string type="normal")
This function starts the path follower.
void wander(double wander_radius=5.0, int flag=0, double aoe=0.0, float wander_weight=1.0)
This function activates wander.
void remove_ai(std::string ai_type)
This function removes individual or all the AIs.
LVecBase3 calculate_prioritized()
This function updates the main steering force for the ai character using the accumulate function and ...
std::string behavior_status(std::string ai_type)
This function returns the status of an AI Type whether it is active, paused or disabled.
void arrival(double distance=10.0)
This function activates arrival.
void flock(float flock_wt)
This function activates flock.
void add_to_path(LVecBase3 pos)
This function adds positions to the path to follow.
void pause_ai(std::string ai_type)
This function pauses individual or all the AIs.
bool is_on(_behavior_type bt)
This function returns true if an aiBehavior is on.
void flock_activate()
This function checks whether any other behavior exists to work with flock.
LVecBase3 do_flock()
This function contains the logic for flocking behavior.
void seek(NodePath target_object, float seek_wt=1.0)
This function activates seek and makes an object of the Seek class.
int char_to_int(std::string ai_type)
This function is used to derive int values from the ai types strings.
bool is_conflict()
Checks for conflict between steering forces.
void arrival_activate()
This function checks for whether the target is within the arrival distance.
LVecBase3 do_arrival()
This function performs the arrival and returns an arrival force which is used in the calculate_priori...
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
LPoint3 get_pos() const
Retrieves the translation component of the transform.
void obstacle_avoidance_activate()
This function activates obstacle_avoidance if a obstacle is detected.
LVecBase3 do_obstacle_avoidance()
This function returns the force necessary by the AICharacter to avoid the nearest obstacle detected b...
This class contains all the members and functions that are required to form an interface between the ...
void path_find(LVecBase3 pos, std::string type="normal")
This function checks for the source and target in the navigation mesh for its availability and then f...
void add_obstacle_to_mesh(NodePath obstacle)
This function allows the user to dynamically add obstacles to the game environment.
void dynamic_avoid(NodePath obstacle)
This function starts the pathfinding obstacle navigation for the passed in obstacle.
void set_path_find(const char *navmesh_filename)
This function starts the path finding process after reading the given navigation mesh.
void do_follow()
This function allows continuous path finding by ai chars.
void start(std::string type)
This function initiates the path follow behavior.
void add_to_path(LVecBase3 pos)
This function adds the positions generated from a pathfind or a simple path follow behavior to the _p...
LVecBase3 do_pursue()
This function performs the pursue and returns a pursue force which is used in the calculate_prioritiz...
LVecBase3 do_seek()
This function performs the seek and returns a seek force which is used in the calculate_prioritized f...
LVecBase3 do_wander()
This function performs the wander and returns the wander force which is used in the calculate_priorit...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.