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);
|
_velocity = LVecBase3(0.0, 0.0, 0.0);
|
||||||
_steering_force = LVecBase3(0.0, 0.0, 0.0);
|
_steering_force = LVecBase3(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
_world = nullptr;
|
||||||
|
|
||||||
_steering = new AIBehaviors();
|
_steering = new AIBehaviors();
|
||||||
_steering->_ai_char = this;
|
_steering->_ai_char = this;
|
||||||
|
|
||||||
@ -31,6 +33,7 @@ AICharacter::AICharacter(string model_name, NodePath model_np, double mass, doub
|
|||||||
}
|
}
|
||||||
|
|
||||||
AICharacter::~AICharacter() {
|
AICharacter::~AICharacter() {
|
||||||
|
nassertv(_world == nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#define _AICHARACTER_H
|
#define _AICHARACTER_H
|
||||||
|
|
||||||
#include "aiBehaviors.h"
|
#include "aiBehaviors.h"
|
||||||
|
#include "referenceCount.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is used for creating the AI characters. It assigns both physics
|
* This class is used for creating the AI characters. It assigns both physics
|
||||||
@ -25,7 +26,7 @@
|
|||||||
class AIBehaviors;
|
class AIBehaviors;
|
||||||
class AIWorld;
|
class AIWorld;
|
||||||
|
|
||||||
class EXPCL_PANDAAI AICharacter {
|
class EXPCL_PANDAAI AICharacter : public ReferenceCount {
|
||||||
public:
|
public:
|
||||||
double _mass;
|
double _mass;
|
||||||
double _max_force;
|
double _max_force;
|
||||||
|
@ -14,44 +14,56 @@
|
|||||||
#include "aiWorld.h"
|
#include "aiWorld.h"
|
||||||
|
|
||||||
AIWorld::AIWorld(NodePath render) {
|
AIWorld::AIWorld(NodePath render) {
|
||||||
_ai_char_pool = new AICharPool();
|
_render = move(render);
|
||||||
_render = render;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AIWorld::~AIWorld() {
|
AIWorld::~AIWorld() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AIWorld::add_ai_char(AICharacter *ai_char) {
|
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->_window_render = _render;
|
||||||
ai_char->_world = this;
|
ai_char->_world = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AIWorld::remove_ai_char(string name) {
|
void AIWorld::remove_ai_char(string name) {
|
||||||
_ai_char_pool->del(name);
|
AICharPool::iterator it;
|
||||||
remove_ai_char_from_flock(name);
|
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) {
|
void AIWorld::remove_ai_char_from_flock(string name) {
|
||||||
AICharPool::node *ai_pool;
|
for (AICharacter *ai_char : _ai_char_pool) {
|
||||||
ai_pool = _ai_char_pool->_head;
|
for (Flock *flock : _flock_pool) {
|
||||||
while((ai_pool) != NULL) {
|
if (ai_char->_ai_char_flock_id == flock->get_id()) {
|
||||||
for(unsigned int i = 0; i < _flock_pool.size(); ++i) {
|
for (size_t j = 0; j < flock->_ai_char_list.size(); ++j) {
|
||||||
if(ai_pool->_ai_char->_ai_char_flock_id == _flock_pool[i]->get_id()) {
|
if (flock->_ai_char_list[j]->_name == name) {
|
||||||
for(unsigned int j = 0; j<_flock_pool[i]->_ai_char_list.size(); ++j) {
|
flock->_ai_char_list.erase(flock->_ai_char_list.begin() + 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;
|
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() {
|
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.
|
* characters which have been added to the AIWorld.
|
||||||
*/
|
*/
|
||||||
void AIWorld::update() {
|
void AIWorld::update() {
|
||||||
AICharPool::node *ai_pool;
|
for (AICharacter *ai_char : _ai_char_pool) {
|
||||||
ai_pool = _ai_char_pool->_head;
|
ai_char->update();
|
||||||
|
|
||||||
while((ai_pool)!=NULL) {
|
|
||||||
ai_pool->_ai_char->update();
|
|
||||||
ai_pool = ai_pool->_next;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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
|
* This function adds the nodepath as an obstacle that is needed by the
|
||||||
* obstacle avoidance behavior.
|
* obstacle avoidance behavior.
|
||||||
|
@ -21,27 +21,6 @@
|
|||||||
class AICharacter;
|
class AICharacter;
|
||||||
class Flock;
|
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
|
* 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 active at any given time. It contains a linked list of AI
|
||||||
@ -51,7 +30,8 @@ class EXPCL_PANDAAI AICharPool {
|
|||||||
*/
|
*/
|
||||||
class EXPCL_PANDAAI AIWorld {
|
class EXPCL_PANDAAI AIWorld {
|
||||||
private:
|
private:
|
||||||
AICharPool * _ai_char_pool;
|
typedef std::vector<PT(AICharacter)> AICharPool;
|
||||||
|
AICharPool _ai_char_pool;
|
||||||
NodePath _render;
|
NodePath _render;
|
||||||
public:
|
public:
|
||||||
vector<NodePath> _obstacles;
|
vector<NodePath> _obstacles;
|
||||||
|
@ -40,7 +40,7 @@ public:
|
|||||||
unsigned int _alignment_wt;
|
unsigned int _alignment_wt;
|
||||||
|
|
||||||
// This vector will hold all the ai characters which belong to this flock.
|
// 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;
|
AICharList _ai_char_list;
|
||||||
|
|
||||||
PUBLISHED:
|
PUBLISHED:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user