Add PandAI (and contribbase)

This commit is contained in:
rdb 2009-12-30 18:23:58 +00:00
parent 0f65870a60
commit fed12caf68
40 changed files with 4908 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,193 @@
// Filename: aiBehaviors.h
// Created by: Deepak, John, Navin (08Sep09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef AIBEHAVIORS_H
#define AIBEHAVIORS_H
#include "aiGlobals.h"
#include "aiCharacter.h"
#include "seek.h"
#include "flee.h"
#include "pursue.h"
#include "evade.h"
#include "arrival.h"
#include "flock.h"
#include "wander.h"
#include "pathFollow.h"
#include "pathFind.h"
#include "obstacleAvoidance.h"
class AICharacter;
class Seek;
class Flee;
class Pursue;
class Evade;
class Arrival;
class Flock;
class Wander;
class PathFollow;
class PathFind;
class ObstacleAvoidance;
typedef list<Flee, allocator<Flee> > ListFlee;
typedef list<Evade, allocator<Evade> > ListEvade;
////////////////////////////////////////////////////////////////////
// Class : AIBehaviors
// Description : This class implements all the steering behaviors
// of the AI framework, such as seek, flee, pursue,
// evade, wander and flock. Each steering behavior
// has a weight which is used when more than one type
// of steering behavior is acting on the same AI
// character. The weight decides the contribution of
// each type of steering behavior. The AICharacter
// class has a handle to an object of this class and
// this allows to invoke the steering behaviors via
// the AICharacter. This class also provides
// functionality such as pausing, resuming and
// removing the AI behaviors of an AI character at
// any time.
///////////////////////////////////////////////////////////////////
class AIBehaviors {
public:
enum BehaviorType {
BT_none = 0x00000,
BT_seek = 0x00002,
BT_flee = 0x00004,
BT_flee_activate = 0x00100,
BT_arrival = 0x00008,
BT_arrival_activate = 0x01000,
BT_wander = 0x00010,
BT_pursue = 0x00040,
BT_evade = 0x00080,
BT_evade_activate = 0x00800,
BT_flock = 0x00200,
BT_flock_activate = 0x00400,
BT_obstacle_avoidance = 0x02000,
BT_obstacle_avoidance_activate = 0x04000,
};
AICharacter *_ai_char;
Flock *_flock_group;
int _behaviors_flags;
LVecBase3f _steering_force;
Seek *_seek_obj;
LVecBase3f _seek_force;
Flee *_flee_obj;
LVecBase3f _flee_force;
// This list is used if the ai character needs to flee from
// multiple onjects.
ListFlee _flee_list;
ListFlee::iterator _flee_itr;
Pursue *_pursue_obj;
LVecBase3f _pursue_force;
Evade *_evade_obj;
LVecBase3f _evade_force;
// This list is used if the ai character needs to evade from
// multiple onjects.
ListEvade _evade_list;
ListEvade::iterator _evade_itr;
Arrival *_arrival_obj;
LVecBase3f _arrival_force;
// Since Flock is a collective behavior the variables are
// declared within the AIBehaviors class.
float _flock_weight;
LVecBase3f _flock_force;
bool _flock_done;
Wander * _wander_obj;
LVecBase3f _wander_force;
ObstacleAvoidance *_obstacle_avoidance_obj;
LVecBase3f _obstacle_avoidance_force;
PathFollow *_path_follow_obj;
PathFind *_path_find_obj;
bool _conflict, _previous_conflict;
AIBehaviors();
~AIBehaviors();
bool is_on(BehaviorType bt);
bool is_off(BehaviorType bt);
// special cases for pathfollow and pathfinding
bool is_on(string ai_type);
bool is_off(string ai_type);
void turn_on(string ai_type);
void turn_off(string ai_type);
bool is_conflict();
void accumulate_force(string force_type, LVecBase3f force);
LVecBase3f calculate_prioritized();
void flock_activate();
LVecBase3f do_flock();
int char_to_int(string ai_type);
PUBLISHED:
void seek(NodePath target_object, float seek_wt = 1.0);
void seek(LVecBase3f pos, float seek_wt = 1.0);
void flee(NodePath target_object, double panic_distance = 10.0,
double relax_distance = 10.0, float flee_wt = 1.0);
void flee(LVecBase3f pos, double panic_distance = 10.0,
double relax_distance = 10.0, float flee_wt = 1.0);
void pursue(NodePath target_object, float pursue_wt = 1.0);
void evade(NodePath target_object, double panic_distance = 10.0,
double relax_distance = 10.0, float evade_wt = 1.0);
void arrival(double distance = 10.0);
void flock(float flock_wt);
void wander(double wander_radius = 5.0, int flag =0,
double aoe = 0.0, float wander_weight = 1.0);
void obstacle_avoidance(float feeler_length = 1.0);
void path_follow(float follow_wt = 1.0);
void add_to_path(LVecBase3f pos);
void start_follow(string type = "normal");
void init_path_find(const char* navmesh_filename);
void path_find_to(LVecBase3f pos, string type = "normal");
void path_find_to(NodePath target, string type = "normal");
void add_static_obstacle(NodePath obstacle);
void add_dynamic_obstacle(NodePath obstacle);
void remove_ai(string ai_type);
void pause_ai(string ai_type);
void resume_ai(string ai_type);
string behavior_status(string ai_type);
};
#endif

View File

@ -0,0 +1,127 @@
// Filename: aiCharacter.cxx
// Created by: Deepak, John, Navin (08Sep09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "aiCharacter.h"
AICharacter::AICharacter(string model_name, NodePath model_np, double mass,
double movt_force, double max_force) {
_name = model_name;
_ai_char_np = model_np;
_mass = mass;
_max_force = max_force;
_movt_force = movt_force;
_velocity = LVecBase3f(0.0, 0.0, 0.0);
_steering_force = LVecBase3f(0.0, 0.0, 0.0);
_steering = new AIBehaviors();
_steering->_ai_char = this;
_pf_guide = false;
}
AICharacter::~AICharacter() {
}
////////////////////////////////////////////////////////////////////
// Function: update
// Description: Each character's update will update its ai and
// physics based on his resultant steering force.
// This also makes the character look in the
// direction of the force.
////////////////////////////////////////////////////////////////////
void AICharacter::update() {
if (!_steering->is_off(_steering->BT_none)) {
LVecBase3f old_pos = _ai_char_np.get_pos();
LVecBase3f steering_force = _steering->calculate_prioritized();
LVecBase3f acceleration = steering_force / _mass;
_velocity = acceleration;
LVecBase3f direction = _steering->_steering_force;
direction.normalize();
_ai_char_np.set_pos(old_pos + _velocity) ;
if (steering_force.length() > 0) {
_ai_char_np.look_at(old_pos + (direction * 5));
_ai_char_np.set_h(_ai_char_np.get_h() + 180);
_ai_char_np.set_p(-_ai_char_np.get_p());
_ai_char_np.set_r(-_ai_char_np.get_r());
}
}
else {
_steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
_steering->_seek_force = LVecBase3f(0.0, 0.0, 0.0);
_steering->_flee_force = LVecBase3f(0.0, 0.0, 0.0);
_steering->_pursue_force = LVecBase3f(0.0, 0.0, 0.0);
_steering->_evade_force = LVecBase3f(0.0, 0.0, 0.0);
_steering->_arrival_force = LVecBase3f(0.0, 0.0, 0.0);
_steering->_flock_force = LVecBase3f(0.0, 0.0, 0.0);
_steering->_wander_force = LVecBase3f(0.0, 0.0, 0.0);
}
}
LVecBase3f AICharacter::get_velocity() {
return _velocity;
}
void AICharacter::set_velocity(LVecBase3f velocity) {
_velocity = velocity;
}
double AICharacter::get_mass() {
return _mass;
}
void AICharacter::set_mass(double m) {
_mass = m;
}
double AICharacter::get_max_force() {
return _max_force;
}
void AICharacter::set_max_force(double max_force) {
_max_force = max_force;
}
NodePath AICharacter::get_node_path() {
return _ai_char_np;
}
void AICharacter::set_node_path(NodePath np) {
_ai_char_np = np;
}
AIBehaviors * AICharacter::get_ai_behaviors() {
return _steering;
}
void AICharacter::set_char_render(NodePath render) {
_window_render = render;
}
NodePath AICharacter::get_char_render() {
return _window_render;
}
void AICharacter::set_pf_guide(bool pf_guide) {
_pf_guide = pf_guide;
}

View File

@ -0,0 +1,76 @@
// Filename: aiCharacter.h
// Created by: Deepak, John, Navin (08Sep09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef AICHARACTER_H
#define AICHARACTER_H
#include "aiBehaviors.h"
#include "aiWorld.h"
class AIBehaviors;
class AIWorld;
////////////////////////////////////////////////////////////////////
// Class : AICharacter
// Description : This class is used for creating the ai characters.
// It assigns both physics and ai attributes to the
// character. It also has an update function which
// updates the physics and ai of the character.
// This update function is called by the AIWorld
// update.
////////////////////////////////////////////////////////////////////
class AICharacter {
public:
double _mass;
double _max_force;
LVecBase3f _velocity;
LVecBase3f _steering_force;
string _name;
double _movt_force;
unsigned int _ai_char_flock_id;
AIWorld *_world;
AIBehaviors *_steering;
NodePath _window_render;
NodePath _ai_char_np;
bool _pf_guide;
void update();
void set_velocity(LVecBase3f vel);
void set_char_render(NodePath render);
NodePath get_char_render();
PUBLISHED:
double get_mass();
void set_mass(double m);
LVecBase3f get_velocity();
double get_max_force();
void set_max_force(double max_force);
NodePath get_node_path();
void set_node_path(NodePath np);
AIBehaviors * get_ai_behaviors();
// This function is used to enable or disable the guides
// for path finding.
void set_pf_guide(bool pf_guide);
AICharacter(string model_name, NodePath model_np, double mass,
double movt_force, double max_force);
~AICharacter();
};
#endif

View File

@ -0,0 +1,28 @@
// Filename: aiGlobals.h
// Created by: Deepak, John, Navin (08Sep09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef AIGLOBALS_H
#define AIGLOBALS_H
#include "pandaFramework.h"
#include "textNode.h"
#include "pandaSystem.h"
#include "lvecBase3.h"
#include "nodePath.h"
#include "genericAsyncTask.h"
#include "asyncTaskManager.h"
#endif

53
contrib/src/ai/aiNode.cxx Normal file
View File

@ -0,0 +1,53 @@
// Filename: aiNode.cxx
// Created by: Deepak, John, Navin (19Nov2009)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "aiNode.h"
AINode::AINode(int grid_x, int grid_y, LVecBase3f pos, float w, float l, float h) {
for (int i = 0; i < 8; ++i) {
_neighbours[i] = NULL;
}
_position = pos;
_width = w;
_length = l;
_height = h;
_grid_x = grid_x;
_grid_y = grid_y;
_status = ST_neutral;
_type = true;
_score = 0;
_cost = 0;
_heuristic = 0;
_next = NULL;
_prv_node = NULL;
}
AINode::~AINode() {
}
////////////////////////////////////////////////////////////////////
// Function: contains
// Description: This is a handy function which returns true if the
// passed position is within the node's dimensions.
////////////////////////////////////////////////////////////////////
bool AINode::contains(float x, float y) {
if (_position.get_x() - _width / 2 <= x && _position.get_x() + _width / 2 >= x &&
_position.get_y() - _length / 2 <= y && _position.get_y() + _length / 2 >= y) {
return true;
}
else {
return false;
}
}

85
contrib/src/ai/aiNode.h Normal file
View File

