mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 00:32:57 -04:00
ai: make AICharacter reference counted
This lets one drop the reference to AICharacter after adding it to a flock or AIWorld without crashes. Also replace the silly and inefficient custom-rolled linked list implementation of AICharPool with a vector, and add additional safety checks. Fixes #318
This commit is contained in:
parent
0ce9dc98b1
commit
0de981d0b8
@ -24,6 +24,8 @@ AICharacter::AICharacter(string model_name, NodePath model_np, double mass, doub
|
||||
_velocity = LVecBase3(0.0, 0.0, 0.0);
|
||||
_steering_force = LVecBase3(0.0, 0.0, 0.0);
|
||||
|
||||
_world = nullptr;
|
||||
|
||||
_steering = new AIBehaviors();
|
||||
_steering->_ai_char = this;
|
||||
|
||||
@ -31,6 +33,7 @@ AICharacter::AICharacter(string model_name, NodePath model_np, double mass, doub
|
||||
}
|
||||
|
||||
AICharacter::~AICharacter() {
|
||||
nassertv(_world == nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define _AICHARACTER_H
|
||||
|
||||
#include "aiBehaviors.h"
|
||||
#include "referenceCount.h"
|
||||
|
||||
/**
|
||||
* This class is used for creating the AI characters. It assigns both physics
|
||||
@ -25,7 +26,7 @@
|
||||
class AIBehaviors;
|
||||
class AIWorld;
|
||||
|
||||
class EXPCL_PANDAAI AICharacter {
|
||||
class EXPCL_PANDAAI AICharacter : public ReferenceCount {
|
||||
public:
|
||||
double _mass;
|
||||
double _max_force;
|
||||
|
@ -14,44 +14,56 @@
|
||||
#include "aiWorld.h"
|
||||
|
||||
AIWorld::AIWorld(NodePath render) {
|
||||
_ai_char_pool = new AICharPool();
|
||||
_render = render;
|
||||
_render = move(render);
|
||||
}
|
||||
|
||||
AIWorld::~AIWorld() {
|
||||
}
|
||||
|
||||
void AIWorld::add_ai_char(AICharacter *ai_char) {
|
||||
_ai_char_pool->append(ai_char);
|
||||
_ai_char_pool.push_back(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);
|
||||
AICharPool::iterator it;
|
||||
for (it = _ai_char_pool.begin(); it != _ai_char_pool.end(); ++it) {
|
||||
AICharacter *ai_char = *it;
|
||||
if (ai_char->_name == name) {
|
||||
nassertv(ai_char->_world == this);
|
||||
ai_char->_world = nullptr;
|
||||
_ai_char_pool.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
remove_ai_char_from_flock(move(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);
|
||||
for (AICharacter *ai_char : _ai_char_pool) {
|
||||
for (Flock *flock : _flock_pool) {
|
||||
if (ai_char->_ai_char_flock_id == flock->get_id()) {
|
||||
for (size_t j = 0; j < flock->_ai_char_list.size(); ++j) {
|
||||
if (flock->_ai_char_list[j]->_name == name) {
|
||||
flock->_ai_char_list.erase(flock->_ai_char_list.begin() + j);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ai_pool = ai_pool->_next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function prints the names of the AI characters that have been added to
|
||||
* the AIWorld. Useful for debugging purposes.
|
||||
*/
|
||||
void AIWorld::print_list() {
|
||||
_ai_char_pool->print_list();
|
||||
for (AICharacter *ai_char : _ai_char_pool) {
|
||||
cout << ai_char->_name << endl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -59,12 +71,8 @@ void AIWorld::print_list() {
|
||||
* 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;
|
||||
for (AICharacter *ai_char : _ai_char_pool) {
|
||||
ai_char->update();
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,86 +150,6 @@ void AIWorld::flock_on(unsigned int flock_id) {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<<endl;
|
||||
q = q->_next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function adds the nodepath as an obstacle that is needed by the
|
||||
* obstacle avoidance behavior.
|
||||
|
@ -21,27 +21,6 @@
|
||||
class AICharacter;
|
||||
class Flock;
|
||||
|
||||
/**
|
||||
* 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 EXPCL_PANDAAI 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();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -51,7 +30,8 @@ class EXPCL_PANDAAI AICharPool {
|
||||
*/
|
||||
class EXPCL_PANDAAI AIWorld {
|
||||
private:
|
||||
AICharPool * _ai_char_pool;
|
||||
typedef std::vector<PT(AICharacter)> AICharPool;
|
||||
AICharPool _ai_char_pool;
|
||||
NodePath _render;
|
||||
public:
|
||||
vector<NodePath> _obstacles;
|
||||
|
@ -40,7 +40,7 @@ public:
|
||||
unsigned int _alignment_wt;
|
||||
|
||||
// This vector will hold all the ai characters which belong to this flock.
|
||||
typedef std::vector<AICharacter*> AICharList;
|
||||
typedef std::vector<PT(AICharacter)> AICharList;
|
||||
AICharList _ai_char_list;
|
||||
|
||||
PUBLISHED:
|
||||
|
Loading…
x
Reference in New Issue
Block a user