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 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void accumulate_force(std::string force_type, LVecBase3 force)
This function updates the individual steering forces for each of the ai characters.
void init_path_find(const char *navmesh_filename)
This function activates path finding in the character.
void pursue(NodePath target_object, float pursue_wt=1.0)
This function activates pursue.
void add_dynamic_obstacle(NodePath obstacle)
This function starts the pathfinding obstacle navigation for the passed in obstacle.
void resume_ai(std::string ai_type)
This function resumes individual or all the AIs.
void flee(NodePath target_object, double panic_distance=10.0, double relax_distance=10.0, float flee_wt=1.0)
This function activates flee_activate and creates an object of the Flee class.
void turn_on(std::string ai_type)
This function turns on any aiBehavior which is passed as a string.
void evade(NodePath target_object, double panic_distance=10.0, double relax_distance=10.0, float evade_wt=1.0)
This function activates evade_activate.
void turn_off(std::string ai_type)
This function turns off any aiBehavior which is passed as a string.
void add_static_obstacle(NodePath obstacle)
This function allows the user to dynamically add obstacles to the game environment.
void obstacle_avoidance(float feeler_length=1.0)
This function activates obstacle avoidance for a given character.
void path_find_to(LVecBase3 pos, std::string type="normal")
This function checks for the source and target in the navigation mesh for its availability and then f...
bool is_off(_behavior_type bt)
This function returns true if an aiBehavior is off.
void path_follow(float follow_wt=1.0f)
This function activates path following.
void start_follow(std::string type="normal")
This function starts the path follower.
void wander(double wander_radius=5.0, int flag=0, double aoe=0.0, float wander_weight=1.0)
This function activates wander.
void remove_ai(std::string ai_type)
This function removes individual or all the AIs.
LVecBase3 calculate_prioritized()
This function updates the main steering force for the ai character using the accumulate function and ...
std::string behavior_status(std::string ai_type)
This function returns the status of an AI Type whether it is active, paused or disabled.
void arrival(double distance=10.0)
This function activates arrival.
void flock(float flock_wt)
This function activates flock.
void add_to_path(LVecBase3 pos)
This function adds positions to the path to follow.
void pause_ai(std::string ai_type)
This function pauses individual or all the AIs.
bool is_on(_behavior_type bt)
This function returns true if an aiBehavior is on.
void flock_activate()
This function checks whether any other behavior exists to work with flock.
LVecBase3 do_flock()
This function contains the logic for flocking behavior.
void seek(NodePath target_object, float seek_wt=1.0)
This function activates seek and makes an object of the Seek class.
int char_to_int(std::string ai_type)
This function is used to derive int values from the ai types strings.
bool is_conflict()
Checks for conflict between steering forces.
Definition: aiBehaviors.cxx:69
void arrival_activate()
This function checks for whether the target is within the arrival distance.
Definition: arrival.cxx:92
LVecBase3 do_arrival()
This function performs the arrival and returns an arrival force which is used in the calculate_priori...
Definition: arrival.cxx:35
Definition: evade.h:22
Definition: flee.h:22
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
LPoint3 get_pos() const
Retrieves the translation component of the transform.
Definition: nodePath.cxx:1044
void obstacle_avoidance_activate()
This function activates obstacle_avoidance if a obstacle is detected.
LVecBase3 do_obstacle_avoidance()
This function returns the force necessary by the AICharacter to avoid the nearest obstacle detected b...
This class contains all the members and functions that are required to form an interface between the ...
Definition: pathFind.h:30
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
void add_obstacle_to_mesh(NodePath obstacle)
This function allows the user to dynamically add obstacles to the game environment.
Definition: pathFind.cxx:336
void dynamic_avoid(NodePath obstacle)
This function starts the pathfinding obstacle navigation for the passed in obstacle.
Definition: pathFind.cxx:389
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
void do_follow()
This function allows continuous path finding by ai chars.
Definition: pathFollow.cxx:60
void start(std::string type)
This function initiates the path follow behavior.
Definition: pathFollow.cxx:40
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
Definition: pursue.h:22
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: seek.h:22
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
Definition: wander.h:21
LVecBase3 do_wander()
This function performs the wander and returns the wander force which is used in the calculate_priorit...
Definition: wander.cxx:76
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.