Added a "collision patch" system that groups entities into a grid on top of the map to make aura checking and collision detection faster.
This was SVN commit r3253.
This commit is contained in:
parent
96df45e83d
commit
45255d3f37
@ -7,63 +7,61 @@
|
||||
|
||||
CBoundingObject* getContainingObject( const CVector2D& point )
|
||||
{
|
||||
std::vector<HEntity>* entities = g_EntityManager.getExtant();
|
||||
std::vector<HEntity>::iterator it;
|
||||
std::vector<CEntity*> entities;
|
||||
g_EntityManager.GetInRange( point.x, point.y, COLLISION_RANGE, entities );
|
||||
std::vector<CEntity*>::iterator it;
|
||||
|
||||
for( it = entities->begin(); it != entities->end(); it++ )
|
||||
for( it = entities.begin(); it != entities.end(); it++ )
|
||||
{
|
||||
if( !(*it)->m_bounds ) continue;
|
||||
if( (*it)->m_bounds->contains( point ) )
|
||||
{
|
||||
CBoundingObject* bounds = (*it)->m_bounds;
|
||||
delete( entities );
|
||||
return( bounds );
|
||||
}
|
||||
}
|
||||
|
||||
delete( entities );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
CEntity* GetCollisionObject( float x, float y )
|
||||
{
|
||||
CVector2D point( x, y );
|
||||
std::vector<HEntity>* entities = g_EntityManager.getExtant();
|
||||
std::vector<HEntity>::iterator it;
|
||||
|
||||
for( it = entities->begin(); it != entities->end(); it++ )
|
||||
std::vector<CEntity*> entities;
|
||||
g_EntityManager.GetInRange( x, y, COLLISION_RANGE, entities );
|
||||
std::vector<CEntity*>::iterator it;
|
||||
|
||||
for( it = entities.begin(); it != entities.end(); it++ )
|
||||
{
|
||||
if( !(*it)->m_bounds ) continue;
|
||||
if( (*it)->m_bounds->contains( point ) )
|
||||
{
|
||||
CEntity* e = (*it);
|
||||
delete( entities );
|
||||
return( e );
|
||||
}
|
||||
}
|
||||
|
||||
delete( entities );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
CBoundingObject* getCollisionObject( CBoundingObject* bounds )
|
||||
{
|
||||
std::vector<HEntity>* entities = g_EntityManager.getExtant();
|
||||
std::vector<HEntity>::iterator it;
|
||||
std::vector<CEntity*> entities;
|
||||
g_EntityManager.GetInRange( bounds->m_pos.x, bounds->m_pos.y, COLLISION_RANGE, entities );
|
||||
std::vector<CEntity*>::iterator it;
|
||||
|
||||
for( it = entities->begin(); it != entities->end(); it++ )
|
||||
for( it = entities.begin(); it != entities.end(); it++ )
|
||||
{
|
||||
if( !(*it)->m_bounds ) continue;
|
||||
if( (*it)->m_bounds == bounds ) continue;
|
||||
if( bounds->intersects( (*it)->m_bounds ) )
|
||||
{
|
||||
CBoundingObject* obj = (*it)->m_bounds;
|
||||
delete( entities );
|
||||
return( obj );
|
||||
}
|
||||
}
|
||||
|
||||
delete( entities );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
@ -75,22 +73,21 @@ HEntity getCollisionObject( CEntity* entity )
|
||||
if( !entity->m_bounds ) return HEntity();
|
||||
#endif
|
||||
|
||||
std::vector<HEntity>* entities = g_EntityManager.getExtant();
|
||||
std::vector<HEntity>::iterator it;
|
||||
std::vector<CEntity*> entities;
|
||||
g_EntityManager.GetInRange( entity->m_position.X, entity->m_position.Z, COLLISION_RANGE, entities );
|
||||
std::vector<CEntity*>::iterator it;
|
||||
|
||||
for( it = entities->begin(); it != entities->end(); it++ )
|
||||
for( it = entities.begin(); it != entities.end(); it++ )
|
||||
{
|
||||
if( !(*it)->m_bounds ) continue;
|
||||
if( (*it)->m_bounds == entity->m_bounds ) continue;
|
||||
if( entity->m_bounds->intersects( (*it)->m_bounds ) )
|
||||
{
|
||||
HEntity collisionObject = *it;
|
||||
delete( entities );
|
||||
HEntity collisionObject = HEntity((*it)->me);
|
||||
return( collisionObject );
|
||||
}
|
||||
}
|
||||
|
||||
delete( entities );
|
||||
return HEntity();
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,9 @@ struct rayIntersectionResults
|
||||
float distance;
|
||||
};
|
||||
|
||||
// maximum radius at which we check for entities (if some entity is much bigger than this, that's bad)
|
||||
#define COLLISION_RANGE 30
|
||||
|
||||
typedef std::vector<CEntity*> RayIntersects;
|
||||
|
||||
HEntity getCollisionObject( CEntity* entity );
|
||||
|
@ -67,7 +67,9 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation )
|
||||
AddProperty( EventNames[t], &m_EventHandlers[t], false );
|
||||
AddHandler( t, &m_EventHandlers[t] );
|
||||
}
|
||||
|
||||
|
||||
m_collisionPatch = NULL;
|
||||
|
||||
// Set our parent unit and build us an actor.
|
||||
m_actor = NULL;
|
||||
m_bounds = NULL;
|
||||
@ -173,6 +175,8 @@ void CEntity::kill()
|
||||
m_actor = NULL;
|
||||
}
|
||||
|
||||
updateCollisionPatch();
|
||||
|
||||
me = HEntity(); // will deallocate the entity, assuming nobody else has a reference to it
|
||||
}
|
||||
|
||||
@ -340,30 +344,39 @@ void CEntity::update( size_t timestep )
|
||||
case CEntityOrder::ORDER_GOTO_COLLISION:
|
||||
case CEntityOrder::ORDER_GOTO_SMOOTHED:
|
||||
if( processGotoNoPathing( current, timestep ) ) break;
|
||||
updateCollisionPatch();
|
||||
return;
|
||||
case CEntityOrder::ORDER_ATTACK_MELEE:
|
||||
if( processAttackMeleeNoPathing( current, timestep ) ) break;
|
||||
updateCollisionPatch();
|
||||
return;
|
||||
case CEntityOrder::ORDER_ATTACK_MELEE_NOPATHING:
|
||||
if( processAttackMeleeNoPathing( current, timestep ) ) break;
|
||||
updateCollisionPatch();
|
||||
return;
|
||||
case CEntityOrder::ORDER_GATHER:
|
||||
if( processGather( current, timestep ) ) break;
|
||||
updateCollisionPatch();
|
||||
return;
|
||||
case CEntityOrder::ORDER_GATHER_NOPATHING:
|
||||
if( processGatherNoPathing( current, timestep ) ) break;
|
||||
updateCollisionPatch();
|
||||
return;
|
||||
case CEntityOrder::ORDER_HEAL:
|
||||
if( processHeal( current, timestep ) ) break;
|
||||
updateCollisionPatch();
|
||||
return;
|
||||
case CEntityOrder::ORDER_HEAL_NOPATHING:
|
||||
if( processHealNoPathing( current, timestep ) ) break;
|
||||
updateCollisionPatch();
|
||||
return;
|
||||
case CEntityOrder::ORDER_GOTO:
|
||||
if( processGoto( current, timestep ) ) break;
|
||||
updateCollisionPatch();
|
||||
return;
|
||||
case CEntityOrder::ORDER_PATROL:
|
||||
if( processPatrol( current, timestep ) ) break;
|
||||
updateCollisionPatch();
|
||||
return;
|
||||
case CEntityOrder::ORDER_PATH_END_MARKER:
|
||||
m_orderQueue.pop_front();
|
||||
@ -399,6 +412,44 @@ void CEntity::update( size_t timestep )
|
||||
}
|
||||
}
|
||||
|
||||
void CEntity::updateCollisionPatch()
|
||||
{
|
||||
vector<CEntity*>* newPatch = g_EntityManager.getCollisionPatch( this );
|
||||
if( newPatch != m_collisionPatch )
|
||||
{
|
||||
if( m_collisionPatch )
|
||||
{
|
||||
// remove ourselves from old patch
|
||||
vector<CEntity*>& old = *m_collisionPatch;
|
||||
if( old.size() == 1 )
|
||||
{
|
||||
// we were the only ones there, just pop us
|
||||
old.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
// find our location and put in the last guy in the patch, then pop back
|
||||
for( size_t i=0; i < old.size(); i++ )
|
||||
{
|
||||
if( old[i] == this )
|
||||
{
|
||||
old[i] = old.back();
|
||||
old.pop_back();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( m_extant )
|
||||
{
|
||||
// add ourselves to new patch
|
||||
newPatch->push_back( this );
|
||||
m_collisionPatch = newPatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if AURA_TEST
|
||||
void CEntity::UpdateAuras( size_t timestep_millis )
|
||||
{
|
||||
@ -583,6 +634,7 @@ void CEntity::teleport()
|
||||
{
|
||||
m_position = m_graphics_position;
|
||||
m_bounds->setPosition( m_position.X, m_position.Z );
|
||||
updateCollisionPatch();
|
||||
repath();
|
||||
}
|
||||
|
||||
@ -1130,6 +1182,8 @@ bool CEntity::Kill( JSContext* UNUSED(cx), uintN UNUSED(argc), jsval* UNUSED(arg
|
||||
{
|
||||
m_extant = false;
|
||||
}
|
||||
|
||||
updateCollisionPatch();
|
||||
|
||||
g_Selection.removeAll( me );
|
||||
|
||||
|
@ -124,6 +124,9 @@ public:
|
||||
// moved since it was last calculated, and the terrain hasn't been changed).
|
||||
bool m_actor_transform_valid;
|
||||
|
||||
// Our current collision patch in CEntityManager
|
||||
std::vector<CEntity*>* m_collisionPatch;
|
||||
|
||||
//-- Scripts
|
||||
|
||||
// Get script execution contexts - always run in the context of the entity that fired it.
|
||||
@ -201,6 +204,9 @@ public:
|
||||
// Process damage
|
||||
void Damage( CDamageType& damage, CEntity* inflictor = NULL );
|
||||
|
||||
// Update collision patch (move ourselves to a new one if necessary)
|
||||
void updateCollisionPatch();
|
||||
|
||||
float getAnchorLevel( float x, float z );
|
||||
|
||||
void snapToGround();
|
||||
|
@ -5,13 +5,16 @@
|
||||
#include "BaseEntityCollection.h"
|
||||
#include "ConfigDB.h"
|
||||
#include "Profile.h"
|
||||
#include "Terrain.h"
|
||||
#include "Game.h"
|
||||
|
||||
int SELECTION_CIRCLE_POINTS;
|
||||
int SELECTION_BOX_POINTS;
|
||||
int SELECTION_SMOOTHNESS_UNIFIED = 9;
|
||||
|
||||
CEntityManager::CEntityManager()
|
||||
: m_entities() // janwas: default-initialize entire array;
|
||||
: m_collisionPatches(0)
|
||||
, m_entities() // janwas: default-initialize entire array;
|
||||
// CHandle ctor sets m_entity and m_refcount to 0
|
||||
{
|
||||
m_nextalloc = 0;
|
||||
@ -30,12 +33,14 @@ CEntityManager::~CEntityManager()
|
||||
m_extant = false;
|
||||
|
||||
for( int i = 0; i < MAX_HANDLES; i++ )
|
||||
{
|
||||
if( m_entities[i].m_refcount )
|
||||
{
|
||||
delete( m_entities[i].m_entity );
|
||||
m_entities[i].m_entity = 0;
|
||||
m_entities[i].m_refcount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete entities that were killed, but not yet reaped by a call to updateAll,
|
||||
// to avoid memory leak warnings upon exiting
|
||||
@ -43,6 +48,9 @@ CEntityManager::~CEntityManager()
|
||||
for( it = m_reaper.begin(); it < m_reaper.end(); it++ )
|
||||
delete( *it );
|
||||
m_reaper.clear();
|
||||
|
||||
delete[] m_collisionPatches;
|
||||
m_collisionPatches = 0;
|
||||
}
|
||||
|
||||
void CEntityManager::deleteAll()
|
||||
@ -123,7 +131,36 @@ void CEntityManager::GetExtant( std::vector<CEntity*>& results )
|
||||
void CEntityManager::GetInRange( float x, float z, float radius, std::vector<CEntity*>& results )
|
||||
{
|
||||
results.clear();
|
||||
for( int i = 0; i < MAX_HANDLES; i++ )
|
||||
|
||||
int cx = (int) ( x / COLLISION_PATCH_SIZE );
|
||||
int cz = (int) ( z / COLLISION_PATCH_SIZE );
|
||||
|
||||
int r = (int) ( radius / COLLISION_PATCH_SIZE + 1 );
|
||||
|
||||
int minX = MAX(cx-r, 0);
|
||||
int minZ = MAX(cz-r, 0);
|
||||
int maxX = MIN(cx+r, m_collisionPatchesPerSide-1);
|
||||
int maxZ = MIN(cz+r, m_collisionPatchesPerSide-1);
|
||||
|
||||
for( int px = minX; px <= maxX; px++ )
|
||||
{
|
||||
for( int pz = minZ; pz <= maxZ; pz++ )
|
||||
{
|
||||
std::vector<CEntity*>& vec = m_collisionPatches[ px * m_collisionPatchesPerSide + pz ];
|
||||
for( std::vector<CEntity*>::iterator it = vec.begin(); it != vec.end(); it++ )
|
||||
{
|
||||
CEntity* e = *it;
|
||||
float dx = x - e->m_position.X;
|
||||
float dz = z - e->m_position.Z;
|
||||
if(dx*dx + dz*dz <= radius*radius)
|
||||
{
|
||||
results.push_back( e );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*for( int i = 0; i < MAX_HANDLES; i++ )
|
||||
{
|
||||
if( m_entities[i].m_refcount && !m_entities[i].m_entity->m_destroyed && m_entities[i].m_entity->m_extant )
|
||||
{
|
||||
@ -134,7 +171,7 @@ void CEntityManager::GetInRange( float x, float z, float radius, std::vector<CEn
|
||||
results.push_back( m_entities[i].m_entity );
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
/*
|
||||
@ -148,15 +185,27 @@ void CEntityManager::dispatchAll( CMessage* msg )
|
||||
|
||||
void CEntityManager::InitializeAll()
|
||||
{
|
||||
CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
|
||||
int unitsPerSide = CELL_SIZE * ( terrain->GetVerticesPerSide() - 1 );
|
||||
m_collisionPatchesPerSide = unitsPerSide / COLLISION_PATCH_SIZE + 1;
|
||||
|
||||
m_collisionPatches = new std::vector<CEntity*>[m_collisionPatchesPerSide * m_collisionPatchesPerSide];
|
||||
|
||||
for( int i = 0; i < MAX_HANDLES; i++ )
|
||||
{
|
||||
if( m_entities[i].m_refcount && !m_entities[i].m_entity->m_destroyed )
|
||||
m_entities[i].m_entity->Initialize();
|
||||
{
|
||||
CEntity* e = m_entities[i].m_entity;
|
||||
e->Initialize();
|
||||
e->updateCollisionPatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CEntityManager::TickAll()
|
||||
{
|
||||
for( int i = 0; i < MAX_HANDLES; i++ )
|
||||
if( m_entities[i].m_refcount && !m_entities[i].m_entity->m_destroyed )
|
||||
if( m_entities[i].m_refcount && !m_entities[i].m_entity->m_destroyed && m_entities[i].m_entity->m_extant )
|
||||
m_entities[i].m_entity->Tick();
|
||||
}
|
||||
|
||||
@ -183,7 +232,6 @@ void CEntityManager::updateAll( size_t timestep )
|
||||
PROFILE_END( "tick all" );
|
||||
*/
|
||||
|
||||
|
||||
PROFILE_START( "update all" );
|
||||
for( int i = 0; i < MAX_HANDLES; i++ )
|
||||
if( m_entities[i].m_refcount && !m_entities[i].m_entity->m_destroyed )
|
||||
@ -219,3 +267,15 @@ void CEntityManager::destroy( u16 handle )
|
||||
}
|
||||
|
||||
bool CEntityManager::m_extant = false;
|
||||
|
||||
std::vector<CEntity*>* CEntityManager::getCollisionPatch( CEntity* e )
|
||||
{
|
||||
if( !e->m_extant )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ix = (int) ( e->m_position.X / COLLISION_PATCH_SIZE );
|
||||
int iz = (int) ( e->m_position.Z / COLLISION_PATCH_SIZE );
|
||||
return &m_collisionPatches[ ix * m_collisionPatchesPerSide + iz ];
|
||||
}
|
||||
|
@ -27,6 +27,9 @@
|
||||
|
||||
#define MAX_HANDLES 4096
|
||||
|
||||
// collision patch size, in graphics units, not tiles (1 tile = 4 units)
|
||||
#define COLLISION_PATCH_SIZE 8
|
||||
|
||||
#define g_EntityManager CEntityManager::GetSingleton()
|
||||
|
||||
class CEntityManager : public Singleton<CEntityManager>
|
||||
@ -38,6 +41,8 @@ friend class CHandle;
|
||||
int m_nextalloc;
|
||||
static bool m_extant;
|
||||
void destroy( u16 handle );
|
||||
int m_collisionPatchesPerSide;
|
||||
std::vector<CEntity*>* m_collisionPatches;
|
||||
public:
|
||||
|
||||
CEntityManager();
|
||||
@ -76,6 +81,8 @@ public:
|
||||
}
|
||||
|
||||
void GetInRange( float x, float z, float radius, std::vector<CEntity*>& results );
|
||||
|
||||
std::vector<CEntity*>* getCollisionPatch( CEntity* e );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user