@ -0,0 +1,85 @@
// Filename: aiNode.h
// Created by: Deepak, John, Navin (18Nov2009)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef AINODE_H
#define AINODE_H
#include "aiGlobals.h"
////////////////////////////////////////////////////////////////////
// Class : AINode
// Description : This class is used to assign the nodes on the mesh.
// It holds all the data necessary to compute A*
// algorithm. It also maintains a lot of vital
// information such as the neighbor nodes of each
// node and also its position on the mesh.
// Note: The Mesh Generator which is a standalone
// tool makes use of this class to generate the nodes
// on the mesh.
////////////////////////////////////////////////////////////////////
class AINode {
public:
// This variable specifies whether the node is an obtacle or not.
// Used for dynamic obstacle addition to the environment.
// obstacle = false
// navigational = true
bool _type;
// This variable specifies the node status whether open, close
// or neutral.
// open = belongs to _open_list.
// close = belongs to _closed_list.
// neutral = unexamined node.
enum Status {
ST_open,
ST_close,
ST_neutral
};
Status _status;
// The score is used to compute the traversal expense to nodes
// when using A*.
// _score = _cost + heuristic
int _score;
int _cost;
int _heuristic;
// Used to trace back the path after it is generated using A*.
AINode *_prv_node;
// Position of the node in the 2d grid.
int _grid_x, _grid_y;
// Position of the node in 3D space.
LVecBase3f _position;
// Dimensions of each face / cell on the mesh.
// Height is given in case of expansion to a 3d mesh. Currently
// not used.
float _width, _length ,_height;
AINode *_neighbours[8]; // anti-clockwise from top left corner.
// The _next pointer is used for traversal during mesh
// generation from the model.
// Note: The data in this member is discarded when mesh data
// is written into navmesh.csv file.
AINode *_next;
AINode(int grid_x, int grid_y, LVecBase3f pos, float w, float l, float h);
~AINode();
bool contains(float x, float y);
};
#endif

View File

