Panda3D
aiBehaviors.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file aiBehaviors.cxx
10  * @author Deepak, John, Navin
11  * @date 2009-09-08
12  */
13 
14 #include "aiBehaviors.h"
15 
16 #include "arrival.h"
17 #include "evade.h"
18 #include "flee.h"
19 #include "flock.h"
20 #include "obstacleAvoidance.h"
21 #include "pathFind.h"
22 #include "pathFollow.h"
23 #include "pursue.h"
24 #include "seek.h"
25 #include "wander.h"
26 
27 using std::cout;
28 using std::endl;
29 using std::string;
30 
31 static const float _PI = 3.14;
32 
33 AIBehaviors::AIBehaviors() {
34  _steering_force = LVecBase3(0.0, 0.0, 0.0);
35  _behaviors_flags = _behaviors_flags & _none;
36  _previous_conflict = false;
37  _conflict = false;
38 
39  _seek_obj = nullptr;
40  _flee_obj = nullptr;
41  _pursue_obj = nullptr;
42  _evade_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;
49 
50  turn_off("seek");
51  turn_off("flee");
52  turn_off("pursue");
53  turn_off("evade");
54  turn_off("arrival");
55  turn_off("flock");
56  turn_off("wander");
57  turn_off("obstacle_avoidance");
58 }
59 
60 AIBehaviors::~AIBehaviors() {
61 
62 }
63 
64 /**
65  * Checks for conflict between steering forces. If there is a conflict it
66  * returns 'true' and sets _conflict to 'true'. If there is no conflict it
67  * returns 'false' and sets _conflict to 'false'.
68  */
70  int value = int(is_on(_seek)) + int(is_on(_flee)) + int(is_on(_pursue)) + int(is_on(_evade)) + int(is_on(_wander)) + int(is_on(_flock))+ int(is_on(_obstacle_avoidance));
71 
72  if(value > 1) {
73  if(_previous_conflict == false) {
74  if(is_on(_seek)) {
75  _seek_force *= _seek_obj->_seek_weight;
76  }
77 
78  if(is_on(_flee)) {
79  LVecBase3 dirn = _flee_force;
80  dirn.normalize();
81  _flee_force = _steering_force.length() * dirn * _flee_obj->_flee_weight;
82  }
83 
84  if(is_on(_pursue)) {
85  _pursue_force *= _pursue_obj->_pursue_weight;
86  }
87 
88  if(is_on(_evade)) {
89  LVecBase3 dirn = _evade_force;
90  dirn.normalize();
91  _evade_force = _steering_force.length() * dirn * _evade_obj->_evade_weight;
92  }
93 
94  if(is_on(_flock)) {
95  _flock_force *= _flock_weight;
96  }
97 
98  if(is_on(_wander)) {
99  _wander_force *= _wander_obj->_wander_weight;
100  }
101 
102  _previous_conflict = true;
103  }
104 
105  _conflict = true;
106  return true;
107  }
108 
109  _conflict = false;
110  _previous_conflict = false;
111  return false;
112 }
113 
114 /**
115  * This function updates the individual steering forces for each of the ai
116  * characters. These accumulated forces are eventually what comprise the
117  * resultant steering force of the character.
118  */
119 
120 void AIBehaviors::accumulate_force(string force_type, LVecBase3 force) {
121 
122  LVecBase3 old_force;
123 
124  if(force_type == "seek") {
125  old_force = _seek_force;
126  _seek_force = old_force + force;
127  }
128 
129  if(force_type == "flee") {
130  old_force = _flee_force;
131  _flee_force = old_force + force;
132  }
133 
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;
138  }
139 
140  if(force_type == "evade") {
141  old_force = _evade_force;
142  double new_force = old_force.length() + force.length();
143  force.normalize();
144  _evade_force = new_force * force;
145  }
146 
147  if(force_type == "arrival") {
148  _arrival_force = force;
149  }
150 
151  if(force_type == "flock") {
152  old_force = _flock_force;
153  _flock_force = old_force + force;
154  }
155 
156  if(force_type == "wander") {
157  old_force = _wander_force;
158  _wander_force = old_force + force;
159  }
160 
161  if(force_type == "obstacle_avoidance") {
162  old_force = _obstacle_avoidance_force;
163  _obstacle_avoidance_force = old_force +force;
164  }
165 
166 }
167 
168 /**
169  * This function updates the main steering force for the ai character using
170  * the accumulate function and checks for max force and arrival force. It
171  * finally returns this steering force which is accessed by the update
172  * function in the AICharacter class.
173  */
174 
176  LVecBase3 force;
177 
178  if(is_on(_seek)) {
179  if(_conflict) {
180  force = _seek_obj->do_seek() * _seek_obj->_seek_weight;
181  }
182  else {
183  force = _seek_obj->do_seek();
184  }
185  accumulate_force("seek",force);
186  }
187 
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();
191  }
192  }
193 
194  if(is_on(_flee)) {
195  for(_flee_itr = _flee_list.begin(); _flee_itr != _flee_list.end(); _flee_itr++) {
196  if(_flee_itr->_flee_activate_done) {
197  if(_conflict) {
198  force = _flee_itr->do_flee() * _flee_itr->_flee_weight;
199  }
200  else {
201  force = _flee_itr->do_flee();
202  }
203  accumulate_force("flee",force);
204  }
205  }
206  }
207 
208  if(is_on(_pursue)) {
209  if(_conflict) {
210  force = _pursue_obj->do_pursue() * _pursue_obj->_pursue_weight;
211  }
212  else {
213  force = _pursue_obj->do_pursue();
214  }
215  accumulate_force("pursue",force);
216  }
217 
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();
221  }
222  }
223 
224  if(is_on(_evade)) {
225  for(_evade_itr = _evade_list.begin(); _evade_itr != _evade_list.end(); _evade_itr++) {
226  if(_evade_itr->_evade_activate_done) {
227  if(_conflict) {
228  force = (_evade_itr->do_evade()) * (_evade_itr->_evade_weight);
229  }
230  else {
231  force = _evade_itr->do_evade();
232  }
233  accumulate_force("evade",force);
234  }
235  }
236  }
237 
238  if(is_on(_arrival_activate)) {
239  _arrival_obj->arrival_activate();
240  }
241 
242  if(is_on(_arrival)) {
243  force = _arrival_obj->do_arrival();
244  accumulate_force("arrival",force);
245  }
246 
247  if(is_on(_flock_activate)) {
248  flock_activate();
249  }
250 
251  if(is_on(_flock)) {
252  if(_conflict) {
253  force = do_flock() * _flock_weight;
254  }
255  else {
256  force = do_flock();
257  }
258  accumulate_force("flock",force);
259  }
260 
261  if(is_on(_wander)) {
262  if(_conflict) {
263  force = _wander_obj->do_wander() * _wander_obj->_wander_weight;
264  }
265  else {
266  force = _wander_obj->do_wander();
267  }
268  accumulate_force("wander", force);
269  }
270 
271  if(is_on(_obstacle_avoidance_activate)) {
272  _obstacle_avoidance_obj->obstacle_avoidance_activate();
273  }
274 
275  if(is_on(_obstacle_avoidance)) {
276  if(_conflict) {
277  force = _obstacle_avoidance_obj->do_obstacle_avoidance();
278  }
279  else {
280  force = _obstacle_avoidance_obj->do_obstacle_avoidance();
281  }
282  accumulate_force("obstacle_avoidance", force);
283  }
284 
285  if(_path_follow_obj!=nullptr) {
286  if(_path_follow_obj->_start) {
287  _path_follow_obj->do_follow();
288  }
289  }
290 
291  is_conflict();
292 
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));
297 
298  if(_steering_force.length() > _ai_char->get_max_force()) {
299  _steering_force.normalize();
300  _steering_force = _steering_force * _ai_char->get_max_force();
301  }
302 
303  if(is_on(_arrival)) {
304  if(_seek_obj != nullptr) {
305  LVecBase3 dirn = _steering_force;
306  dirn.normalize();
307  _steering_force = ((_steering_force.length() - _arrival_force.length()) * dirn);
308  }
309 
310  if(_pursue_obj != nullptr) {
311  LVecBase3 dirn = _steering_force;
312  dirn.normalize();
313  _steering_force = ((_steering_force.length() - _arrival_force.length()) * _arrival_obj->_arrival_direction);
314  }
315  }
316  return _steering_force;
317 }
318 
319 /**
320  * This function removes individual or all the AIs.
321  */
322 void AIBehaviors::remove_ai(string ai_type) {
323  switch(char_to_int(ai_type)) {
324  case 0: {
325  remove_ai("seek");
326  remove_ai("flee");
327  remove_ai("pursue");
328  remove_ai("evade");
329  remove_ai("arrival");
330  remove_ai("flock");
331  remove_ai("wander");
332  remove_ai("obstacle_avoidance");
333  remove_ai("pathfollow");
334  break;
335  }
336 
337  case 1: {
338  if(_seek_obj != nullptr) {
339  turn_off("seek");
340  delete _seek_obj;
341  _seek_obj = nullptr;
342  }
343  break;
344  }
345 
346  case 2: {
347  while (!_flee_list.empty()) {
348  turn_off("flee");
349  turn_off("flee_activate");
350  _flee_list.pop_front();
351  }
352  break;
353  }
354 
355  case 3: {
356  if(_pursue_obj != nullptr) {
357  turn_off("pursue");
358  delete _pursue_obj;
359  _pursue_obj = nullptr;
360  }
361  break;
362  }
363 
364  case 4: {
365  while (!_evade_list.empty()) {
366  turn_off("evade");
367  turn_off("evade_activate");
368  _evade_list.pop_front();
369  }
370  break;
371  }
372 
373  case 5: {
374  if(_arrival_obj != nullptr) {
375  turn_off("arrival");
376  turn_off("arrival_activate");
377  delete _arrival_obj;
378  _arrival_obj = nullptr;
379  }
380  break;
381  }
382 
383  case 6: {
384  if(_flock_group != nullptr) {
385  turn_off("flock");
386  turn_off("flock_activate");
387  _flock_group = nullptr;
388  }
389  break;
390  }
391 
392  case 7: {
393  if(_wander_obj != nullptr) {
394  turn_off("wander");
395  delete _wander_obj;
396  _wander_obj = nullptr;
397  }
398  break;
399  }
400 
401  case 8: {
402  if(_obstacle_avoidance_obj !=nullptr) {
403  turn_off("obstacle_avoidance");
404  delete _obstacle_avoidance_obj;
405  _obstacle_avoidance_obj = nullptr;
406  }
407  break;
408  }
409 
410  case 9: {
411  if(_pursue_obj != nullptr && _path_follow_obj != nullptr) {
412  turn_off("pursue");
413  delete _pursue_obj;
414  _pursue_obj = nullptr;
415  delete _path_follow_obj;
416  _path_follow_obj = nullptr;
417  }
418  break;
419  }
420  case 16: {
421  if(_pursue_obj != nullptr && _path_follow_obj != nullptr) {
422  turn_off("pursue");
423  delete _pursue_obj;
424  _pursue_obj = nullptr;
425  delete _path_follow_obj;
426  _path_follow_obj = nullptr;
427  }
428  break;
429  }
430  default:
431  cout<<"Invalid option!"<<endl;
432  }
433 }
434 
435 /**
436  * This function pauses individual or all the AIs.
437  */
438 void AIBehaviors::pause_ai(string ai_type) {
439  switch(char_to_int(ai_type)) {
440  case 0: {
441  pause_ai("seek");
442  pause_ai("flee");
443  pause_ai("pursue");
444  pause_ai("evade");
445  pause_ai("arrival");
446  pause_ai("flock");
447  pause_ai("wander");
448  pause_ai("obstacle_avoidance");
449  pause_ai("pathfollow");
450  break;
451  }
452 
453  case 1: {
454  if(_seek_obj != nullptr) {
455  turn_off("seek");
456  }
457  break;
458  }
459 
460  case 2: {
461  for(_flee_itr = _flee_list.begin(); _flee_itr != _flee_list.end(); _flee_itr++) {
462  turn_off("flee");
463  turn_off("flee_activate");
464  }
465  break;
466  }
467 
468  case 3: {
469  if(_pursue_obj != nullptr) {
470  turn_off("pursue");
471  }
472  break;
473  }
474 
475  case 4: {
476  for(_evade_itr = _evade_list.begin(); _evade_itr != _evade_list.end(); _evade_itr++) {
477  turn_off("evade");
478  turn_off("evade_activate");
479  }
480  break;
481  }
482 
483  case 5: {
484  if(_arrival_obj != nullptr) {
485  turn_off("arrival");
486  turn_off("arrival_activate");
487  }
488  break;
489  }
490 
491  case 6: {
492  if(_flock_group != nullptr) {
493  turn_off("flock");
494  turn_off("flock_activate");
495  }
496  break;
497  }
498 
499  case 7: {
500  if(_wander_obj != nullptr) {
501  turn_off("wander");
502  }
503  break;
504  }
505 
506  case 8: {
507  if(_obstacle_avoidance_obj != nullptr) {
508  turn_off("obstacle_avoidance");
509  turn_off("obstacle_avoidance_activate");
510  }
511  break;
512  }
513 
514  case 9: {
515  if(_pursue_obj != nullptr && _path_follow_obj != nullptr) {
516  turn_off("pursue");
517  _path_follow_obj->_start = false;
518  }
519  break;
520  }
521  case 16: {
522  if(_pursue_obj != nullptr && _path_follow_obj != nullptr) {
523  turn_off("pursue");
524  _path_follow_obj->_start = false;
525  }
526  break;
527  }
528  default:
529  cout<<"Invalid option!"<<endl;
530  }
531 }
532 
533 /**
534  * This function resumes individual or all the AIs
535  */
536 void AIBehaviors::resume_ai(string ai_type) {
537  switch(char_to_int(ai_type)) {
538  case 0: {
539  resume_ai("seek");
540  resume_ai("flee");
541  resume_ai("pursue");
542  resume_ai("evade");
543  resume_ai("arrival");
544  resume_ai("flock");
545  resume_ai("wander");
546  resume_ai("obstacle_avoidance");
547  resume_ai("pathfollow");
548  break;
549  }
550 
551  case 1: {
552  if(_seek_obj != nullptr) {
553  turn_on("seek");
554  }
555  break;
556  }
557 
558  case 2: {
559  for(_flee_itr = _flee_list.begin(); _flee_itr != _flee_list.end(); _flee_itr++) {
560  turn_on("flee");
561  }
562  break;
563  }
564 
565  case 3: {
566  if(_pursue_obj != nullptr) {
567  turn_on("pursue");
568  }
569  break;
570  }
571 
572  case 4: {
573  for(_evade_itr = _evade_list.begin(); _evade_itr != _evade_list.end(); _evade_itr++) {
574  turn_on("evade");
575  }
576  break;
577  }
578 
579  case 5: {
580  if(_arrival_obj != nullptr) {
581  turn_on("arrival");
582  }
583  break;
584  }
585 
586  case 6: {
587  if(_flock_group != nullptr) {
588  turn_on("flock");
589  }
590  break;
591  }
592 
593  case 7: {
594  if(_wander_obj != nullptr) {
595  turn_on("wander");
596  }
597  break;
598  }
599 
600  case 8: {
601  if(_obstacle_avoidance_obj != nullptr) {
602  turn_on("obstacle_avoidance");
603  }
604  break;
605  }
606 
607  case 9: {
608  if(_pursue_obj != nullptr && _path_follow_obj != nullptr) {
609  turn_on("pursue");
610  _path_follow_obj->_start = true;
611  }
612  break;
613  }
614  case 16: {
615  if(_pursue_obj != nullptr && _path_follow_obj != nullptr) {
616  turn_off("pursue");
617  _path_follow_obj->_start = false;
618  }
619  break;
620  }
621  default:
622  cout<<"Invalid option!"<<endl;
623  }
624 }
625 
626 /**
627  * This function activates seek and makes an object of the Seek class. This
628  * is the function we want the user to call for seek to be done. This
629  * function is overloaded to accept a NodePath or an LVecBase3.
630  */
631 void AIBehaviors::seek(NodePath target_object, float seek_wt) {
632  _seek_obj = new Seek(_ai_char, target_object, seek_wt);
633  turn_on("seek");
634 }
635 
636 void AIBehaviors::seek(LVecBase3 pos, float seek_wt) {
637  _seek_obj = new Seek(_ai_char, pos, seek_wt);
638  turn_on("seek");
639 }
640 
641 /**
642  * This function activates flee_activate and creates an object of the Flee
643  * class. This function is overloaded to accept a NodePath or an LVecBase3.
644  */
645 void AIBehaviors::flee(NodePath target_object, double panic_distance, double relax_distance, float flee_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);
648 
649  turn_on("flee_activate");
650 }
651 
652 void 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);
655 
656  turn_on("flee_activate");
657 }
658 
659 /**
660  * This function activates pursue. This is the function we want the user to
661  * call for pursue to be done.
662  */
663 void AIBehaviors::pursue(NodePath target_object, float pursue_wt) {
664  _pursue_obj = new Pursue(_ai_char, target_object, pursue_wt);
665 
666  turn_on("pursue");
667 }
668 
669 /**
670  * This function activates evade_activate.
671  */
672 void AIBehaviors::evade(NodePath target_object, double panic_distance, double relax_distance, float evade_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);
675 
676  turn_on("evade_activate");
677 }
678 
679 /**
680  * This function activates arrival. This is the function we want the user to
681  * call for arrival to be done.
682  */
683 void AIBehaviors::arrival(double distance) {
684  if(_pursue_obj) {
685  _arrival_obj = new Arrival(_ai_char, distance);
686  _arrival_obj->_arrival_type = true;
687  turn_on("arrival_activate");
688  }
689  else if(_seek_obj) {
690  _arrival_obj = new Arrival(_ai_char, distance);
691  _arrival_obj->_arrival_type = false;
692  turn_on("arrival_activate");
693  }
694  else {
695  cout<<"Note: A Seek or Pursue behavior is required to use Arrival behavior."<<endl;
696  }
697 }
698 
699 /**
700  * This function activates flock. This is the function we want the user to
701  * call for flock to be done.
702  */
703 void AIBehaviors::flock(float flock_wt) {
704  _flock_weight = flock_wt;
705 
706  _flock_done = false;
707  turn_on("flock_activate");
708 }
709 
710 /**
711  * This function checks whether any other behavior exists to work with flock.
712  * When this is true, it calls the do_flock function.
713  */
715  if(is_on(_seek) || is_on(_flee) || is_on(_pursue) || is_on(_evade) || is_on(_wander)) {
716  turn_off("flock_activate");
717  turn_on("flock");
718  }
719 }
720 
721 /**
722  * This function contains the logic for flocking behavior. This is an
723  * emergent behavior and is obtained by combining three other behaviors which
724  * are separation, cohesion and alignment based on Craig Reynold's algorithm.
725  * Also, this behavior does not work by itself. It works only when combined
726  * with other steering behaviors such as wander, pursue, evade, seek and flee.
727  */
729 
730  // ! Initialize variables required to compute the flocking force on the ai
731  // char.
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);
740 
741  // ! Loop through all the other AI units in the flock to check if they are
742  // neigbours.
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) {
745 
746  // ! Using visibilty cone to detect neighbors.
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();
750 
751  // ! Check if the current unit is a neighbor.
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)) {
754  // ! Separation force calculation.
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);
759 
760  // ! Calculating the total heading and center of mass of all the
761  // neighbors.
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();
766 
767  // ! Update the neighbor count.
768  ++neighbor_count;
769  }
770  }
771  }
772 
773  if(neighbor_count > 0) {
774  // ! Alignment force calculation
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;
781 
782  // ! Cohesion force calculation
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;
787  }
788  else if(is_on(_seek) || is_on(_flee) || is_on(_pursue) || is_on(_evade) || is_on(_wander)) {
789  _flock_done = true;
790  turn_off("flock");
791  turn_on("flock_activate");
792  return(LVecBase3(0.0, 0.0, 0.0));
793  }
794 
795  // ! Calculate the resultant force on the ai character by taking into
796  // account the separation, alignment and cohesion ! forces along with their
797  // corresponding weights.
798  return (separation_force * _flock_group->_separation_wt + avg_neighbor_heading * _flock_group->_alignment_wt
799  + cohesion_force * _flock_group->_cohesion_wt);
800 }
801 
802 /**
803  * This function activates wander. This is the function we want the user to
804  * call for flock to be done.
805  */
806 void AIBehaviors::wander(double wander_radius, int flag, double aoe, float wander_weight) {
807  _wander_obj = new Wander(_ai_char, wander_radius, flag, aoe, wander_weight);
808  turn_on("wander");
809 }
810 
811 /**
812  * This function activates obstacle avoidance for a given character. This is
813  * the function we want the user to call for obstacle avoidance to be
814  * performed.
815  */
816 void AIBehaviors::obstacle_avoidance(float obstacle_avoidance_weight) {
817  _obstacle_avoidance_obj = new ObstacleAvoidance(_ai_char, obstacle_avoidance_weight);
818  turn_on("obstacle_avoidance_activate");
819 }
820 
821 /**
822  * This function activates path following. This is the function we want the
823  * user to call for path following.
824  */
825 void AIBehaviors::path_follow(float follow_wt) {
826  _path_follow_obj = new PathFollow(_ai_char, follow_wt);
827 }
828 
829 /**
830  * This function adds positions to the path to follow.
831  */
832 void AIBehaviors::add_to_path(LVecBase3 pos) {
833  _path_follow_obj->add_to_path(pos);
834 }
835 
836 /**
837  * This function starts the path follower.
838  */
839 
840 void AIBehaviors::start_follow(string type) {
841  _path_follow_obj->start(type);
842 }
843 
844 /**
845  * This function activates path finding in the character. This function
846  * accepts the meshdata in .csv format.
847  *
848  */
849 void AIBehaviors::init_path_find(const char* navmesh_filename) {
850  _path_find_obj = new PathFind(_ai_char);
851  _path_find_obj->set_path_find(navmesh_filename);
852 }
853 
854 /**
855  * This function checks for the source and target in the navigation mesh for
856  * its availability and then finds the best path via the A* algorithm Then it
857  * calls the path follower to make the object follow the path.
858  */
859 void AIBehaviors::path_find_to(LVecBase3 pos, string type) {
860  _path_find_obj->path_find(pos, type);
861 }
862 
863 /**
864  * This function checks for the source and target in the navigation mesh for
865  * its availability and then finds the best path via the A* algorithm Then it
866  * calls the path follower to make the object follow the path.
867  */
868 void AIBehaviors::path_find_to(NodePath target, string type) {
869  _path_find_obj->path_find(target, type);
870 }
871 
872 /**
873  * This function allows the user to dynamically add obstacles to the game
874  * environment. The function will update the nodes within the bounding volume
875  * of the obstacle as non-traversable. Hence will not be considered by the
876  * pathfinding algorithm.
877  */
879  _path_find_obj->add_obstacle_to_mesh(obstacle);
880 }
881 
882 /**
883  * This function starts the pathfinding obstacle navigation for the passed in
884  * obstacle.
885  */
887  _path_find_obj->dynamic_avoid(obstacle);
888 }
889 
890 /**
891  * This function returns the status of an AI Type whether it is active, paused
892  * or disabled. It returns -1 if an invalid string is passed.
893  */
894 string AIBehaviors::behavior_status(string ai_type) {
895  switch(char_to_int(ai_type)) {
896  case 1:
897  if(_seek_obj) {
898  if(is_on(_seek)) {
899  return "active";
900  }
901  else {
902  if(_seek_obj->_seek_done) {
903  return "done";
904  }
905  return "paused";
906  }
907  }
908  else {
909  return "disabled";
910  }
911  break;
912 
913  case 2:
914  if(_flee_obj) {
915  if(is_on(_flee)) {
916  unsigned int i = 0;
917  for(_flee_itr = _flee_list.begin(); _flee_itr != _flee_list.end(); _flee_itr++) {
918  if(_flee_itr->_flee_done == true) {
919  ++i;
920  }
921  }
922  if(i == _flee_list.size()) {
923  return "done";
924  }
925  else {
926  return "active";
927  }
928  }
929  else {
930  return "paused";
931  }
932  }
933  else {
934  return "disabled";
935  }
936  break;
937 
938  case 3:
939  if(_pursue_obj) {
940  if(is_on(_pursue)) {
941  if(_pursue_obj->_pursue_done) {
942  return "done";
943  }
944  else {
945  return "active";
946  }
947  }
948  else {
949  return "paused";
950  }
951  }
952  else {
953  return "disabled";
954  }
955  break;
956 
957  case 4:
958  if(_evade_obj) {
959  if(is_on(_evade)) {
960  unsigned int i = 0;
961  for(_evade_itr = _evade_list.begin(); _evade_itr != _evade_list.end(); _evade_itr++) {
962  if(_evade_itr->_evade_done == true) {
963  ++i;
964  }
965  }
966  if(i == _evade_list.size()) {
967  return "done";
968  }
969  else {
970  return "active";
971  }
972  }
973  else {
974  return "paused";
975  }
976  }
977  else {
978  return "disabled";
979  }
980  break;
981 
982  case 5:
983  if(_arrival_obj) {
984  if(is_on(_arrival)) {
985  if(_arrival_obj->_arrival_done) {
986  return "done";
987  }
988  else {
989  return "active";
990  }
991  }
992  else {
993  return "paused";
994  }
995  }
996  else {
997  return "disabled";
998  }
999  break;
1000 
1001  case 6:
1002  if(_flock_group) {
1003  if(is_on(_flock)) {
1004  if(_flock_done) {
1005  return "done";
1006  }
1007  else {
1008  return "active";
1009  }
1010  return "active";
1011  }
1012  else {
1013  return "paused";
1014  }
1015  }
1016  else {
1017  return "disabled";
1018  }
1019  break;
1020 
1021  case 7:
1022  if(_wander_obj) {
1023  if(is_on(_wander)) {
1024  return "active";
1025  }
1026  else {
1027  return "paused";
1028  }
1029  }
1030  else {
1031  return "disabled";
1032  }
1033  break;
1034 
1035  case 8:
1036  if(_obstacle_avoidance_obj) {
1037  if(is_on(_obstacle_avoidance)) {
1038  return "active";
1039  }
1040  else {
1041  return "paused";
1042  }
1043  }
1044  else {
1045  return "disabled";
1046  }
1047  break;
1048 
1049  case 9:
1050  if(_path_follow_obj) {
1051  if(is_on("pathfollow")) {
1052  if(_pursue_obj->_pursue_done) {
1053  return "done";
1054  }
1055  else {
1056  return "active";
1057  }
1058  }
1059  else {
1060  return "paused";
1061  }
1062  }
1063  else {
1064  return "disabled";
1065  }
1066  break;
1067 
1068  case 16:
1069  if(_path_find_obj) {
1070  if(is_on("pathfind")) {
1071  if(_pursue_obj->_pursue_done) {
1072  return "done";
1073  }
1074  else {
1075  return "active";
1076  }
1077  }
1078  else {
1079  return "paused";
1080  }
1081  }
1082  else {
1083  return "disabled";
1084  }
1085  break;
1086 
1087  case 10:
1088  if(_seek_obj || _flee_obj || _pursue_obj || _evade_obj || _arrival_obj || _flock_group || _wander_obj || _obstacle_avoidance_obj || _path_follow_obj) {
1089  if(is_on(_seek) || is_on(_flee) || is_on(_pursue)|| is_on(_evade) || is_on(_arrival) || is_on(_flock) || is_on(_wander)
1090  || is_on(_obstacle_avoidance) || is_on("pathfollow") || is_on("pathfinding")) {
1091  return "active";
1092  }
1093  else {
1094  return "paused";
1095  }
1096  }
1097  else {
1098  return "disabled";
1099  }
1100  break;
1101 
1102  default:
1103  cout<<"Invalid value!"<<endl;
1104  return "invalid";
1105  }
1106  }
1107 
1108 /**
1109  * This function is used to derive int values from the ai types strings.
1110  * Returns -1 if an invalid string is passed.
1111  */
1112 int AIBehaviors::char_to_int(string ai_type) {
1113  if(ai_type == "all") {
1114  return 0;
1115  }
1116  else if(ai_type == "seek") {
1117  return 1;
1118  }
1119  else if(ai_type == "flee") {
1120  return 2;
1121  }
1122  else if(ai_type == "pursue") {
1123  return 3;
1124  }
1125  else if(ai_type == "evade") {
1126  return 4;
1127  }
1128  else if(ai_type == "arrival") {
1129  return 5;
1130  }
1131  else if(ai_type == "flock") {
1132  return 6;
1133  }
1134  else if(ai_type == "wander") {
1135  return 7;
1136  }
1137  else if(ai_type == "obstacle_avoidance") {
1138  return 8;
1139  }
1140  else if(ai_type == "pathfollow") {
1141  return 9;
1142  }
1143  else if(ai_type == "any") {
1144  return 10;
1145  }
1146  else if(ai_type == "flee_activate") {
1147  return 11;
1148  }
1149  else if(ai_type == "evade_activate") {
1150  return 12;
1151  }
1152  else if(ai_type == "arrival_activate") {
1153  return 13;
1154  }
1155  else if(ai_type == "flock_activate") {
1156  return 14;
1157  }
1158  else if(ai_type == "obstacle_avoidance_activate") {
1159  return 15;
1160  }
1161  else if(ai_type == "path_finding") {
1162  return 16;
1163  }
1164 
1165  return -1;
1166 }
1167 
1168 /**
1169  * This function turns on any aiBehavior which is passed as a string.
1170  */
1171 void AIBehaviors::turn_on(string ai_type) {
1172  switch(char_to_int(ai_type)) {
1173  case 1: {
1174  _behaviors_flags |= _seek;
1175  break;
1176  }
1177  case 2: {
1178  _behaviors_flags |= _flee;
1179  break;
1180  }
1181  case 3: {
1182  _behaviors_flags |= _pursue;
1183  break;
1184  }
1185  case 4: {
1186  _behaviors_flags |= _evade;
1187  break;
1188  }
1189  case 5: {
1190  _behaviors_flags |= _arrival;
1191  break;
1192  }
1193  case 6: {
1194  _behaviors_flags |= _flock;
1195  break;
1196  }
1197  case 7: {
1198  _behaviors_flags |= _wander;
1199  break;
1200  }
1201  case 8: {
1202  _behaviors_flags |= _obstacle_avoidance;
1203  break;
1204  }
1205  case 11:{
1206  _behaviors_flags |= _flee_activate;
1207  break;
1208  }
1209  case 12:{
1210  _behaviors_flags |= _evade_activate;
1211  break;
1212  }
1213  case 13:{
1214  _behaviors_flags |= _arrival_activate;
1215  break;
1216  }
1217  case 14:{
1218  _behaviors_flags |= _flock_activate;
1219  break;
1220  }
1221  case 15:{
1222  _behaviors_flags |= _obstacle_avoidance_activate;
1223  break;
1224  }
1225  default:
1226  cout<<"Invalid option!"<<endl;
1227  }
1228 }
1229 
1230 /**
1231  * This function turns off any aiBehavior which is passed as a string.
1232  */
1233 void AIBehaviors::turn_off(string ai_type) {
1234 switch(char_to_int(ai_type)) {
1235  case 1: {
1236  if (is_on(_seek)) {
1237  _behaviors_flags ^= _seek;
1238  }
1239  _seek_force = LVecBase3(0.0f, 0.0f, 0.0f);
1240  break;
1241  }
1242  case 2: {
1243  if (is_on(_flee)) {
1244  _behaviors_flags ^= _flee;
1245  }
1246  _flee_force = LVecBase3(0.0f, 0.0f, 0.0f);
1247  break;
1248  }
1249  case 3: {
1250  if(is_on(_pursue)) {
1251  _behaviors_flags ^= _pursue;
1252  }
1253  _pursue_force = LVecBase3(0.0f, 0.0f, 0.0f);
1254  break;
1255  }
1256  case 4: {
1257  if(is_on(_evade)) {
1258  _behaviors_flags ^= _evade;
1259  }
1260  _evade_force = LVecBase3(0.0f, 0.0f, 0.0f);
1261  break;
1262  }
1263  case 5: {
1264  if (is_on(_arrival)) {
1265  _behaviors_flags ^= _arrival;
1266  }
1267  _arrival_force = LVecBase3(0.0f, 0.0f, 0.0f);
1268  break;
1269  }
1270  case 6: {
1271  if(is_on(_flock)) {
1272  _behaviors_flags ^= _flock;
1273  }
1274  _flock_force = LVecBase3(0.0f, 0.0f, 0.0f);
1275  break;
1276  }
1277  case 7: {
1278  if(is_on(_wander)) {
1279  _behaviors_flags ^= _wander;
1280  }
1281  _wander_force = LVecBase3(0.0f, 0.0f, 0.0f);
1282  break;
1283  }
1284  case 8: {
1285  if(is_on(_obstacle_avoidance)) {
1286  _behaviors_flags ^= _obstacle_avoidance;
1287  }
1288  _obstacle_avoidance_force = LVecBase3(0.0f, 0.0f, 0.0f);
1289  break;
1290  }
1291  case 9:{
1292  turn_off("pursue");
1293  break;
1294  }
1295  case 11:{
1296  if (is_on(_flee_activate)) {
1297  _behaviors_flags ^= _flee_activate;
1298  }
1299  break;
1300  }
1301  case 12:{
1302  if (is_on(_evade_activate)) {
1303  _behaviors_flags ^= _evade_activate;
1304  }
1305  break;
1306  }
1307  case 13:{
1308  if (is_on(_arrival_activate)) {
1309  _behaviors_flags ^= _arrival_activate;
1310  }
1311  break;
1312  }
1313  case 14:{
1314  if (is_on(_flock_activate)) {
1315  _behaviors_flags ^= _flock_activate;
1316  }
1317  break;
1318  }
1319  case 15:{
1320  if (is_on(_obstacle_avoidance_activate)) {
1321  _behaviors_flags ^= _obstacle_avoidance_activate;
1322  }
1323  break;
1324  }
1325  case 16:{
1326  turn_off("pathfollow");
1327  break;
1328  }
1329  default:
1330  cout<<"Invalid option!"<<endl;
1331  }
1332 }
1333 
1334 /**
1335  * This function returns true if an aiBehavior is on
1336  */
1337 bool AIBehaviors::is_on(_behavior_type bt) {
1338  return (_behaviors_flags & bt) == bt;
1339 }
1340 
1341 /**
1342  * This function returns true if pathfollow or pathfinding is on
1343  */
1344 bool AIBehaviors::is_on(string ai_type) {
1345  if(ai_type == "pathfollow") {
1346  if(_path_follow_obj) {
1347  return (is_on(_pursue) && _path_follow_obj->_start);
1348  }
1349  else {
1350  return false;
1351  }
1352  }
1353 
1354  if(ai_type == "pathfinding") {
1355  if(_path_follow_obj && _path_find_obj) {
1356  return (is_on(_pursue) && _path_follow_obj->_start);
1357  }
1358  else {
1359  return false;
1360  }
1361  }
1362 
1363  return false;
1364 }
1365 
1366 /**
1367  * This function returns true if an aiBehavior is off
1368  */
1369 bool AIBehaviors::is_off(_behavior_type bt) {
1370  return ((_behaviors_flags | bt) == bt);
1371 }
1372 
1373 /**
1374  * This function returns true if pathfollow or pathfinding is off
1375  */
1376 bool AIBehaviors::is_off(string ai_type) {
1377  if(ai_type == "pathfollow") {
1378  if(_path_follow_obj && _path_follow_obj->_start) {
1379  return true;
1380  }
1381  else {
1382  return false;
1383  }
1384  }
1385 
1386  if(ai_type == "pathfinding") {
1387  if(_path_find_obj && _path_follow_obj && _path_follow_obj->_start) {
1388  return true;
1389  }
1390  else {
1391  return false;
1392  }
1393  }
1394 
1395  cout<<"You passed an invalid string, defaulting return value to false!"<<endl;
1396  return false;
1397 }
AIBehaviors::behavior_status
std::string behavior_status(std::string ai_type)
This function returns the status of an AI Type whether it is active, paused or disabled.
Definition: aiBehaviors.cxx:894
evade.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
AIBehaviors::is_off
bool is_off(_behavior_type bt)
This function returns true if an aiBehavior is off.
Definition: aiBehaviors.cxx:1369
Pursue::do_pursue
LVecBase3 do_pursue()
This function performs the pursue and returns a pursue force which is used in the calculate_prioritiz...
Definition: pursue.cxx:37
Evade
Definition: evade.h:22
PathFollow::add_to_path
void add_to_path(LVecBase3 pos)
This function adds the positions generated from a pathfind or a simple path follow behavior to the _p...
Definition: pathFollow.cxx:33
PathFind::path_find
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...
Definition: pathFind.cxx:203
pathFind.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Wander
Definition: wander.h:21
ObstacleAvoidance
Definition: obstacleAvoidance.h:22
PathFind
This class contains all the members and functions that are required to form an interface between the ...
Definition: pathFind.h:30
AIBehaviors::resume_ai
void resume_ai(std::string ai_type)
This function resumes individual or all the AIs.
Definition: aiBehaviors.cxx:536
AIBehaviors::is_conflict
bool is_conflict()
Checks for conflict between steering forces.
Definition: aiBehaviors.cxx:69
AIBehaviors::turn_on
void turn_on(std::string ai_type)
This function turns on any aiBehavior which is passed as a string.
Definition: aiBehaviors.cxx:1171
Arrival::do_arrival
LVecBase3 do_arrival()
This function performs the arrival and returns an arrival force which is used in the calculate_priori...
Definition: arrival.cxx:35
aiBehaviors.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
AIBehaviors::arrival
void arrival(double distance=10.0)
This function activates arrival.
Definition: aiBehaviors.cxx:683
AIBehaviors::calculate_prioritized
LVecBase3 calculate_prioritized()
This function updates the main steering force for the ai character using the accumulate function and ...
Definition: aiBehaviors.cxx:175
AIBehaviors::turn_off
void turn_off(std::string ai_type)
This function turns off any aiBehavior which is passed as a string.
Definition: aiBehaviors.cxx:1233
flee.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
AIBehaviors::init_path_find
void init_path_find(const char *navmesh_filename)
This function activates path finding in the character.
Definition: aiBehaviors.cxx:849
wander.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PathFind::dynamic_avoid
void dynamic_avoid(NodePath obstacle)
This function starts the pathfinding obstacle navigation for the passed in obstacle.
Definition: pathFind.cxx:389
AIBehaviors::remove_ai
void remove_ai(std::string ai_type)
This function removes individual or all the AIs.
Definition: aiBehaviors.cxx:322
Seek
Definition: seek.h:22
Wander::do_wander
LVecBase3 do_wander()
This function performs the wander and returns the wander force which is used in the calculate_priorit...
Definition: wander.cxx:76
pursue.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Seek::do_seek
LVecBase3 do_seek()
This function performs the seek and returns a seek force which is used in the calculate_prioritized f...
Definition: seek.cxx:48
PathFind::set_path_find
void set_path_find(const char *navmesh_filename)
This function starts the path finding process after reading the given navigation mesh.
Definition: pathFind.cxx:181
AIBehaviors::evade
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.
Definition: aiBehaviors.cxx:672
AIBehaviors::wander
void wander(double wander_radius=5.0, int flag=0, double aoe=0.0, float wander_weight=1.0)
This function activates wander.
Definition: aiBehaviors.cxx:806
seek.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PathFollow
Definition: pathFollow.h:11
Flee
Definition: flee.h:22
ObstacleAvoidance::obstacle_avoidance_activate
void obstacle_avoidance_activate()
This function activates obstacle_avoidance if a obstacle is detected.
Definition: obstacleAvoidance.cxx:74
AIBehaviors::add_dynamic_obstacle
void add_dynamic_obstacle(NodePath obstacle)
This function starts the pathfinding obstacle navigation for the passed in obstacle.
Definition: aiBehaviors.cxx:886
AIBehaviors::do_flock
LVecBase3 do_flock()
This function contains the logic for flocking behavior.
Definition: aiBehaviors.cxx:728
ObstacleAvoidance::do_obstacle_avoidance
LVecBase3 do_obstacle_avoidance()
This function returns the force necessary by the AICharacter to avoid the nearest obstacle detected b...
Definition: obstacleAvoidance.cxx:87
obstacleAvoidance.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
AIBehaviors::accumulate_force
void accumulate_force(std::string force_type, LVecBase3 force)
This function updates the individual steering forces for each of the ai characters.
Definition: aiBehaviors.cxx:120
AIBehaviors::flee
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.
Definition: aiBehaviors.cxx:645
AIBehaviors::is_on
bool is_on(_behavior_type bt)
This function returns true if an aiBehavior is on.
Definition: aiBehaviors.cxx:1337
PathFind::add_obstacle_to_mesh
void add_obstacle_to_mesh(NodePath obstacle)
This function allows the user to dynamically add obstacles to the game environment.
Definition: pathFind.cxx:336
Arrival
Definition: arrival.h:22
AIBehaviors::path_follow
void path_follow(float follow_wt)
This function activates path following.
Definition: aiBehaviors.cxx:825
PathFollow::start
void start(std::string type)
This function initiates the path follow behavior.
Definition: pathFollow.cxx:40
AIBehaviors::add_static_obstacle
void add_static_obstacle(NodePath obstacle)
This function allows the user to dynamically add obstacles to the game environment.
Definition: aiBehaviors.cxx:878
AIBehaviors::pause_ai
void pause_ai(std::string ai_type)
This function pauses individual or all the AIs.
Definition: aiBehaviors.cxx:438
Arrival::arrival_activate
void arrival_activate()
This function checks for whether the target is within the arrival distance.
Definition: arrival.cxx:92
NodePath
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
AIBehaviors::start_follow
void start_follow(std::string type="normal")
This function starts the path follower.
Definition: aiBehaviors.cxx:840
AIBehaviors::flock_activate
void flock_activate()
This function checks whether any other behavior exists to work with flock.
Definition: aiBehaviors.cxx:714
AIBehaviors::char_to_int
int char_to_int(std::string ai_type)
This function is used to derive int values from the ai types strings.
Definition: aiBehaviors.cxx:1112
PathFollow::do_follow
void do_follow()
This function allows continuous path finding by ai chars.
Definition: pathFollow.cxx:60
arrival.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
flock.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
AIBehaviors::pursue
void pursue(NodePath target_object, float pursue_wt=1.0)
This function activates pursue.
Definition: aiBehaviors.cxx:663
AIBehaviors::path_find_to
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...
Definition: aiBehaviors.cxx:859
AIBehaviors::seek
void seek(NodePath target_object, float seek_wt=1.0)
This function activates seek and makes an object of the Seek class.
Definition: aiBehaviors.cxx:631
AIBehaviors::add_to_path
void add_to_path(LVecBase3 pos)
This function adds positions to the path to follow.
Definition: aiBehaviors.cxx:832
NodePath::get_pos
LPoint3 get_pos() const
Retrieves the translation component of the transform.
Definition: nodePath.cxx:992
Pursue
Definition: pursue.h:22
AIBehaviors::flock
void flock(float flock_wt)
This function activates flock.
Definition: aiBehaviors.cxx:703
AIBehaviors::obstacle_avoidance
void obstacle_avoidance(float feeler_length=1.0)
This function activates obstacle avoidance for a given character.
Definition: aiBehaviors.cxx:816