Panda3D
Loading...
Searching...
No Matches
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
27using std::cout;
28using std::endl;
29using std::string;
30
31static const float _PI = 3.14;
32
33AIBehaviors::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
60AIBehaviors::~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
120void 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)) {
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 */
322void 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 */
438void 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 */
536void 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 */
631void 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
636void 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 */
645void 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
652void AIBehaviors::flee(LVecBase3 pos, double panic_distance, double relax_distance, float flee_wt) {
653 _flee_obj = new Flee(_ai_char, pos, panic_distance, relax_distance, flee_wt);
654 _flee_list.insert(_flee_list.end(), *_flee_obj);
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 */
663void 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 */
672void 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 */
683void 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 */
703void 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 */
806void 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 */
816void 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 */
825void 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 */
832void 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
840void 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 */
849void 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 */
859void 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 */
868void 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 */
894string 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 */
1112int 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 */
1171void 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 */
1233void AIBehaviors::turn_off(string ai_type) {
1234switch(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 */
1337bool 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 */
1344bool 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 */
1369bool 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 */
1376bool 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.
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.
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.
void start(std::string type)
This function initiates the path follow behavior.
void add_to_path(LVecBase3 pos)
This function adds the positions generated from a pathfind or a simple path follow behavior to the _p...
LVecBase3 do_pursue()
This function performs the pursue and returns a pursue force which is used in the calculate_prioritiz...
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
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.