@ -0,0 +1,377 @@
// Filename: aiPathfinder.cxx
// Created by: Deepak, John, Navin (08Sep09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "aiPathFinder.h"
PathFinder::PathFinder(NavMesh nav_mesh) {
_grid = nav_mesh;
}
PathFinder::~PathFinder() {
}
////////////////////////////////////////////////////////////////////
// Function: find_path
// Description: This function initializes the pathfinding process
// by accepting the source and destination nodes.
// It then calls the generate_path().
////////////////////////////////////////////////////////////////////
void PathFinder::find_path(AINode *src_node, AINode *dest_node) {
_src_node = src_node;
_dest_node = dest_node;
// Add a dummy node as the first element of the open list with score
// = -1.
// Inorder to implement a binary heap the index of the elements
// should never be 0.
AINode *_dummy_node = new AINode(-1, -1, LVecBase3f(0.0, 0.0, 0.0), 0, 0, 0);
_dummy_node->_status = _dummy_node->ST_open;
_dummy_node->_score = -1;
_open_list.push_back(_dummy_node);
// Add the source node to the open list.
add_to_olist(_src_node);
// Generate the path.
generate_path();
}
////////////////////////////////////////////////////////////////////
// Function: generate_path
// Description: This function performs the pathfinding process
// using the A* algorithm.
// It updates the openlist and closelist.
////////////////////////////////////////////////////////////////////
void PathFinder::generate_path() {
// All the A* algorithm is implemented here.
// The check is > 1 due to the existence of the dummy node.
while (_open_list.size() > 1) {
// The first element of the open list will always be the optimal
// node.
// This is because the open list is a binary heap with element
// having the smallest score at the top of the heap.
AINode* nxt_node = _open_list[1];
if (nxt_node->_grid_x == _dest_node->_grid_x &&
nxt_node->_grid_y == _dest_node->_grid_y) {
// Remove the optimal node from the top of the heap.
remove_from_olist();
// add the used node to the closed list.
add_to_clist(nxt_node);
// At this point the destination is reached.
return;
}
else {
identify_neighbors(nxt_node);
// add the used node to the closed list.
add_to_clist(nxt_node);
}
}
cout << "DESTINATION NOT REACHABLE MATE!\n";
_closed_list.clear();
}
////////////////////////////////////////////////////////////////////
// Function: identify_neighbors
// Description: This function traverses through the 8 neigbors of
// the parent node and then adds the neighbors to the
// _open_list based on A* criteria.
////////////////////////////////////////////////////////////////////
void PathFinder::identify_neighbors(AINode *parent_node) {
// Remove the parent node from the open_list so that it is not considered
// while adding new nodes to the open list heap.
remove_from_olist();
for (int i = 0; i < 8; ++i) {
if (parent_node->_neighbours[i] != NULL) {
if (parent_node->_neighbours[i]->_status == parent_node->_neighbours[i]->ST_neutral
&& parent_node->_neighbours[i]->_type == true) {
// Link the neighbor to the parent node.
parent_node->_neighbours[i]->_prv_node = parent_node;
// Calculate and update the score for the node.
calc_node_score(parent_node->_neighbours[i]);
// Add the neighbor to the open list.
add_to_olist(parent_node->_neighbours[i]);
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: calc_node_score
// Description: This function calculates the score of each node.
// Score = Cost + Heuristics.
////////////////////////////////////////////////////////////////////
void PathFinder::calc_node_score(AINode *nd) {
nd->_cost = calc_cost_frm_src(nd);
nd->_heuristic = calc_heuristic(nd);
nd->_score = nd->_cost + nd->_heuristic;
}
////////////////////////////////////////////////////////////////////
// Function: calc_cost_frm_src
// Description: This function calculates the cost of each node by
// finding out the number of node traversals required
// to reach the source node.
// Diagonal traversals have have cost = 14.
// Horizontal / Vertical traversals have cost = 10.
////////////////////////////////////////////////////////////////////
int PathFinder::calc_cost_frm_src(AINode *nd) {
int cost = 0;
AINode *start_node = nd;
while (start_node->_prv_node != _src_node) {
if (is_diagonal_node(start_node)) {
cost += 14;
}
else {
cost += 10;
}
start_node = start_node->_prv_node;
}
// Add the cost of traversal to the source node also.
if (is_diagonal_node(start_node)) {
cost += 14;
}
else {
cost += 10;
}
return cost;
}
////////////////////////////////////////////////////////////////////
// Function: calc_heuristic
// Description: This function calculates the heuristic of the nodes
// using Manhattan method. All it does is predict the
// number of node traversals required to reach the
// target node. No diagonal traversals are allowed
// in this technique.
////////////////////////////////////////////////////////////////////
int PathFinder::calc_heuristic(AINode *nd) {
int row_diff = abs(_dest_node->_grid_x - nd->_grid_x);
int col_diff = abs(_dest_node->_grid_y - nd->_grid_y);
int heuristic = 10 * (row_diff + col_diff);
return heuristic;
}
////////////////////////////////////////////////////////////////////
// Function: is_diagonal_node
// Description: This function checks if the traversal from a
// node is diagonal.
////////////////////////////////////////////////////////////////////
bool PathFinder::is_diagonal_node(AINode *nd) {
// Calculate the row and column differences between child and parent
// nodes.
float row_diff = nd->_grid_x - nd->_prv_node->_grid_x;
float col_diff = nd->_grid_y - nd->_prv_node->_grid_y;
// Check if the relationship between child and parent node is
// diagonal.
if (row_diff == 0 || col_diff == 0) {
return false;
}
else {
return true;
}
}
////////////////////////////////////////////////////////////////////
// Function: add_to_olist
// Description: This function adds a node to the open list heap.
// A binay heap is maintained to improve the search.
////////////////////////////////////////////////////////////////////
void PathFinder::add_to_olist(AINode *nd) {
// Variables required to search the binary heap.
AINode *child_node, *parent_node;
int child_idx, parent_idx;
// Set the status as open.
nd->_status = nd->ST_open;
// Add the node to the open list.
_open_list.push_back(nd);
// Find the parent and child nodes and create temporary nodes out
// of them. In a binary heap the children of a parent node are
// always i*2 and i*2 + 1, where i is the index of the parent node
// in the heap. And hence, the parent of a node can be easily found
// out by dividing by 2 and rounding it.
child_idx = _open_list.size() - 1;
parent_idx = child_idx / 2;
child_node = _open_list[child_idx];
parent_node = _open_list[parent_idx];
// Keep traversing the heap until the lowest element in the list is
// bubbled
// to the top of the heap.
while (_open_list[child_idx]->_score <= _open_list[parent_idx]->_score) {
// Swap the parent node and the child node.
_open_list[parent_idx] = child_node;
_open_list[child_idx] = parent_node;
// Update the new child and parent indices.
child_idx = parent_idx;
parent_idx = child_idx / 2;
// Update the new child and parent nodes.
child_node = _open_list[child_idx];
parent_node = _open_list[parent_idx];
}
// At this point the AINode with the smallest score will be at the
// top of the heap.
}
////////////////////////////////////////////////////////////////////
// Function: remove_from_olist
// Description: This function removes a node from the open list.
// During the removal the binary heap is maintained.
////////////////////////////////////////////////////////////////////
void PathFinder::remove_from_olist() {
// Variables for maintaining the binary heap.
AINode *child_node, *child_node_1, *child_node_2;
int child_idx, child_idx_1, child_idx_2;
// Remove the AINode at index 1 from the open list binary heap.
// Note: AINode at index 0 of open list is a dummy node.
_open_list.erase(_open_list.begin() + 1);
if (_open_list.size() > 1) {
// Store the last element in the open list to a temp_node.
AINode *temp_node = _open_list[_open_list.size() - 1];
// Shift the elements of the open list to the right by 1 element
// circularly, excluding element at 0 index.
for (int i = _open_list.size() - 1; i > 1; --i) {
_open_list[i] = _open_list[i - 1];
}
// Assign the temp_node to 1st element in the open list.
_open_list[1] = temp_node;
// Set the iterator for traversing the node from index 1 in
// the heap.
unsigned int k = 1;
// This loop traverses down the open list till the node reaches
// the correct position in the binary heap.
while (true) {
if ((k * 2 + 1) < _open_list.size()) {
// Two children exists for the parent node.
child_idx_1 = k * 2;
child_idx_2 = k * 2 + 1;
child_node_1 = _open_list[child_idx_1];
child_node_2 = _open_list[child_idx_2];
if (_open_list[child_idx_1]->_score < _open_list[child_idx_2]->_score) {
if (_open_list[k]->_score > _open_list[child_idx_1]->_score) {
// Swap the parent node and the child node.
_open_list[child_idx_1] = _open_list[k];
_open_list[k] = child_node_1;
// Update the parent node index.
k = child_idx_1;
}
else {
break;
}
}
else {
if (_open_list[k]->_score > _open_list[child_idx_2]->_score) {
// Swap the parent node and the child node.
_open_list[child_idx_2] = _open_list[k];
_open_list[k] = child_node_2;
// Update the parent node index.
k = child_idx_2;
}
else {
break;
}
}
}
else if ((k * 2) < _open_list.size()) {
// Only one child exists for the parent node.
child_idx = k * 2;
child_node = _open_list[child_idx];
if (_open_list[k]->_score > _open_list[child_idx]->_score) {
// Swap the parent node and the child node.
_open_list[child_idx] = _open_list[k];
_open_list[k] = child_node;
// Update the parent node index.
k = child_idx;
}
else {
break;
}
}
else {
// No children exists.
break;
}
}
}
// At this point the AINode was succesfully removed and the binary
// heap re-arranged.
}
////////////////////////////////////////////////////////////////////
// Function: add_to_clist
// Description: This function adds a node to the closed list.
////////////////////////////////////////////////////////////////////
void PathFinder::add_to_clist(AINode *nd) {
// Set the status as closed.
nd->_status = nd->ST_close;
// Add the node to the close list.
_closed_list.push_back(nd);
}
////////////////////////////////////////////////////////////////////
// Function: remove_from_clist
// Description: This function removes a node from the closed list.
////////////////////////////////////////////////////////////////////
void PathFinder::remove_from_clist(int r, int c) {
for (unsigned int i = 0; i < _closed_list.size(); ++i) {
if (_closed_list[i]->_grid_x == r && _closed_list[i]->_grid_y == c) {
_closed_list.erase(_closed_list.begin() + i);
break;
}
}
}
////////////////////////////////////////////////////////////////////
// Function: find_in_mesh
// Description: This function allows the user to pass a position
// and it returns the corresponding node on the
// navigation mesh. A very useful function as it allows
// for dynamic updation of the mesh based on position.
////////////////////////////////////////////////////////////////////
AINode* find_in_mesh(NavMesh nav_mesh, LVecBase3f pos, int grid_size) {
int size = grid_size;
float x = pos[0];
float y = pos[1];
for (int i = 0; i < size; ++i) {
for (int j = 0; j < size; ++j) {
if (nav_mesh[i][j] != NULL && nav_mesh[i][j]->contains(x, y)) {
return (nav_mesh[i][j]);
}
}
}
return NULL;
}

View File

@ -0,0 +1,61 @@
// Filename: aiPathfinder.h
// Created by: Deepak, John, Navin (08Sep09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef PATHFINDER_H
#define PATHFINDER_H
#include "aiNode.h"
#include "cmath.h"
#include "lineSegs.h"
typedef vector<AINode *> NodeArray;
typedef vector<NodeArray> NavMesh;
AINode* find_in_mesh(NavMesh nav_mesh, LVecBase3f pos, int grid_size);
////////////////////////////////////////////////////////////////////
// Class : PathFinder
// Description : This class implements pathfinding using the A*
// algorithm. It also uses a Binary Heap search to
// search the open list. The heuristics are
// calculated using the manhattan method.
////////////////////////////////////////////////////////////////////
class PathFinder {
public:
AINode *_src_node;
AINode *_dest_node;
vector<AINode*> _open_list;
vector<AINode*> _closed_list;
NavMesh _grid;
void identify_neighbors(AINode *nd);
int calc_cost_frm_src(AINode *nd);
int calc_heuristic(AINode *nd);
void calc_node_score(AINode *nd);
bool is_diagonal_node(AINode *nd);
void add_to_olist(AINode *nd);
void remove_from_olist();
void add_to_clist(AINode *nd);
void remove_from_clist(int r, int c);
void generate_path();
void find_path(AINode *src_node, AINode *dest_node);
PathFinder(NavMesh nav_mesh);
~PathFinder();
};
#endif

258
contrib/src/ai/aiWorld.cxx Normal file
View File

@ -0,0 +1,258 @@
// Filename: aiWorld.cxx
// Created by: Deepak, John, Navin (08Sep09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "aiWorld.h"
AIWorld::AIWorld(NodePath render) {
_ai_char_pool = new AICharPool();
_render = render;
}
AIWorld::~AIWorld() {
}
void AIWorld::add_ai_char(AICharacter *ai_char) {
_ai_char_pool->append(ai_char);
ai_char->_window_render = _render;
ai_char->_world = this;
}
void AIWorld::remove_ai_char(string name) {
_ai_char_pool->del(name);
remove_ai_char_from_flock(name);
}
void AIWorld::remove_ai_char_from_flock(string name) {
AICharPool::node *ai_pool;
ai_pool = _ai_char_pool->_head;
while ((ai_pool) != NULL) {
for (unsigned int i = 0; i < _flock_pool.size(); ++i) {
if (ai_pool->_ai_char->_ai_char_flock_id == _flock_pool[i]->get_id()) {
for (unsigned int j = 0; j<_flock_pool[i]->_ai_char_list.size(); ++j) {
if (_flock_pool[i]->_ai_char_list[j]->_name == name) {
_flock_pool[i]->_ai_char_list.erase(_flock_pool[i]->_ai_char_list.begin() + j);
return;
}
}
}
}
ai_pool = ai_pool->_next;
}
}
void AIWorld::print_list() {
_ai_char_pool->print_list();
}
////////////////////////////////////////////////////////////////////
// Function: update
// Description: The AIWorld update function calls the update
// function of all the AI characters which have been
// added to the AIWorld.
////////////////////////////////////////////////////////////////////
void AIWorld::update() {
AICharPool::node *ai_pool;
ai_pool = _ai_char_pool->_head;
while ((ai_pool)!=NULL) {
ai_pool->_ai_char->update();
ai_pool = ai_pool->_next;
}
}
////////////////////////////////////////////////////////////////////
// Function: add_flock
// Description: This function adds all the AI characters in the
// Flock object to the AICharPool. This function
// allows adding the AI characetrs as part of a flock.
////////////////////////////////////////////////////////////////////
void AIWorld::add_flock(Flock *flock) {
// Add all the ai_characters in the flock to the AIWorld.
for (unsigned int i = 0; i < flock->_ai_char_list.size(); ++i) {
this->add_ai_char(flock->_ai_char_list[i]);
}
// Add the flock to the flock pool.
_flock_pool.push_back(flock);
}
////////////////////////////////////////////////////////////////////
//
// Function: get_flock
// Description: This function returns a handle to the Flock whose
// id is passed.
////////////////////////////////////////////////////////////////////
Flock AIWorld::get_flock(unsigned int flock_id) {
for (unsigned int i=0; i < _flock_pool.size(); ++i) {
if (_flock_pool[i]->get_id() == flock_id) {
return *_flock_pool[i];
}
}
Flock *null_flock = NULL;
return *null_flock;
}
////////////////////////////////////////////////////////////////////
// Function: remove_flock
// Description: This function removes the flock behavior completely.
////////////////////////////////////////////////////////////////////
void AIWorld::remove_flock(unsigned int flock_id) {
for (unsigned int i = 0; i < _flock_pool.size(); ++i) {
if (_flock_pool[i]->get_id() == flock_id) {
for (unsigned int j = 0; j < _flock_pool[i]->_ai_char_list.size(); ++j) {
_flock_pool[i]->_ai_char_list[j]->get_ai_behaviors()->turn_off("flock_activate");
_flock_pool[i]->_ai_char_list[j]->get_ai_behaviors()->turn_off("flock");
_flock_pool[i]->_ai_char_list[j]->get_ai_behaviors()->_flock_group = NULL;
}
_flock_pool.erase(_flock_pool.begin() + i);
break;
}
}
}
////////////////////////////////////////////////////////////////////
// Function: flock_off
// Description: This function turns off the flock behavior
// temporarily. Similar to pausing the behavior.
////////////////////////////////////////////////////////////////////
void AIWorld::flock_off(unsigned int flock_id) {
for (unsigned int i = 0; i < _flock_pool.size(); ++i) {
if (_flock_pool[i]->get_id() == flock_id) {
for (unsigned int j = 0; j < _flock_pool[i]->_ai_char_list.size(); ++j) {
_flock_pool[i]->_ai_char_list[j]->get_ai_behaviors()->turn_off("flock_activate");
_flock_pool[i]->_ai_char_list[j]->get_ai_behaviors()->turn_off("flock");
}
break;
}
}
}
////////////////////////////////////////////////////////////////////
// Function: flock_on
// Description: This function turns on the flock behavior.
////////////////////////////////////////////////////////////////////
void AIWorld::flock_on(unsigned int flock_id) {
for (unsigned int i = 0; i < _flock_pool.size(); ++i) {
if (_flock_pool[i]->get_id() == flock_id) {
for (unsigned int j = 0; j < _flock_pool[i]->_ai_char_list.size(); ++j) {
_flock_pool[i]->_ai_char_list[j]->get_ai_behaviors()->turn_on("flock_activate");
}
break;
}
}
}
AICharPool::AICharPool() {
_head = NULL;
}
AICharPool::~AICharPool() {
}
void AICharPool::append(AICharacter *ai_ch) {
node *q;
node *t;
if (_head == NULL) {
q = new node();
q->_ai_char = ai_ch;
q->_next = NULL;
_head = q;
}
else {
q = _head;
while ( q->_next != NULL) {
q = q->_next;
}
t = new node();
t->_ai_char = ai_ch;
t->_next = NULL;
q->_next = t;
}
}
void AICharPool::del(string name) {
node *q;
node *r;
q = _head;
if (_head == NULL) {
return;
}
// Only one node in the linked list
if (q->_next == NULL) {
if (q->_ai_char->_name == name) {
_head = NULL;
delete q;
}
return;
}
r = q;
while ( q != NULL) {
if ( q->_ai_char->_name == name) {
// Special case
if (q == _head) {
_head = q->_next;
delete q;
return;
}
r->_next = q->_next;
delete q;
return;
}
r = q;
q = q->_next;
}
}
////////////////////////////////////////////////////////////////////
// Function: print_list
// Description: This function prints the ai characters in the
// AICharPool. Used for debugging purposes.
////////////////////////////////////////////////////////////////////
void AICharPool::print_list() {
node* q;
q = _head;
while (q != NULL) {
cout << q->_ai_char->_name << "\n";
q = q->_next;
}
}
////////////////////////////////////////////////////////////////////
// Function: add_obstacle
// Description: This function adds the nodepath as an obstacle that
// is needed by the obstacle avoidance behavior.
////////////////////////////////////////////////////////////////////
void AIWorld::add_obstacle(NodePath obstacle) {
_obstacles.push_back(obstacle);
}
////////////////////////////////////////////////////////////////////
// Function: remove_obstacle
// Description: This function removes the nodepath from the
// obstacles list that is needed by the obstacle
// avoidance behavior.
////////////////////////////////////////////////////////////////////
void AIWorld::remove_obstacle(NodePath obstacle) {
for (unsigned int i = 0; i <= _obstacles.size(); ++i) {
if (_obstacles[i] == obstacle) {
_obstacles.erase(_obstacles.begin() + i);
}
}
}

87
contrib/src/ai/aiWorld.h Normal file
View File

@ -0,0 +1,87 @@
// Filename: aiWorld.h
// Created by: Deepak, John, Navin (08Sep09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef AIWORLD_H
#define AIWORLD_H
#include "aiGlobals.h"
#include "aiCharacter.h"
#include "flock.h"
class AICharacter;
class Flock;
////////////////////////////////////////////////////////////////////
// Class : AICharPool
// Description : This class implements a linked list of AI
// Characters allowing the user to add and delete
// characters from the linked list.
// This will be used in the AIWorld class.
////////////////////////////////////////////////////////////////////
class AICharPool {
public:
struct node {
AICharacter * _ai_char;
node * _next;
};
node* _head;
AICharPool();
~AICharPool();
void append(AICharacter *ai_ch);
void del(string name);
void print_list();
};
////////////////////////////////////////////////////////////////////
// Class : AIWorld
// Description : A class that implements the virtual AI world which
// keeps track of the AI characters active at any
// given time. It contains a linked list of AI
// characters, obstactle data and unique name for each
// character. It also updates each characters state.
// The AI characters can also be added to the world
// as flocks.
////////////////////////////////////////////////////////////////////
class AIWorld {
private:
AICharPool * _ai_char_pool;
NodePath _render;
public:
vector<NodePath> _obstacles;
typedef std::vector<Flock*> FlockPool;
FlockPool _flock_pool;
void remove_ai_char_from_flock(string name);
PUBLISHED:
AIWorld(NodePath render);
~AIWorld();
void add_ai_char(AICharacter *ai_ch);
void remove_ai_char(string name);
void add_flock(Flock *flock);
void flock_off(unsigned int flock_id);
void flock_on(unsigned int flock_id);
void remove_flock(unsigned int flock_id);
Flock get_flock(unsigned int flock_id);
void add_obstacle(NodePath obstacle);
void remove_obstacle(NodePath obstacle);
void print_list();
void update();
};
#endif

View File

@ -0,0 +1 @@
#include "ai_composite1.cxx"

View File

@ -0,0 +1,20 @@
#include "config_ai.cxx"
#include "aiWorld.cxx"
#include "aiCharacter.cxx"
#include "aiBehaviors.cxx"
#include "seek.cxx"
#include "flee.cxx"
#include "pursue.cxx"
#include "evade.cxx"
#include "arrival.cxx"
#include "flock.cxx"
#include "wander.cxx"
#include "pathFollow.cxx"
#include "obstacleAvoidance.cxx"
#include "pathFind.cxx"
#include "aiNode.cxx"
#include "aiPathFinder.cxx"

120
contrib/src/ai/arrival.cxx Normal file
View File

@ -0,0 +1,120 @@
// Filename: arrival.cxx
// Created by: Deepak, John, Navin (24Oct09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "arrival.h"
Arrival::Arrival(AICharacter *ai_ch, double distance) {
_ai_char = ai_ch;
_arrival_distance = distance;
_arrival_done = false;
}
Arrival::~Arrival() {
}
////////////////////////////////////////////////////////////////////
// Function: do_arrival
// Description: This function performs the arrival and returns an
// arrival force which is used in the
// calculate_prioritized function. In case the steering
// force is zero, it resets to arrival_activate. The
// arrival behavior works only when seek or pursue is
// active. This function is not to be used by the user.
////////////////////////////////////////////////////////////////////
LVecBase3f Arrival::do_arrival() {
LVecBase3f direction_to_target;
double distance;
if (_arrival_type) {
direction_to_target = _ai_char->get_ai_behaviors()->_pursue_obj->_pursue_target.get_pos(_ai_char->_window_render)
- _ai_char->_ai_char_np.get_pos(_ai_char->_window_render);
}
else {
direction_to_target = _ai_char->get_ai_behaviors()->_seek_obj->_seek_position
- _ai_char->_ai_char_np.get_pos(_ai_char->_window_render);
}
distance = direction_to_target.length();
_arrival_direction = direction_to_target;
_arrival_direction.normalize();
if (int(distance) == 0) {
_ai_char->_steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
_ai_char->_steering->_arrival_force = LVecBase3f(0.0, 0.0, 0.0);
if (_ai_char->_steering->_seek_obj != NULL) {
_ai_char->_steering->turn_off("arrival");
_ai_char->_steering->turn_on("arrival_activate");
}
_arrival_done = true;
return (LVecBase3f(0.0, 0.0, 0.0));
}
else {
_arrival_done = false;
}
double u = _ai_char->get_velocity().length();
LVecBase3f desired_force = ((u * u) / (2 * distance)) * _ai_char->get_mass();
if (_ai_char->_steering->_seek_obj != NULL) {
return (desired_force);
}
if (_ai_char->_steering->_pursue_obj != NULL) {
if (distance > _arrival_distance) {
_ai_char->_steering->turn_off("arrival");
_ai_char->_steering->turn_on("arrival_activate");
_ai_char->_steering->resume_ai("pursue");
}
return (desired_force);
}
cout << "Arrival works only with seek and pursue\n";
return (LVecBase3f(0.0, 0.0, 0.0));
}
////////////////////////////////////////////////////////////////////
// Function: arrival_activate
// Description: This function checks for whether the target is
// within the arrival distance. When this is true,
// it calls the do_arrival function and sets the
// arrival direction.
// This function is not to be used by the user.
////////////////////////////////////////////////////////////////////
void Arrival::arrival_activate() {
LVecBase3f dirn;
if (_arrival_type) {
dirn = (_ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _ai_char->get_ai_behaviors()->_pursue_obj->_pursue_target.get_pos(_ai_char->_window_render));
}
else {
dirn = (_ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _ai_char->get_ai_behaviors()->_seek_obj->_seek_position);
}
double distance = dirn.length();
if (distance < _arrival_distance && _ai_char->_steering->_steering_force.length() > 0) {
_ai_char->_steering->turn_off("arrival_activate");
_ai_char->_steering->turn_on("arrival");
if (_ai_char->_steering->is_on(_ai_char->_steering->BT_seek)) {
_ai_char->_steering->turn_off("seek");
}
if (_ai_char->_steering->is_on(_ai_char->_steering->BT_pursue)) {
_ai_char->_steering->pause_ai("pursue");
}
}
}

49
contrib/src/ai/arrival.h Normal file
View File

@ -0,0 +1,49 @@
// Filename: arrival.h
// Created by: Deepak, John, Navin (24Oct09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef ARRIVAL_H
#define ARRIVAL_H
#include "aiGlobals.h"
#include "aiCharacter.h"
class AICharacter;
////////////////////////////////////////////////////////////////////
// Class : Arrival
// Description : This class handles all calls to the arrival behavior
////////////////////////////////////////////////////////////////////
class Arrival {
public:
AICharacter *_ai_char;
NodePath _arrival_target;
LVecBase3f _arrival_target_pos;
double _arrival_distance;
LVecBase3f _arrival_direction;
bool _arrival_done;
// This flag specifies if the arrival behavior is being used with
// seek or pursue behavior.
// True = used with pursue.
// False = used with seek.
bool _arrival_type;
Arrival(AICharacter *ai_ch, double distance = 10.0);
~Arrival();
LVecBase3f do_arrival();
void arrival_activate();
};
#endif

View File

@ -0,0 +1,55 @@
// Filename: config_ai.cxx
// Created by: Pandai (13Sep09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "config_ai.h"
#include "aiWorld.h"
#include "aiCharacter.h"
#include "aiBehaviors.h"
#include "seek.h"
#include "flee.h"
#include "pursue.h"
#include "evade.h"
#include "arrival.h"
#include "flock.h"
#include "wander.h"
#include "pathFollow.h"
#include "obstacleAvoidance.h"
#include "pathFind.h"
#include "aiNode.h"
#include "aiPathFinder.h"
#include "dconfig.h"
Configure(config_ai);
NotifyCategoryDef(ai, "");
ConfigureFn(config_ai) {
init_libai();
}
////////////////////////////////////////////////////////////////////
// Function: init_libai
// Description: Initializes the library. This must be called at
// least once before any of the functions or classes in
// this library can be used. Normally it will be
// called by the static initializers and need not be
// called explicitly, but special cases exist.
////////////////////////////////////////////////////////////////////
void
init_libai() {
static bool initialized = false;
if (initialized) {
return;
}
initialized = true;
}

View File

@ -0,0 +1,26 @@
// Filename: config_ai.h
// Created by: Pandai (13Sep09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef CONFIG_AI_H
#define CONFIG_AI_H
#include "contribbase.h"
#include "notifyCategoryProxy.h"
NotifyCategoryDecl(ai, EXPCL_PANDAAI, EXPTP_PANDAAI);
extern EXPCL_PANDAAI void init_libai();
#endif

86
contrib/src/ai/evade.cxx Normal file
View File

@ -0,0 +1,86 @@
// Filename: evade.cxx
// Created by: Deepak, John, Navin (24Oct09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "evade.h"
Evade::
Evade(AICharacter *ai_ch, NodePath target_object,
double panic_distance, double relax_distance, float evade_wt) {
_ai_char = ai_ch;
_evade_target = target_object;
_evade_distance = panic_distance;
_evade_relax_distance = relax_distance;
_evade_weight = evade_wt;
_evade_done = true;
_evade_activate_done = false;
}
Evade::~Evade() {
}
////////////////////////////////////////////////////////////////////
// Function: do_evade
// Description: This function performs the evade and returns an
// evade force which is used in the
// calculate_prioritized function. In case the
// AICharacter is past the (panic + relax) distance,
// it resets to evade_activate. This function is not
// to be used by the user.
////////////////////////////////////////////////////////////////////
LVecBase3f Evade::do_evade() {
assert(_evade_target && "evade target not assigned");
_evade_direction = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render)
- _evade_target.get_pos(_ai_char->_window_render);
double distance = _evade_direction.length();
_evade_direction.normalize();
LVecBase3f desired_force = _evade_direction * _ai_char->_movt_force;
if (distance > (_evade_distance + _evade_relax_distance)) {
if ((_ai_char->_steering->_behaviors_flags |
_ai_char->_steering->BT_evade) == _ai_char->_steering->BT_evade) {
_ai_char->_steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
}
_ai_char->_steering->turn_off("evade");
_ai_char->_steering->turn_on("evade_activate");
_evade_done = true;
return (LVecBase3f(0.0, 0.0, 0.0));
} else {
_evade_done = false;
return (desired_force);
}
}
////////////////////////////////////////////////////////////////////
// Function: evade_activate
// Description: This function checks for whether the target is
// within the panic distance.
// When this is true, it calls the do_evade function
// and sets the evade direction.
// This function is not to be used by the user.
////////////////////////////////////////////////////////////////////
void Evade::evade_activate() {
_evade_direction = (_ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _evade_target.get_pos(_ai_char->_window_render));
double distance = _evade_direction.length();
_evade_activate_done = false;
if (distance < _evade_distance) {
_ai_char->_steering->turn_off("evade_activate");
_ai_char->_steering->turn_on("evade");
_evade_activate_done = true;
}
}

48
contrib/src/ai/evade.h Normal file
View File

@ -0,0 +1,48 @@
// Filename: evade.h
// Created by: Deepak, John, Navin (24Oct09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef EVADE_H
#define EVADE_H
#include "aiGlobals.h"
#include "aiCharacter.h"
class AICharacter;
////////////////////////////////////////////////////////////////////
// Class : Evade
// Description : This class handles all calls to the evade behavior
////////////////////////////////////////////////////////////////////
class Evade {
public:
AICharacter *_ai_char;
NodePath _evade_target;
float _evade_weight;
LVecBase3f _evade_direction;
double _evade_distance;
double _evade_relax_distance;
bool _evade_done;
bool _evade_activate_done;
Evade(AICharacter *ai_ch, NodePath target_object, double panic_distance,
double relax_distance, float evade_wt);
~Evade();
LVecBase3f do_evade();
void evade_activate();
};
#endif

104
contrib/src/ai/flee.cxx Normal file
View File

@ -0,0 +1,104 @@
// Filename: flee.cxx
// Created by: Deepak, John, Navin (24Oct09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "flee.h"
Flee::Flee(AICharacter *ai_ch, NodePath target_object, double panic_distance,
double relax_distance, float flee_wt){
_ai_char = ai_ch;
_flee_position = target_object.get_pos(_ai_char->_window_render);
_flee_distance = panic_distance;
_flee_weight = flee_wt;
_flee_relax_distance = relax_distance;
_flee_done = false;
_flee_activate_done = false;
}
Flee::Flee(AICharacter *ai_ch, LVecBase3f pos, double panic_distance,
double relax_distance, float flee_wt){
_ai_char = ai_ch;
_flee_position = pos;
_flee_distance = panic_distance;
_flee_weight = flee_wt;
_flee_relax_distance = relax_distance;
_flee_done = false;
_flee_activate_done = false;
}
Flee::~Flee() {
}
////////////////////////////////////////////////////////////////////
// Function: do_flee
// Description: This function performs the flee and returns a flee
// force which is used in the calculate_prioritized
// function. In case the AICharacter is past the
// (panic + relax) distance, it resets to flee_activate.
// This function is not to be used by the user.
////////////////////////////////////////////////////////////////////
LVecBase3f Flee::do_flee() {
LVecBase3f dirn;
double distance;
LVecBase3f desired_force;
dirn = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _flee_present_pos;
distance = dirn.length();
desired_force = _flee_direction * _ai_char->_movt_force;
if (distance > (_flee_distance + _flee_relax_distance)) {
if ((_ai_char->_steering->_behaviors_flags | _ai_char->_steering->BT_flee) == _ai_char->_steering->BT_flee) {
_ai_char->_steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
}
_flee_done = true;
_ai_char->_steering->turn_off("flee");
_ai_char->_steering->turn_on("flee_activate");
return (LVecBase3f(0.0, 0.0, 0.0));
}
else {
return (desired_force);
}
}
////////////////////////////////////////////////////////////////////
// Function: flee_activate
// Description: This function checks for whether the target is
// within the panic distance. When this is true,
// it calls the do_flee function and sets the flee
// direction.
// This function is not to be used by the user.
////////////////////////////////////////////////////////////////////
void Flee::flee_activate() {
LVecBase3f dirn;
double distance;
_flee_activate_done = false;
dirn = (_ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _flee_position);
distance = dirn.length();
if (distance < _flee_distance) {
_flee_direction = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render) - _flee_position;
_flee_direction.normalize();
_flee_present_pos = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render);
_ai_char->_steering->turn_off("flee_activate");
_ai_char->_steering->turn_on("flee");
_flee_activate_done = true;
}
}

52
contrib/src/ai/flee.h Normal file
View File

@ -0,0 +1,52 @@
// Filename: flee.h
// Created by: Deepak, John, Navin (24Oct09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef FLEE_H
#define FLEE_H
#include "aiGlobals.h"
#include "aiCharacter.h"
class AICharacter;
////////////////////////////////////////////////////////////////////
// Class : Flee
// Description : This class handles all calls to the flee behavior
////////////////////////////////////////////////////////////////////
class Flee {
public:
AICharacter *_ai_char;
LVecBase3f _flee_position;
float _flee_weight;
LVecBase3f _flee_direction;
double _flee_distance;
double _flee_relax_distance;
LVecBase3f _flee_present_pos;
bool _flee_done;
bool _flee_activate_done;
Flee(AICharacter *ai_ch, NodePath target_object, double panic_distance = 10.0,
double relax_distance = 10.0, float flee_wt = 1.0);
Flee(AICharacter *ai_ch, LVecBase3f pos, double panic_distance = 10.0,
double relax_distance = 10.0, float flee_wt = 1.0);
~Flee();
LVecBase3f do_flee();
void flee_activate();
};
#endif

42
contrib/src/ai/flock.cxx Normal file
View File

@ -0,0 +1,42 @@
// Filename: flock.cxx
// Created by: Deepak, John, Navin (12Oct09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "flock.h"
Flock::Flock(unsigned int flock_id, double vcone_angle, double vcone_radius, unsigned int separation_wt,
unsigned int cohesion_wt, unsigned int alignment_wt) {
_flock_id = flock_id;
_flock_vcone_angle = vcone_angle;
_flock_vcone_radius = vcone_radius;
_separation_wt = separation_wt;
_cohesion_wt = cohesion_wt;
_alignment_wt = alignment_wt;
}
Flock::~Flock() {
}
////////////////////////////////////////////////////////////////////
// Function: add_ai_char
// Description: This function adds AI characters to the flock.
////////////////////////////////////////////////////////////////////
void Flock::add_ai_char(AICharacter *ai_char) {
ai_char->_ai_char_flock_id = _flock_id;
ai_char->_steering->_flock_group = this;
_ai_char_list.push_back(ai_char);
}
unsigned int Flock::get_id() {
return _flock_id;
}

62
contrib/src/ai/flock.h Normal file
View File

@ -0,0 +1,62 @@
// Filename: flock.h
// Created by: Deepak, John, Navin (12Oct09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef FLOCK_H
#define FLOCK_H
#include "aiGlobals.h"
#include "aiCharacter.h"
class AICharacter;
////////////////////////////////////////////////////////////////////
// Class : Flock
// Description : This class is used to define the flock attributes
// and the AI characters which are part of the flock.
////////////////////////////////////////////////////////////////////
class Flock {
private:
unsigned int _flock_id;
public:
// Variables which will hold the parameters of the ai character's
// visibility cone.
double _flock_vcone_angle;
double _flock_vcone_radius;
// Variables to specify weights of separation, cohesion and
// alignment behaviors and thus create variable flock behavior.
unsigned int _separation_wt;
unsigned int _cohesion_wt;
unsigned int _alignment_wt;
// This vector will hold all the ai characters which belong to
// this flock.
typedef std::vector<AICharacter*> AICharList;
AICharList _ai_char_list;
PUBLISHED:
Flock(unsigned int flock_id, double vcone_angle, double vcone_radius,
unsigned int separation_wt = 2, unsigned int cohesion_wt = 4,
unsigned int alignment_wt = 1);
~Flock();
// Function to add the ai characters to _ai_char_list.
void add_ai_char(AICharacter *ai_char);
// Function to access the private member flock_id.
unsigned int get_id();
};
#endif

33
contrib/src/ai/globals.h Normal file
View File

@ -0,0 +1,33 @@
////////////////////////////////////////////////////////////////////////
//! Filename : globals.h
//! Created by : Deepak, John, Navin
//! Date: 8 Sep 09
//!
////////////////////////////////////////////////////////////////////////
//!
//! PANDA3D SOFTWARE
//! Copyright(c) Carnegie Mellon University. All rights reserved.
//!
//! All use of this software is subjest to the terms of the revised BSD
//! license. You should have received a copy of this license along with this source code in a file named "LICENSE"
////////////////////////////////////////////////////////////////////////
#pragma warning (disable:4996)
#pragma warning (disable:4005)
#pragma warning(disable:4275)
#ifndef _GLOBALS_H
#define _GLOBALS_H
#include "pandaFramework.h"
#include "textNode.h"
#include "pandaSystem.h"
#include "lvecBase3.h"
#include "nodePath.h"
#include "genericAsyncTask.h"
#include "asyncTaskManager.h"
#endif

View File

@ -0,0 +1,43 @@
#include "meshNode.h"
Node::Node(int grid_x, int grid_y, LVecBase3f pos, float w, float l, float h) {
for(int i = 0; i < 8; ++i) {
_neighbours[i] = NULL;
}
_position = pos;
_width = w;
_length = l;
_height = h;
_grid_x = grid_x;
_grid_y = grid_y;
_status = neutral;
_type = true;
_score = 0;
_cost = 0;
_heuristic = 0;
_next = NULL;
_prv_node = NULL;
}
Node::~Node() {
}
/////////////////////////////////////////////////////////////////////////////////////////
//!
//! Function : contains
//! Description : This is a handy function which returns true if the passed position is
//! within the node's dimensions.
/////////////////////////////////////////////////////////////////////////////////////////
bool Node::contains(float x, float y) {
if(_position.get_x() - _width / 2 <= x && _position.get_x() + _width / 2 >= x &&
_position.get_y() - _length / 2 <= y && _position.get_y() + _length / 2 >= y) {
return true;
}
else {
return false;
}
}

67
contrib/src/ai/meshNode.h Normal file
View File

@ -0,0 +1,67 @@
#ifndef _MESHNODE_H
#define _MESHNODE_H
#include "globals.h"
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//!
//! Class : Node
//! Description : This class is used to assign the nodes on the mesh. It holds all the data necessary to
//! compute A* algorithm. It also maintains a lot of vital information such as the neighbor
//! nodes of each node and also its position on the mesh.
//! Note: The Mesh Generator which is a stand alone tool makes use of this class to generate the nodes on the
//! mesh.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class Node {
public:
// This variable specifies whether the node is an obtacle or not.
// Used for dynamic obstacle addition to the environment.
// obstacle = false
// navigational = true
bool _type;
// This variable specifies the node status whether open, close or neutral.
// open = belongs to _open_list.
// close = belongs to _closed_list.
// neutral = unexamined node.
enum Status {
open,
close,
neutral
};
Status _status;
// The score is used to compute the traversal expense to nodes when using A*.
// _score = _cost + heuristic
int _score;
int _cost;
int _heuristic;
// Used to trace back the path after it is generated using A*.
Node *_prv_node;
// Position of the node in the 2d grid.
int _grid_x, _grid_y;
// Position of the node in 3D space.
LVecBase3f _position;
// Dimensions of each face / cell on the mesh.
// Height is given in case of expansion to a 3d mesh. Currently not used.
float _width, _length ,_height;
Node *_neighbours[8]; // anti-clockwise from top left corner.
// The _next pointer is used for traversal during mesh generation from the model.
// Note: The data in this member is discarded when mesh data is written into navmesh.csv file.
Node *_next;
Node(int grid_x, int grid_y, LVecBase3f pos, float w, float l, float h);
~Node();
bool contains(float x, float y);
};
#endif

