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