20 static const float _PI = 3.14;
22 AIBehaviors::AIBehaviors() {
23 _steering_force = LVecBase3(0.0, 0.0, 0.0);
24 _behaviors_flags = _behaviors_flags & _none;
25 _previous_conflict =
false;
30 _pursue_obj =
nullptr;
32 _arrival_obj =
nullptr;
33 _wander_obj =
nullptr;
34 _flock_group =
nullptr;
35 _path_follow_obj =
nullptr;
36 _path_find_obj =
nullptr;
37 _obstacle_avoidance_obj =
nullptr;
49 AIBehaviors::~AIBehaviors() {
62 if(_previous_conflict ==
false) {
64 _seek_force *= _seek_obj->_seek_weight;
68 LVecBase3 dirn = _flee_force;
70 _flee_force = _steering_force.length() * dirn * _flee_obj->_flee_weight;
74 _pursue_force *= _pursue_obj->_pursue_weight;
78 LVecBase3 dirn = _evade_force;
80 _evade_force = _steering_force.length() * dirn * _evade_obj->_evade_weight;
84 _flock_force *= _flock_weight;
88 _wander_force *= _wander_obj->_wander_weight;
91 _previous_conflict =
true;
99 _previous_conflict =
false;
113 if(force_type ==
"seek") {
114 old_force = _seek_force;
115 _seek_force = old_force + force;
118 if(force_type ==
"flee") {
119 old_force = _flee_force;
120 _flee_force = old_force + force;
123 if(force_type ==
"pursue") {
124 old_force = _pursue_force;
125 double new_force = old_force.length() + force.length();
126 _pursue_force = new_force * _pursue_obj->_pursue_direction;
129 if(force_type ==
"evade") {
130 old_force = _evade_force;
131 double new_force = old_force.length() + force.length();
133 _evade_force = new_force * force;
136 if(force_type ==
"arrival") {
137 _arrival_force = force;
140 if(force_type ==
"flock") {
141 old_force = _flock_force;
142 _flock_force = old_force + force;
145 if(force_type ==
"wander") {
146 old_force = _wander_force;
147 _wander_force = old_force + force;
150 if(force_type ==
"obstacle_avoidance") {
151 old_force = _obstacle_avoidance_force;
152 _obstacle_avoidance_force = old_force +force;
169 force = _seek_obj->
do_seek() * _seek_obj->_seek_weight;
177 if(
is_on(_flee_activate)) {
178 for(_flee_itr = _flee_list.begin(); _flee_itr != _flee_list.end(); _flee_itr++) {
179 _flee_itr->flee_activate();
184 for(_flee_itr = _flee_list.begin(); _flee_itr != _flee_list.end(); _flee_itr++) {
185 if(_flee_itr->_flee_activate_done) {
187 force = _flee_itr->do_flee() * _flee_itr->_flee_weight;
190 force = _flee_itr->do_flee();
199 force = _pursue_obj->
do_pursue() * _pursue_obj->_pursue_weight;
207 if(
is_on(_evade_activate)) {
208 for(_evade_itr = _evade_list.begin(); _evade_itr != _evade_list.end(); _evade_itr++) {
209 _evade_itr->evade_activate();
214 for(_evade_itr = _evade_list.begin(); _evade_itr != _evade_list.end(); _evade_itr++) {
215 if(_evade_itr->_evade_activate_done) {
217 force = (_evade_itr->do_evade()) * (_evade_itr->_evade_weight);
220 force = _evade_itr->do_evade();
227 if(
is_on(_arrival_activate)) {
231 if(
is_on(_arrival)) {
236 if(
is_on(_flock_activate)) {
252 force = _wander_obj->
do_wander() * _wander_obj->_wander_weight;
260 if(
is_on(_obstacle_avoidance_activate)) {
264 if(
is_on(_obstacle_avoidance)) {
274 if(_path_follow_obj!=
nullptr) {
275 if(_path_follow_obj->_start) {
282 _steering_force += _seek_force * int(
is_on(_seek)) + _flee_force * int(
is_on(_flee)) +
283 _pursue_force * int(
is_on(_pursue)) + _evade_force * int(
is_on(_evade)) +
284 _flock_force * int(
is_on(_flock)) + _wander_force * int(
is_on(_wander)) +
285 _obstacle_avoidance_force * int(
is_on(_obstacle_avoidance));
287 if(_steering_force.length() > _ai_char->get_max_force()) {
288 _steering_force.normalize();
289 _steering_force = _steering_force * _ai_char->get_max_force();
292 if(
is_on(_arrival)) {
293 if(_seek_obj !=
nullptr) {
294 LVecBase3 dirn = _steering_force;
296 _steering_force = ((_steering_force.length() - _arrival_force.length()) * dirn);
299 if(_pursue_obj !=
nullptr) {
300 LVecBase3 dirn = _steering_force;
302 _steering_force = ((_steering_force.length() - _arrival_force.length()) * _arrival_obj->_arrival_direction);
305 return _steering_force;
327 if(_seek_obj !=
nullptr) {
336 while (!_flee_list.empty()) {
339 _flee_list.pop_front();
345 if(_pursue_obj !=
nullptr) {
348 _pursue_obj =
nullptr;
354 while (!_evade_list.empty()) {
357 _evade_list.pop_front();
363 if(_arrival_obj !=
nullptr) {
367 _arrival_obj =
nullptr;
373 if(_flock_group !=
nullptr) {
376 _flock_group =
nullptr;
382 if(_wander_obj !=
nullptr) {
385 _wander_obj =
nullptr;
391 if(_obstacle_avoidance_obj !=
nullptr) {
393 delete _obstacle_avoidance_obj;
394 _obstacle_avoidance_obj =
nullptr;
400 if(_pursue_obj !=
nullptr && _path_follow_obj !=
nullptr) {
403 _pursue_obj =
nullptr;
404 delete _path_follow_obj;
405 _path_follow_obj =
nullptr;
410 if(_pursue_obj !=
nullptr && _path_follow_obj !=
nullptr) {
413 _pursue_obj =
nullptr;
414 delete _path_follow_obj;
415 _path_follow_obj =
nullptr;
420 cout<<
"Invalid option!"<<endl;
443 if(_seek_obj !=
nullptr) {
450 for(_flee_itr = _flee_list.begin(); _flee_itr != _flee_list.end(); _flee_itr++) {
458 if(_pursue_obj !=
nullptr) {
465 for(_evade_itr = _evade_list.begin(); _evade_itr != _evade_list.end(); _evade_itr++) {
473 if(_arrival_obj !=
nullptr) {
481 if(_flock_group !=
nullptr) {
489 if(_wander_obj !=
nullptr) {
496 if(_obstacle_avoidance_obj !=
nullptr) {
498 turn_off(
"obstacle_avoidance_activate");
504 if(_pursue_obj !=
nullptr && _path_follow_obj !=
nullptr) {
506 _path_follow_obj->_start =
false;
511 if(_pursue_obj !=
nullptr && _path_follow_obj !=
nullptr) {
513 _path_follow_obj->_start =
false;
518 cout<<
"Invalid option!"<<endl;
541 if(_seek_obj !=
nullptr) {
548 for(_flee_itr = _flee_list.begin(); _flee_itr != _flee_list.end(); _flee_itr++) {
555 if(_pursue_obj !=
nullptr) {
562 for(_evade_itr = _evade_list.begin(); _evade_itr != _evade_list.end(); _evade_itr++) {
569 if(_arrival_obj !=
nullptr) {
576 if(_flock_group !=
nullptr) {
583 if(_wander_obj !=
nullptr) {
590 if(_obstacle_avoidance_obj !=
nullptr) {
597 if(_pursue_obj !=
nullptr && _path_follow_obj !=
nullptr) {
599 _path_follow_obj->_start =
true;
604 if(_pursue_obj !=
nullptr && _path_follow_obj !=
nullptr) {
606 _path_follow_obj->_start =
false;
611 cout<<
"Invalid option!"<<endl;
621 _seek_obj =
new Seek(_ai_char, target_object, seek_wt);
626 _seek_obj =
new Seek(_ai_char, pos, seek_wt);
635 _flee_obj =
new Flee(_ai_char, target_object, panic_distance, relax_distance, flee_wt);
636 _flee_list.insert(_flee_list.end(), *_flee_obj);
641 void AIBehaviors::flee(LVecBase3 pos,
double panic_distance,
double relax_distance,
float flee_wt) {
642 _flee_obj =
new Flee(_ai_char, pos, panic_distance, relax_distance, flee_wt);
643 _flee_list.insert(_flee_list.end(), *_flee_obj);
653 _pursue_obj =
new Pursue(_ai_char, target_object, pursue_wt);
662 _evade_obj =
new Evade(_ai_char, target_object, panic_distance, relax_distance, evade_wt);
663 _evade_list.insert(_evade_list.end(), *_evade_obj);
674 _arrival_obj =
new Arrival(_ai_char, distance);
675 _arrival_obj->_arrival_type =
true;
679 _arrival_obj =
new Arrival(_ai_char, distance);
680 _arrival_obj->_arrival_type =
false;
684 cout<<
"Note: A Seek or Pursue behavior is required to use Arrival behavior."<<endl;
693 _flock_weight = flock_wt;
721 unsigned int neighbor_count = 0;
722 LVecBase3 separation_force = LVecBase3(0.0, 0.0, 0.0);
723 LVecBase3 alignment_force = LVecBase3(0.0, 0.0, 0.0);
724 LVecBase3 cohesion_force = LVecBase3(0.0, 0.0, 0.0);
725 LVecBase3 avg_neighbor_heading = LVecBase3(0.0, 0.0, 0.0);
726 LVecBase3 total_neighbor_heading = LVecBase3(0.0, 0.0, 0.0);
727 LVecBase3 avg_center_of_mass = LVecBase3(0.0, 0.0, 0.0);
728 LVecBase3 total_center_of_mass = LVecBase3(0.0, 0.0, 0.0);
732 for(
unsigned int i = 0; i < _flock_group->_ai_char_list.size(); i++) {
733 if(_flock_group->_ai_char_list[i]->_name != _ai_char->_name) {
736 LVecBase3 dist_vect = _flock_group->_ai_char_list[i]->_ai_char_np.get_pos() - _ai_char->_ai_char_np.
get_pos();
737 LVecBase3 ai_char_heading = _ai_char->get_velocity();
738 ai_char_heading.normalize();
741 if(dist_vect.dot(ai_char_heading) > ((dist_vect.length()) * (ai_char_heading.length()) * cos(_flock_group->_flock_vcone_angle * (_PI / 180)))
742 && (dist_vect.length() < _flock_group->_flock_vcone_radius)) {
744 LVecBase3 ai_char_to_units = _ai_char->_ai_char_np.
get_pos() - _flock_group->_ai_char_list[i]->_ai_char_np.get_pos();
745 float to_units_dist = ai_char_to_units.length();
746 ai_char_to_units.normalize();
747 separation_force += (ai_char_to_units / to_units_dist);
751 LVecBase3 neighbor_heading = _flock_group->_ai_char_list[i]->get_velocity();
752 neighbor_heading.normalize();
753 total_neighbor_heading += neighbor_heading;
754 total_center_of_mass += _flock_group->_ai_char_list[i]->_ai_char_np.get_pos();
762 if(neighbor_count > 0) {
764 avg_neighbor_heading = total_neighbor_heading / neighbor_count;
765 LVector3 ai_char_heading = _ai_char->get_velocity();
766 ai_char_heading.normalize();
767 avg_neighbor_heading -= ai_char_heading;
768 avg_neighbor_heading.normalize();
769 alignment_force = avg_neighbor_heading;
772 avg_center_of_mass = total_center_of_mass / neighbor_count;
773 LVecBase3 cohesion_dir = avg_center_of_mass - _ai_char->_ai_char_np.
get_pos();
774 cohesion_dir.normalize();
775 cohesion_force = cohesion_dir * _ai_char->_movt_force;
781 return(LVecBase3(0.0, 0.0, 0.0));
787 return (separation_force * _flock_group->_separation_wt + avg_neighbor_heading * _flock_group->_alignment_wt
788 + cohesion_force * _flock_group->_cohesion_wt);
796 _wander_obj =
new Wander(_ai_char, wander_radius, flag, aoe, wander_weight);
806 _obstacle_avoidance_obj =
new ObstacleAvoidance(_ai_char, obstacle_avoidance_weight);
807 turn_on(
"obstacle_avoidance_activate");
815 _path_follow_obj =
new PathFollow(_ai_char, follow_wt);
830 _path_follow_obj->
start(type);
839 _path_find_obj =
new PathFind(_ai_char);
891 if(_seek_obj->_seek_done) {
906 for(_flee_itr = _flee_list.begin(); _flee_itr != _flee_list.end(); _flee_itr++) {
907 if(_flee_itr->_flee_done ==
true) {
911 if(i == _flee_list.size()) {
930 if(_pursue_obj->_pursue_done) {
950 for(_evade_itr = _evade_list.begin(); _evade_itr != _evade_list.end(); _evade_itr++) {
951 if(_evade_itr->_evade_done ==
true) {
955 if(i == _evade_list.size()) {
973 if(
is_on(_arrival)) {
974 if(_arrival_obj->_arrival_done) {
1012 if(
is_on(_wander)) {
1025 if(_obstacle_avoidance_obj) {
1026 if(
is_on(_obstacle_avoidance)) {
1039 if(_path_follow_obj) {
1040 if(
is_on(
"pathfollow")) {
1041 if(_pursue_obj->_pursue_done) {
1058 if(_path_find_obj) {
1059 if(
is_on(
"pathfind")) {
1060 if(_pursue_obj->_pursue_done) {
1077 if(_seek_obj || _flee_obj || _pursue_obj || _evade_obj || _arrival_obj || _flock_group || _wander_obj || _obstacle_avoidance_obj || _path_follow_obj) {
1079 ||
is_on(_obstacle_avoidance) ||
is_on(
"pathfollow") ||
is_on(
"pathfinding")) {
1092 cout<<
"Invalid value!"<<endl;
1102 if(ai_type ==
"all") {
1105 else if(ai_type ==
"seek") {
1108 else if(ai_type ==
"flee") {
1111 else if(ai_type ==
"pursue") {
1114 else if(ai_type ==
"evade") {
1117 else if(ai_type ==
"arrival") {
1120 else if(ai_type ==
"flock") {
1123 else if(ai_type ==
"wander") {
1126 else if(ai_type ==
"obstacle_avoidance") {
1129 else if(ai_type ==
"pathfollow") {
1132 else if(ai_type ==
"any") {
1135 else if(ai_type ==
"flee_activate") {
1138 else if(ai_type ==
"evade_activate") {
1141 else if(ai_type ==
"arrival_activate") {
1144 else if(ai_type ==
"flock_activate") {
1147 else if(ai_type ==
"obstacle_avoidance_activate") {
1150 else if(ai_type ==
"path_finding") {
1163 _behaviors_flags |= _seek;
1167 _behaviors_flags |= _flee;
1171 _behaviors_flags |= _pursue;
1175 _behaviors_flags |= _evade;
1179 _behaviors_flags |= _arrival;
1183 _behaviors_flags |= _flock;
1187 _behaviors_flags |= _wander;
1191 _behaviors_flags |= _obstacle_avoidance;
1195 _behaviors_flags |= _flee_activate;
1199 _behaviors_flags |= _evade_activate;
1203 _behaviors_flags |= _arrival_activate;
1207 _behaviors_flags |= _flock_activate;
1211 _behaviors_flags |= _obstacle_avoidance_activate;
1215 cout<<
"Invalid option!"<<endl;
1226 _behaviors_flags ^= _seek;
1228 _seek_force = LVecBase3(0.0f, 0.0f, 0.0f);
1233 _behaviors_flags ^= _flee;
1235 _flee_force = LVecBase3(0.0f, 0.0f, 0.0f);
1239 if(
is_on(_pursue)) {
1240 _behaviors_flags ^= _pursue;
1242 _pursue_force = LVecBase3(0.0f, 0.0f, 0.0f);
1247 _behaviors_flags ^= _evade;
1249 _evade_force = LVecBase3(0.0f, 0.0f, 0.0f);
1253 if (
is_on(_arrival)) {
1254 _behaviors_flags ^= _arrival;
1256 _arrival_force = LVecBase3(0.0f, 0.0f, 0.0f);
1261 _behaviors_flags ^= _flock;
1263 _flock_force = LVecBase3(0.0f, 0.0f, 0.0f);
1267 if(
is_on(_wander)) {
1268 _behaviors_flags ^= _wander;
1270 _wander_force = LVecBase3(0.0f, 0.0f, 0.0f);
1274 if(
is_on(_obstacle_avoidance)) {
1275 _behaviors_flags ^= _obstacle_avoidance;
1277 _obstacle_avoidance_force = LVecBase3(0.0f, 0.0f, 0.0f);
1285 if (
is_on(_flee_activate)) {
1286 _behaviors_flags ^= _flee_activate;
1291 if (
is_on(_evade_activate)) {
1292 _behaviors_flags ^= _evade_activate;
1297 if (
is_on(_arrival_activate)) {
1298 _behaviors_flags ^= _arrival_activate;
1303 if (
is_on(_flock_activate)) {
1304 _behaviors_flags ^= _flock_activate;
1309 if (
is_on(_obstacle_avoidance_activate)) {
1310 _behaviors_flags ^= _obstacle_avoidance_activate;
1319 cout<<
"Invalid option!"<<endl;
1327 return (_behaviors_flags & bt) == bt;
1334 if(ai_type ==
"pathfollow") {
1335 if(_path_follow_obj) {
1336 return (
is_on(_pursue) && _path_follow_obj->_start);
1343 if(ai_type ==
"pathfinding") {
1344 if(_path_follow_obj && _path_find_obj) {
1345 return (
is_on(_pursue) && _path_follow_obj->_start);
1359 return ((_behaviors_flags | bt) == bt);
1366 if(ai_type ==
"pathfollow") {
1367 if(_path_follow_obj && _path_follow_obj->_start) {
1375 if(ai_type ==
"pathfinding") {
1376 if(_path_find_obj && _path_follow_obj && _path_follow_obj->_start) {
1384 cout<<
"You passed an invalid string, defaulting return value to false!"<<endl;
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.
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.
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 do_follow()
This function allows continuous path finding by ai chars.
void flock(float flock_wt)
This function activates flock.
void resume_ai(std::string ai_type)
This function resumes individual or all the AIs.
void turn_on(std::string ai_type)
This function turns on any aiBehavior which is passed as a string.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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 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.
void turn_off(std::string ai_type)
This function turns off any aiBehavior which is passed as a string.
LVecBase3 do_arrival()
This function performs the arrival and returns an arrival force which is used in the calculate_priori...
void remove_ai(std::string ai_type)
This function removes individual or all the AIs.
LVecBase3 do_flock()
This function contains the logic for flocking behavior.
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_static_obstacle(NodePath obstacle)
This function allows the user to dynamically add obstacles to the game environment.
void pause_ai(std::string ai_type)
This function pauses individual or all the AIs.
void add_obstacle_to_mesh(NodePath obstacle)
This function allows the user to dynamically add obstacles to the game environment.
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.
This class contains all the members and functions that are required to form an interface between the ...
void accumulate_force(std::string force_type, LVecBase3 force)
This function updates the individual steering forces for each of the ai characters.
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.
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.
bool is_on(_behavior_type bt)
This function returns true if an aiBehavior is on.
void path_follow(float follow_wt)
This function activates path following.
int char_to_int(std::string ai_type)
This function is used to derive int values from the ai types strings.
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...
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 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...
void start(std::string type)
This function initiates the path follow behavior.
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.
void pursue(NodePath target_object, float pursue_wt=1.0)
This function activates pursue.
void arrival_activate()
This function checks for whether the target is within the arrival distance.