View File

@ -0,0 +1,119 @@
// Filename: obstacleAvoidance.cxx
// Created by: Deepak, John, Navin (10Nov09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "obstacleAvoidance.h"
ObstacleAvoidance::ObstacleAvoidance(AICharacter *ai_char, float feeler_length) {
_ai_char = ai_char;
_feeler = feeler_length;
}
ObstacleAvoidance::~ObstacleAvoidance() {
}
////////////////////////////////////////////////////////////////////
// Function: obstacle_detection
// Description: This function checks if an obstacle is near to the
// AICharacter and if an obstacle is detected returns
// true.
////////////////////////////////////////////////////////////////////
bool ObstacleAvoidance::obstacle_detection() {
// Calculate the volume of the AICharacter with respect to render
PT(BoundingVolume) np_bounds = _ai_char->get_node_path().get_bounds();
CPT(BoundingSphere) np_sphere = np_bounds->as_bounding_sphere();
LVecBase3f avoidance(0.0, 0.0, 0.0);
double distance = 0x7fff ;
double expanded_radius;
LVecBase3f to_obstacle;
LVecBase3f prev_avoidance;
for (unsigned int i = 0; i < _ai_char->_world->_obstacles.size(); ++i) {
PT(BoundingVolume) bounds = _ai_char->_world->_obstacles[i].get_bounds();
CPT(BoundingSphere) bsphere = bounds->as_bounding_sphere();
LVecBase3f near_obstacle = _ai_char->_world->_obstacles[i].get_pos()
- _ai_char->get_node_path().get_pos();
// Check if it's the nearest obstacle, If so initialize as the nearest
// obstacle
if ((near_obstacle.length() < distance) &&
(_ai_char->_world->_obstacles[i].get_pos() != _ai_char->get_node_path().get_pos())) {
_nearest_obstacle = _ai_char->_world->_obstacles[i];
distance = near_obstacle.length();
expanded_radius = bsphere->get_radius() + np_sphere->get_radius();
}
}
LVecBase3f feeler = _feeler * _ai_char->get_char_render().get_relative_vector(_ai_char->get_node_path(), LVector3f::forward());
feeler.normalize();
feeler *= (expanded_radius + np_sphere->get_radius()) ;
to_obstacle = _nearest_obstacle.get_pos() - _ai_char->get_node_path().get_pos();
LVector3f line_vector = _ai_char->get_char_render().get_relative_vector(_ai_char->get_node_path(), LVector3f::forward());
LVecBase3f project = (to_obstacle.dot(line_vector) * line_vector) / line_vector.length_squared();
LVecBase3f perp = project - to_obstacle;
// If the nearest obstacle will collide with our AICharacter then
// send obstacle detection as true
if ((_nearest_obstacle) &&
(perp.length() < expanded_radius - np_sphere->get_radius()) &&
(project.length() < feeler.length())) {
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: obstacle_avoidance_activate
// Description: This function activates obstacle_avoidance if an
// obstacle is detected
////////////////////////////////////////////////////////////////////
void ObstacleAvoidance::obstacle_avoidance_activate() {
if (obstacle_detection()) {
_ai_char->_steering->turn_off("obstacle_avoidance_activate");
_ai_char->_steering->turn_on("obstacle_avoidance");
}
}
////////////////////////////////////////////////////////////////////
// Function: do_obstacle_avoidance
// Description: This function returns the force necessary by the
// AICharacter to avoid the nearest obstacle detected
// by obstacle_detection function
// NOTE : This assumes the obstacles are spherical
////////////////////////////////////////////////////////////////////
LVecBase3f ObstacleAvoidance::do_obstacle_avoidance() {
LVecBase3f offset = _ai_char->get_node_path().get_pos()
- _nearest_obstacle.get_pos();
PT(BoundingVolume) bounds =_nearest_obstacle.get_bounds();
CPT(BoundingSphere) bsphere = bounds->as_bounding_sphere();
PT(BoundingVolume) np_bounds = _ai_char->get_node_path().get_bounds();
CPT(BoundingSphere) np_sphere = np_bounds->as_bounding_sphere();
double distance_needed = offset.length() - bsphere->get_radius()
- np_sphere->get_radius();
if (obstacle_detection()) {
LVecBase3f direction = _ai_char->get_char_render().get_relative_vector(
_ai_char->get_node_path(), LVector3f::forward());
direction.normalize();
float forward_component = offset.dot(direction);
LVecBase3f projection = forward_component * direction;
LVecBase3f perpendicular_component = offset - projection;
double p = perpendicular_component.length();
perpendicular_component.normalize();
LVecBase3f avoidance = perpendicular_component;
// The closer the obstacle, the more force it generates
avoidance = (avoidance * _ai_char->get_max_force() *
_ai_char->_movt_force) / (p + 0.01);
return avoidance;
}
_ai_char->_steering->turn_on("obstacle_avoidance_activate");
_ai_char->_steering->turn_off("obstacle_avoidance");
return LVecBase3f(0, 0, 0);
}

View File

@ -0,0 +1,42 @@
// Filename: obstacleAvoidance.h
// Created by: Deepak, John, Navin (10Nov2009)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef OBSTACLE_AVOIDANCE_H
#define OBSTACLE_AVOIDANCE_H
#include "aiCharacter.h"
#include "boundingSphere.h"
class AICharacter;
////////////////////////////////////////////////////////////////////
// Class : ObstacleAvoidance
// Description : This class handles all calls to the obstacle
// avoidance behavior
////////////////////////////////////////////////////////////////////
class ObstacleAvoidance {
public :
AICharacter *_ai_char;
float _obstacle_avoidance_weight;
NodePath _nearest_obstacle;
bool _obstacle_avoidance_done;
float _feeler;
ObstacleAvoidance(AICharacter *ai_char, float feeler_length);
LVecBase3f do_obstacle_avoidance();
~ObstacleAvoidance();
void obstacle_avoidance_activate();
bool obstacle_detection();
};
#endif

413
contrib/src/ai/pathFind.cxx Normal file
View File

@ -0,0 +1,413 @@
// Filename: pathFind.cxx
// Created by: Deepak, John, Navin (12Oct09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "pathFind.h"
PathFind::PathFind(AICharacter *ai_ch) {
_ai_char = ai_ch;
_parent = new GeomNode("parent");
_ai_char->_window_render.attach_new_node(_parent);
_pen = new LineSegs("pen");
_pen->set_color(1.0, 0.0, 0.0);
_pen->set_thickness(2.0);
_path_finder_obj = NULL;
_dynamic_avoid = false;
}
PathFind::~PathFind() {
}
////////////////////////////////////////////////////////////////////
// Function: create_nav_mesh
// Description: This function recreates the navigation mesh from
// the .csv file.
////////////////////////////////////////////////////////////////////
void PathFind::create_nav_mesh(const char* navmesh_filename) {
// Stage variables.
int grid_x, grid_y;
float l, w, h;
LVecBase3f position;
// Variable to hold line data read from file.
string line;
// Array for storing data members obtained from each line of the
// file.
string fields[10];
// Open data file for reading.
ifstream nav_mesh_file (navmesh_filename);
if (nav_mesh_file.is_open()) {
// Capture the grid size from the file.
getline(nav_mesh_file, line);
int pos = line.find(",");
_grid_size = atoi((line.substr(pos + 1)).c_str());
// Initialize the stage mesh with NULL nodes.
for (int r = 0; r < _grid_size; ++r) {
_nav_mesh.push_back(vector<AINode*>());
for (int c = 0; c < _grid_size; ++c) {
_nav_mesh[r].push_back(NULL);
}
}
// Ignore the header of the navmesh.csv file.
getline(nav_mesh_file, line);
// Begin reading data from the file.
while (!nav_mesh_file.eof()) {
getline(nav_mesh_file, line);
stringstream linestream (line);
// Stores all the data members in the line to the array.
// Data structure: NULL,NodeType,GridX,GridY,Length,Width,
// Height,PosX,PosY,PosZ
for (int i = 0; i < 10; ++i) {
getline(linestream, fields[i], ',');
}
// Populate the main nodes into stage mesh.
if (fields[0] == "0" && fields[1] == "0") {
grid_x = atoi(fields[2].c_str());
grid_y = atoi(fields[3].c_str());
l = atof(fields[4].c_str());
w = atof(fields[5].c_str());
h = atof(fields[6].c_str());
position = LVecBase3f(atof(fields[7].c_str()),
atof(fields[8].c_str()), atof(fields[9].c_str()));
AINode *stage_node = new AINode(grid_x, grid_y, position, w, l, h);
_nav_mesh[grid_y][grid_x] = stage_node;
}
else if (fields[0] == "") {
// End of file reached at this point.
nav_mesh_file.close();
// Assign the neighbor nodes for each of the main nodes
// that just got populated into the stage mesh.
assign_neighbor_nodes(navmesh_filename);
}
}
}
else {
cout << "error opening navmesh.csv file!\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: assign_neighbor_nodes
// Description: This function assigns the neighbor nodes for each
// main node present in _nav_mesh.
////////////////////////////////////////////////////////////////////
void PathFind::assign_neighbor_nodes(const char* navmesh_filename){
ifstream nav_mesh_file (navmesh_filename);
// Stage variables.
int gd_x, gd_y, gd_xn, gd_yn;
string ln;
string fields[10];
string fields_n[10];
if (nav_mesh_file.is_open()) {
getline(nav_mesh_file, ln); // Get rid of grid size line.
getline(nav_mesh_file, ln); // Get rid of the header.
while (!nav_mesh_file.eof()) {
getline(nav_mesh_file, ln); // Gets main node data only. No neighbor nodes.
stringstream linestream (ln);
for (int i = 0; i < 10; ++i) {
getline(linestream, fields[i], ',');
}
if (fields[0] == "0" && fields[1] == "0") {
// Usable main node.
gd_x = atoi(fields[2].c_str());
gd_y = atoi(fields[3].c_str());
for (int i = 0; i < 8; ++i) {
getline(nav_mesh_file, ln); // Gets neighbor node data only. No main nodes.
stringstream linestream_n (ln);
for (int j = 0; j < 10; ++j) {
getline(linestream_n, fields_n[j], ',');
}
gd_xn = atoi(fields_n[2].c_str());
gd_yn = atoi(fields_n[3].c_str());
if (fields_n[0] == "0" && fields_n[1] == "1") {
// Usable neighbor for main node.
// Note: The indices of the vector are inverted
// when compared to the values of the nodes on actual grid.
_nav_mesh[gd_y][gd_x]->_neighbours[i] = _nav_mesh[gd_yn][gd_xn];
}
else if (fields_n[0] == "1" && fields_n[1] == "1") {
// NULL neighbor.
_nav_mesh[gd_y][gd_x]->_neighbours[i] = NULL;
}
else {
cout << "Warning: Corrupt data!\n";
}
}
}
else if (fields[0] == "") {
// End of file reached at this point.
nav_mesh_file.close();
}
}
}
else {
cout << "error opening navmesh.csv file!\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: set_path_find
// Description: This function starts the path finding process after
// reading the given navigation mesh.
////////////////////////////////////////////////////////////////////
void PathFind::set_path_find(const char* navmesh_filename) {
create_nav_mesh(navmesh_filename);
if (_ai_char->_steering->_path_follow_obj) {
_ai_char->_steering->remove_ai("pathfollow");
}
_ai_char->_steering->path_follow(1.0f);
if (_path_finder_obj) {
delete _path_finder_obj;
_path_finder_obj = NULL;
}
_path_finder_obj = new PathFinder(_nav_mesh);
}
////////////////////////////////////////////////////////////////////
// Function: path_find (for pathfinding towards a static position)
// Description: This function checks for the source and target in
// the navigation mesh for its availability and then
// finds the best path via the A* algorithm Then it
// calls the path follower to make the object follow
// the path.
////////////////////////////////////////////////////////////////////
void PathFind::path_find(LVecBase3f pos, string type) {
if (type == "addPath") {
if (_ai_char->_steering->_path_follow_obj) {
_ai_char->_steering->remove_ai("pathfollow");
}
_ai_char->_steering->path_follow(1.0f);
}
clear_path();
AINode* src = find_in_mesh(_nav_mesh,
_ai_char->_ai_char_np.get_pos(_ai_char->_window_render), _grid_size);
if (src == NULL) {
cout << "couldnt find source\n";
}
AINode* dst = find_in_mesh(_nav_mesh, pos, _grid_size);
if (dst == NULL) {
cout << "couldnt find destination\n";
}
if (src != NULL && dst != NULL) {
_path_finder_obj->find_path(src, dst);
trace_path(src);
}
if (!_ai_char->_steering->_path_follow_obj->_start) {
_ai_char->_steering->start_follow();
}
}
////////////////////////////////////////////////////////////////////
// Function: path_find (for pathfinding towards a moving target
// (a NodePath))
// Description: This function checks for the source and target in
// the navigation mesh for its availability and then
// finds the best path via the A* algorithm
// Then it calls the path follower to make the object
// follow the path.
////////////////////////////////////////////////////////////////////
void PathFind::path_find(NodePath target, string type) {
if (type == "addPath") {
if (_ai_char->_steering->_path_follow_obj) {
_ai_char->_steering->remove_ai("pathfollow");
}
_ai_char->_steering->path_follow(1.0f);
}
clear_path();
_path_find_target = target;
_prev_position = target.get_pos(_ai_char->_window_render);
AINode* src = find_in_mesh(_nav_mesh,
_ai_char->_ai_char_np.get_pos(_ai_char->_window_render), _grid_size);
if (src == NULL) {
cout << "couldnt find source\n";
}
AINode* dst = find_in_mesh(_nav_mesh, _prev_position, _grid_size);
if (dst == NULL) {
cout << "couldnt find destination\n";
}
if (src != NULL && dst != NULL) {
_path_finder_obj->find_path(src, dst);
trace_path(src);
}
if (_ai_char->_steering->_path_follow_obj!=NULL) {
if (!_ai_char->_steering->_path_follow_obj->_start) {
_ai_char->_steering->start_follow("pathfind");
}
}
}
////////////////////////////////////////////////////////////////////
// Function: clear_path
// Description: Helper function to restore the path and mesh
// to its initial state
////////////////////////////////////////////////////////////////////
void PathFind::clear_path() {
// Initialize to zero
for (int i = 0; i < _grid_size; ++i) {
for (int j = 0; j < _grid_size; ++j) {
if (_nav_mesh[i][j] != NULL) {
_nav_mesh[i][j]->_status = _nav_mesh[i][j]->ST_neutral;
_nav_mesh[i][j]->_cost = 0;
_nav_mesh[i][j]->_heuristic = 0;
_nav_mesh[i][j]->_score = 0;
_nav_mesh[i][j]->_prv_node = NULL;
}
}
}
if (_path_finder_obj) {
_path_finder_obj->_open_list.clear();
_path_finder_obj->_closed_list.clear();
}
}
////////////////////////////////////////////////////////////////////
// Function: trace_path
// Description: This function is the function which sends the path
// information one by one to the path follower so that
// it can store the path needed to be
// traversed by the pathfinding object
////////////////////////////////////////////////////////////////////
void PathFind::trace_path(AINode* src) {
if (_ai_char->_pf_guide) {
_parent->remove_all_children();
}
else {
_parent->remove_all_children();
}
if (_path_finder_obj->_closed_list.size() > 0) {
AINode *traversor = _path_finder_obj->_closed_list[_path_finder_obj->_closed_list.size() - 0.5];
while (traversor != src) {
if (_ai_char->_pf_guide) {
_pen->move_to(traversor->_position.get_x(), traversor->_position.get_y(), 1);
_pen->draw_to(traversor->_prv_node->_position.get_x(),
traversor->_prv_node->_position.get_y(), 0.5);
PT(GeomNode) gnode = _pen->create();
_parent->add_child(gnode);
}
_ai_char->_steering->add_to_path(traversor->_position);
traversor = traversor->_prv_node;
}
}
}
////////////////////////////////////////////////////////////////////
// Function: add_obstacle_to_mesh
// Description: This function allows the user to dynamically add
// obstacles to the game environment. The function
// will update the nodes within the
// bounding volume of the obstacle as non-traversable.
// Hence will not be considered by the pathfinding
// algorithm.
////////////////////////////////////////////////////////////////////
void PathFind::add_obstacle_to_mesh(NodePath obstacle) {
PT(BoundingVolume) np_bounds = obstacle.get_bounds();
CPT(BoundingSphere) np_sphere = np_bounds->as_bounding_sphere();
AINode* temp = find_in_mesh(_nav_mesh, obstacle.get_pos(), _grid_size);
if (temp != NULL) {
float left = temp->_position.get_x() - np_sphere->get_radius();
float right = temp->_position.get_x() + np_sphere->get_radius();
float top = temp->_position.get_y() + np_sphere->get_radius();
float down = temp->_position.get_y() - np_sphere->get_radius();
for (int i = 0; i < _grid_size; ++i) {
for (int j = 0; j < _grid_size; ++j) {
if (_nav_mesh[i][j] != NULL && _nav_mesh[i][j]->_type == true) {
if (_nav_mesh[i][j]->_position.get_x() >= left && _nav_mesh[i][j]->_position.get_x() <= right &&
_nav_mesh[i][j]->_position.get_y() >= down && _nav_mesh[i][j]->_position.get_y() <= top) {
_nav_mesh[i][j]->_type = false;
_previous_obstacles.insert(_previous_obstacles.end(), i);
_previous_obstacles.insert(_previous_obstacles.end(), j);
}
}
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: do_dynamic_avoid()
// Description: This function does the updation of the collisions to
// the mesh based on the new positions of the obstacles.
////////////////////////////////////////////////////////////////////
void PathFind::do_dynamic_avoid() {
clear_previous_obstacles();
_previous_obstacles.clear();
for (unsigned int i = 0; i < _dynamic_obstacle.size(); ++i) {
add_obstacle_to_mesh(_dynamic_obstacle[i]);
}
}
////////////////////////////////////////////////////////////////////
// Function: clear_previous_obstacles()
// Description: Helper function to reset the collisions if the
// obstacle is not on the node anymore.
////////////////////////////////////////////////////////////////////
void PathFind::clear_previous_obstacles(){
for (unsigned int i = 0; i < _previous_obstacles.size(); i = i + 2) {
_nav_mesh[_previous_obstacles[i]][_previous_obstacles[i + 1]]->_type = true;
}
}
////////////////////////////////////////////////////////////////////
// Function: dynamic_avoid
// Description: This function starts the pathfinding obstacle
// navigation for the passed in obstacle.
////////////////////////////////////////////////////////////////////
void PathFind::dynamic_avoid(NodePath obstacle) {
_dynamic_avoid = true;
_dynamic_obstacle.insert(_dynamic_obstacle.end(), obstacle);
}

70
contrib/src/ai/pathFind.h Normal file
View File

@ -0,0 +1,70 @@
// Filename: pathFind.h
// Created by: Deepak, John, Navin (12Oct09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef PATHFIND_H
#define PATHFIND_H
#include "aiGlobals.h"
#include "aiCharacter.h"
#include "aiPathFinder.h"
#include "boundingSphere.h"
class AICharacter;
////////////////////////////////////////////////////////////////////
// Class : PathFind
// Description : This class contains all the members and functions
// that are required to form an interface between
// the AIBehaviors class and the PathFinder class.
// An object (pointer) of this class is provided in
// the AIBehaviors class. It is only via this object
// that the user can activate pathfinding.
////////////////////////////////////////////////////////////////////
class PathFind {
public:
AICharacter *_ai_char;
PathFinder *_path_finder_obj;
NavMesh _nav_mesh;
NavMesh _stage_mesh;
int _grid_size;
NodePath _path_find_target;
LVecBase3f _prev_position;
PT(GeomNode) _parent;
LineSegs *_pen;
vector<int> _previous_obstacles;
bool _dynamic_avoid;
vector<NodePath> _dynamic_obstacle;
PathFind(AICharacter *ai_ch);
~PathFind();
void clear_path();
void trace_path(AINode* src);
void create_nav_mesh(const char* navmesh_filename);
void assign_neighbor_nodes(const char* navmesh_filename);
void do_dynamic_avoid();
void clear_previous_obstacles();
void set_path_find(const char* navmesh_filename);
void path_find(LVecBase3f pos, string type = "normal");
void path_find(NodePath target, string type = "normal");
void add_obstacle_to_mesh(NodePath obstacle);
void dynamic_avoid(NodePath obstacle);
};
#endif

View File

@ -0,0 +1,138 @@
// Filename: pathFollow.cxx
// Created by: Deepak, John, Navin (24Oct09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "pathFollow.h"
PathFollow::PathFollow(AICharacter *ai_ch, float follow_wt) {
_follow_weight = follow_wt;
_curr_path_waypoint = -1;
_start = false;
_ai_char = ai_ch;
_myClock = ClockObject::get_global_clock();
}
PathFollow::~PathFollow() {
}
////////////////////////////////////////////////////////////////////
// Function: add_to_path
// Description: This function adds the positions generated from a
// pathfind or a simple path follow behavior to the
// _path list.
////////////////////////////////////////////////////////////////////
void PathFollow::add_to_path(LVecBase3f pos) {
_path.push_back(pos);
}
////////////////////////////////////////////////////////////////////
// Function: start
// Description: This function initiates the path follow behavior.
////////////////////////////////////////////////////////////////////
void PathFollow::start(string type) {
_type = type;
_start = true;
if (_path.size() > 0) {
_curr_path_waypoint = _path.size() - 1;
_dummy = _ai_char->_window_render.attach_new_node("dummy");
_dummy.set_pos(_path[_curr_path_waypoint]);
_ai_char->_steering->pursue(_dummy, _follow_weight);
_time = _myClock->get_real_time();
}
}
////////////////////////////////////////////////////////////////////
// Function: do_follow
// Description: This function allows continuous path finding by AI
// chars. There are 2 ways in which this is implemented.
// 1. The character re-calculates the optimal path
// everytime the target changes its position.
// Less computationally expensive.
// 2. The character continuosly re-calculates its
// optimal path to the target. This is used in a
// scenario where the ai chars have to avoid other AI
// chars. More computationally expensive.
////////////////////////////////////////////////////////////////////
void PathFollow::do_follow() {
if ((_myClock->get_real_time() - _time) > 0.5) {
if (_type == "pathfind") {
// This 'if' statement when 'true' causes the path to be
// re-calculated irrespective of target position.
// This is done when _dynamice_avoid is active. More
// computationally expensive.
if (_ai_char->_steering->_path_find_obj->_dynamic_avoid) {
_ai_char->_steering->_path_find_obj->do_dynamic_avoid();
if (check_if_possible()) {
_path.clear();
_ai_char->_steering->_path_find_obj->path_find(_ai_char->_steering->_path_find_obj->_path_find_target);
// Ensure that the path size is not 0.
if (_path.size() > 0) {
_curr_path_waypoint = _path.size() - 1;
_dummy.set_pos(_path[_curr_path_waypoint]);
}
else {
// Refresh the _curr_path_waypoint value if path size is <= 0.
_curr_path_waypoint = -1;
}
}
}
// This 'if' statement causes the path to be re-calculated only
// when there is a change in target position.
// Less computationally expensive.
else if (_ai_char->_steering->_path_find_obj->_path_find_target.get_pos(_ai_char->_window_render)
!= _ai_char->_steering->_path_find_obj->_prev_position) {
if (check_if_possible()) {
_path.clear();
_ai_char->_steering->_path_find_obj->path_find(_ai_char->_steering->_path_find_obj->_path_find_target);
// Ensure that the path size is not 0.
if (_path.size() > 0) {
_curr_path_waypoint = _path.size() - 1;
_dummy.set_pos(_path[_curr_path_waypoint]);
}
else {
// Refresh the _curr_path_waypoint value if path size is 0.
_curr_path_waypoint = -1;
}
}
}
_time = _myClock->get_real_time();
}
}
if (_curr_path_waypoint > 0) {
double distance = (_path[_curr_path_waypoint] -
_ai_char->_ai_char_np.get_pos(_ai_char->_window_render)).length();
if (distance < 5) {
_curr_path_waypoint--;
_dummy.set_pos(_path[_curr_path_waypoint]);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: check_if_possible
// Description: This function checks if the current positions of
// the ai char and the target char can be used to
// generate an optimal path.
////////////////////////////////////////////////////////////////////
bool PathFollow::check_if_possible() {
AINode* src = find_in_mesh(_ai_char->_steering->_path_find_obj->_nav_mesh,
_ai_char->_ai_char_np.get_pos(_ai_char->_window_render),
_ai_char->_steering->_path_find_obj->_grid_size);
LVecBase3f _prev_position = _ai_char->_steering->_path_find_obj->_path_find_target.get_pos(_ai_char->_window_render);
AINode* dst = find_in_mesh(_ai_char->_steering->_path_find_obj->_nav_mesh,
_prev_position, _ai_char->_steering->_path_find_obj->_grid_size);
return (src && dst);
}

View File

@ -0,0 +1,50 @@
// Filename: pathFollow.h
// Created by: Deepak, John, Navin (24Oct09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef PATHFOLLOW_H
#define PATHFOLLOW_H
#include "aiGlobals.h"
#include "aiCharacter.h"
#include "aiNode.h"
class AICharacter;
////////////////////////////////////////////////////////////////////
// Class : PathFollow
// Description : This class handles all calls to the path follow
// behavior and has functions to handle pathfinding
////////////////////////////////////////////////////////////////////
class PathFollow {
public:
AICharacter *_ai_char;
float _follow_weight;
vector<LVecBase3f> _path;
int _curr_path_waypoint;
bool _start;
NodePath _dummy;
string _type;
ClockObject *_myClock;
float _time;
PathFollow(AICharacter *ai_ch, float follow_wt);
~PathFollow();
void add_to_path(LVecBase3f pos);
void start(string type);
void do_follow();
bool check_if_possible();
};
#endif

60
contrib/src/ai/pursue.cxx Normal file
View File

@ -0,0 +1,60 @@
// Filename: pursue.cxx
// Created by: Deepak, John, Navin (24Oct09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "pursue.h"
Pursue::Pursue(AICharacter *ai_ch, NodePath target_object, float pursue_wt) {
_ai_char = ai_ch;
_pursue_target = target_object;
_pursue_weight = pursue_wt;
_pursue_done = false;
}
Pursue::~Pursue() {
}
////////////////////////////////////////////////////////////////////
// Function: do_pursue
// Description: This function performs the pursue and returns a
// pursue force which is used
// in the calculate_prioritized function.
// In case the target has been reached it resets the
// forces to 0 so that the character stops.
// This function is not to be used by the user.
////////////////////////////////////////////////////////////////////
LVecBase3f Pursue::do_pursue() {
assert(_pursue_target && "pursue target not assigned");
LVecBase3f present_pos = _ai_char->_ai_char_np.get_pos(_ai_char->_window_render);
double target_distance = (_pursue_target.get_pos(_ai_char->_window_render) -
present_pos).length();
if (int(target_distance) == 0) {
_pursue_done = true;
_ai_char->_steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
_ai_char->_steering->_pursue_force = LVecBase3f(0.0, 0.0, 0.0);
return (LVecBase3f(0.0, 0.0, 0.0));
}
else {
_pursue_done = false;
}
_pursue_direction = _pursue_target.get_pos(_ai_char->_window_render) - present_pos;
_pursue_direction.normalize();
LVecBase3f desired_force = _pursue_direction * _ai_char->_movt_force;
return (desired_force);
}

42
contrib/src/ai/pursue.h Normal file
View File

@ -0,0 +1,42 @@
// Filename: pursue.h
// Created by: Deepak, John, Navin (24Oct09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef PURSUE_H
#define PURSUE_H
#include "aiGlobals.h"
#include "aiCharacter.h"
class AICharacter;
////////////////////////////////////////////////////////////////////
// Class : Pursue
// Description : This class handles all calls to the pursue
// behavior
////////////////////////////////////////////////////////////////////
class Pursue {
public:
AICharacter *_ai_char;
NodePath _pursue_target;
float _pursue_weight;
LVecBase3f _pursue_direction;
bool _pursue_done;
Pursue(AICharacter *ai_ch, NodePath target_object, float pursue_wt);
~Pursue();
LVecBase3f do_pursue();
};
#endif

66
contrib/src/ai/seek.cxx Normal file
View File

@ -0,0 +1,66 @@
// Filename: seek.cxx
// Created by: Deepak, John, Navin (24Oct09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "seek.h"
Seek::Seek(AICharacter *ai_ch, NodePath target_object, float seek_wt) {
_ai_char = ai_ch;
_seek_position = target_object.get_pos(_ai_char->_window_render);
_seek_weight = seek_wt;
_seek_direction = _seek_position -
_ai_char->_ai_char_np.get_pos(_ai_char->_window_render);
_seek_direction.normalize();
_seek_done = false;
}
Seek::Seek(AICharacter *ai_ch, LVecBase3f pos, float seek_wt) {
_ai_char = ai_ch;
_seek_position = pos;
_seek_weight = seek_wt;
_seek_direction = _seek_position -
_ai_char->_ai_char_np.get_pos(_ai_char->_window_render);
_seek_direction.normalize();
_seek_done = false;
}
Seek::~Seek() {
}
////////////////////////////////////////////////////////////////////
// Function: do_seek
// Description: This function performs the seek and returns a seek
// force which is used
// in the calculate_prioritized function.
// This function is not to be used by the user.
////////////////////////////////////////////////////////////////////
LVecBase3f Seek::do_seek() {
double target_distance = (_seek_position -
_ai_char->_ai_char_np.get_pos(_ai_char->_window_render)).length();
if (int(target_distance) == 0) {
_seek_done = true;
_ai_char->_steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
_ai_char->_steering->turn_off("seek");
return (LVecBase3f(0.0, 0.0, 0.0));
}
LVecBase3f desired_force = _seek_direction * _ai_char->_movt_force;
return (desired_force);
}

44
contrib/src/ai/seek.h Normal file
View File

@ -0,0 +1,44 @@
// Filename: seek.h
// Created by: Deepak, John, Navin (24Oct09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef SEEK_H
#define SEEK_H
#include "aiGlobals.h"
#include "aiCharacter.h"
class AICharacter;
////////////////////////////////////////////////////////////////////
// Class : Seek
// Description : This class handles all calls to the seek behavior
////////////////////////////////////////////////////////////////////
class Seek {
public:
AICharacter *_ai_char;
LVecBase3f _seek_position;
float _seek_weight;
LVecBase3f _seek_direction;
bool _seek_done;
LVecBase3f _seek_accum_force;
Seek(AICharacter *ai_ch, NodePath target_object, float seek_wt = 1.0);
Seek(AICharacter *ai_ch, LVecBase3f pos, float seek_wt = 1.0);
~Seek();
LVecBase3f do_seek();
};
#endif

140
contrib/src/ai/wander.cxx Normal file
View File

@ -0,0 +1,140 @@
// Filename: wander.cxx
// Created by: Deepak, John, Navin (24Oct09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "wander.h"
////////////////////////////////////////////////////////////////////
// Function: rand_float
// Description: This function creates a random float point number
////////////////////////////////////////////////////////////////////
double rand_float() {
const static double rand_max = 0x7fff;
return ((rand()) / (rand_max + 1.0));
}
////////////////////////////////////////////////////////////////////
// Function: random_clamped
// Description: This function returns a random floating point number
// in the range -1 to 1.
////////////////////////////////////////////////////////////////////
double random_clamped() {
return (rand_float() - rand_float());
}
Wander::Wander(AICharacter *ai_ch, double wander_radius,int flag,
double aoe, float wander_weight) {
_ai_char = ai_ch;
_wander_radius = wander_radius ;
_wander_weight = wander_weight;
double theta = rand_float() * 2 * 3.14159;
double si = rand_float() * 3.14159;
_flag = flag;
// Area around which the character should wander
_area_of_effect = aoe;
_init_pos = _ai_char->get_node_path().get_pos(_ai_char->get_char_render());
// _flag is used by Wander to wander in a given axis
// Value 0 - XY axes wander
// Value 1 - YZ axes wander
// Value 2 - XZ axes wander
// Value 3 - XYZ axes wander
// default is XY axes
switch (_flag) {
case 0: {
_wander_target = LVecBase3f(_wander_radius * cos(theta),
_wander_radius * sin(theta),0);
break;
}
case 1: {
_wander_target = LVecBase3f(0, _wander_radius * cos(theta),
_wander_radius * sin(theta));
break;
}
case 2: {
_wander_target = LVecBase3f(_wander_radius * cos(theta), 0,
_wander_radius * sin(theta));
break;
}
case 3: {
_wander_target = LVecBase3f(_wander_radius * sin(theta) * cos(si),
_wander_radius * sin(theta) * sin(si), _wander_radius * cos(theta));
break;
}
default: {
_wander_target = LVecBase3f(_wander_radius * cos(theta),
_wander_radius * sin(theta),0);
break;
}
}
}
Wander::~Wander() {
}
////////////////////////////////////////////////////////////////////
// Function: do_wander
// Description: This function performs the wander and returns the
// wander force which is used
// in the calculate_prioritized function.
// This function is not to be used by the user.
////////////////////////////////////////////////////////////////////
LVecBase3f Wander::do_wander() {
LVecBase3f present_pos = _ai_char->get_node_path().get_pos(_ai_char->get_char_render());
// Create the random slices to enable random movement of wander
// for x,y,z respectively
double time_slice_1 = random_clamped() * 1.5;
double time_slice_2 = random_clamped() * 1.5;
double time_slice_3 = random_clamped() * 1.5;
switch (_flag) {
case 0: {
_wander_target += LVecBase3f(time_slice_1, time_slice_2, 0);
break;
}
case 1: {
_wander_target += LVecBase3f(0, time_slice_1, time_slice_2);
break;
}
case 2: {
_wander_target += LVecBase3f(time_slice_1, 0, time_slice_2);
break;
}
case 3: {
_wander_target += LVecBase3f(time_slice_1, time_slice_2, time_slice_3);
break;
}
default: {
_wander_target = LVecBase3f(time_slice_1, time_slice_2, 0);
}
}
_wander_target.normalize();
_wander_target *= _wander_radius;
LVecBase3f target = _ai_char->get_char_render().get_relative_vector(_ai_char->get_node_path(), LVector3f::forward());
target.normalize();
// Project wander target onto global space
target = _wander_target + target;
LVecBase3f desired_target = present_pos + target;
LVecBase3f desired_force = desired_target - _ai_char->get_node_path().get_pos() ;
desired_force.normalize();
desired_force *= _ai_char->_movt_force;
double distance = (present_pos - _init_pos).length();
if (_area_of_effect > 0 && distance > _area_of_effect) {
LVecBase3f direction = present_pos - _init_pos;
direction.normalize();
desired_force = - direction * _ai_char->_movt_force;
LVecBase3f dirn = _ai_char->_steering->_steering_force;
dirn.normalize();
_ai_char->_steering->_steering_force = LVecBase3f(0.0, 0.0, 0.0);
}
return desired_force;
}

40
contrib/src/ai/wander.h Normal file
View File

@ -0,0 +1,40 @@
// Filename: wander.h
// Created by: Deepak, John, Navin (24Oct09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised
// BSD license. You should have received a copy of this license
// along with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef WANDER_H
#define WANDER_H
#include "aiCharacter.h"
class AICharacter;
////////////////////////////////////////////////////////////////////
// Class : Wander
// Description : This class handles all calls to the wander behavior
////////////////////////////////////////////////////////////////////
class Wander {
public:
AICharacter *_ai_char;
double _wander_radius;
LVecBase3f _wander_target;
float _wander_weight;
int _flag;
LVecBase3f _init_pos;
double _area_of_effect;
Wander(AICharacter *ai_ch, double wander_radius, int flag, double aoe, float wander_weight);
LVecBase3f do_wander();
~Wander();
};
#endif

View File

@ -0,0 +1,26 @@
/* Filename: contribbase.h
* Created by: rdb (30Dec09)
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* This file is included at the beginning of every header file and/or
C or C++ file. It must be compilable for C as well as C++ files,
so no C++-specific code or syntax can be put here. */
#ifndef CONTRIBBASE_H
#define CONTRIBBASE_H
#include "pandabase.h"
#include "contribsymbols.h"
#endif

View File

@ -0,0 +1,42 @@
/* Filename: contribsymbols.h
* Created by: rdb (30Dec09)
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef CONTRIBSYMBOLS_H
#define CONTRIBSYMBOLS_H
/* See dtoolsymbols.h for a rant on the purpose of this file. */
/* Note that the symbols declared in this file appear in alphabetical
order. Also note that we must use C-style comments only here, not
C++-style comments, since this file is occasionally included by a C
file. */
#if defined(WIN32_VC) && !defined(CPPPARSER) && !defined(LINK_ALL_STATIC)
#ifdef BUILDING_PANDAAI
#define EXPCL_PANDAAI __declspec(dllexport)
#define EXPTP_PANDAAI
#else
#define EXPCL_PANDAAI __declspec(dllimport)
#define EXPTP_PANDAAI extern
#endif
#else /* !WIN32_VC */
#define EXPCL_PANDAAI
#define EXPTP_PANDAAI
#endif /* WIN32_VC */
#endif