Pathfinding tweaks; coldet fixes.
This was SVN commit r379.
This commit is contained in:
parent
4daa183dd3
commit
d32be2011f
@ -160,7 +160,7 @@ void CMapReader::ApplyData(CFileUnpacker& unpacker)
|
||||
CVector3D orient = -((CMatrix3D*)m_Objects[i].m_Transform)->GetIn();
|
||||
CVector3D position = ((CMatrix3D*)m_Objects[i].m_Transform)->GetTranslation();
|
||||
|
||||
g_EntityManager.create( templateObject, position, atan2( orient.X, orient.Z ) );
|
||||
g_EntityManager.create( templateObject, position, atan2( -orient.X, -orient.Z ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -155,7 +155,7 @@ void calc_fps()
|
||||
// update fps counter if update threshold is exceeded
|
||||
const float avg_fps = fps_sum / H;
|
||||
const float d_avg = avg_fps-fps;
|
||||
const float max_diff = fminf(5.f, 0.05f*fps);
|
||||
const float max_diff = __min( 5.f, 0.05f * fps ); //fminf(5.f, 0.05f*fps);
|
||||
|
||||
if((trend > 0 && (avg_fps > fps || d_avg < -4.f)) || // going up, or large drop
|
||||
(trend < 0 && (avg_fps < fps || d_avg > 4.f)) || // going down, or large raise
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: Renderer.cpp
|
||||
@ -1345,4 +1346,4 @@ void CRenderer::UpdateSubmittedObjectData()
|
||||
// (recursively) build transparent passes from model
|
||||
BuildTransparentPasses(m_Models[i]);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -46,7 +46,7 @@ CBoundingCircle::CBoundingCircle( float x, float y, CBoundingCircle* copy )
|
||||
void CBoundingObject::setPosition( float x, float y )
|
||||
{
|
||||
m_pos.x = x; m_pos.y = y;
|
||||
m_pos += m_offset;
|
||||
m_pos -= m_offset;
|
||||
}
|
||||
|
||||
void CBoundingCircle::setRadius( float radius )
|
||||
@ -99,6 +99,23 @@ CBoundingBox::CBoundingBox( float x, float y, const CVector2D& u, CBoundingBox*
|
||||
setOrientation( u );
|
||||
}
|
||||
|
||||
CBoundingBox::CBoundingBox( float x, float y, float orientation, float width, float height )
|
||||
{
|
||||
m_type = BOUND_OABB;
|
||||
setPosition( x, y );
|
||||
setDimensions( width, height );
|
||||
setOrientation( orientation );
|
||||
}
|
||||
|
||||
CBoundingBox::CBoundingBox( float x, float y, float orientation, CBoundingBox* copy )
|
||||
{
|
||||
m_type = BOUND_OABB;
|
||||
m_offset = copy->m_offset;
|
||||
setPosition( x, y );
|
||||
setDimensions( copy->getWidth(), copy->getHeight() );
|
||||
setOrientation( orientation );
|
||||
}
|
||||
|
||||
void CBoundingBox::setDimensions( float width, float height )
|
||||
{
|
||||
m_w = width / 2.0f;
|
||||
|
@ -56,15 +56,9 @@ public:
|
||||
CVector2D m_v; // Unit vector along the direction of this box's width.
|
||||
float m_h; // Half this box's height.
|
||||
float m_w; // Half this box's width.
|
||||
CBoundingBox( float x, float y, float orientation, float width, float height )
|
||||
{
|
||||
CBoundingBox( x, y, CVector2D( sin( orientation ), cos( orientation ) ), width, height );
|
||||
}
|
||||
CBoundingBox( float x, float y, float orientation, float width, float height );
|
||||
CBoundingBox( float x, float y, const CVector2D& orientation, float width, float height );
|
||||
CBoundingBox( float x, float y, float orientation, CBoundingBox* copy )
|
||||
{
|
||||
CBoundingBox( x, y, CVector2D( sin( orientation ), cos( orientation ) ), copy );
|
||||
}
|
||||
CBoundingBox( float x, float y, float orientation, CBoundingBox* copy );
|
||||
CBoundingBox( float x, float y, const CVector2D& orientation, CBoundingBox* copy );
|
||||
void setDimensions( float width, float height );
|
||||
void setOrientation( float orientation );
|
||||
|
@ -54,7 +54,7 @@ HEntity getCollisionObject( CEntity* entity, float x, float y )
|
||||
return( _e );
|
||||
}
|
||||
|
||||
bool getRayIntersection( const CVector2D& source, const CVector2D& forward, const CVector2D& right, float length, float maxDistance, rayIntersectionResults* results )
|
||||
bool getRayIntersection( const CVector2D& source, const CVector2D& forward, const CVector2D& right, float length, float maxDistance, CBoundingObject* destinationCollisionObject, rayIntersectionResults* results )
|
||||
{
|
||||
std::vector<HEntity>* entities = g_EntityManager.getActive();
|
||||
std::vector<HEntity>::iterator it;
|
||||
@ -69,13 +69,17 @@ bool getRayIntersection( const CVector2D& source, const CVector2D& forward, cons
|
||||
for( it = entities->begin(); it != entities->end(); it++ )
|
||||
{
|
||||
assert( (*it)->m_bounds );
|
||||
if( (*it)->m_bounds == destinationCollisionObject ) continue;
|
||||
// HACK:
|
||||
if( (*it)->m_bounds->m_type == CBoundingObject::BOUND_OABB ) continue;
|
||||
if( (*it)->m_speed ) continue;
|
||||
CBoundingObject* obj = (*it)->m_bounds;
|
||||
delta = obj->m_pos - source;
|
||||
closestApproach = delta.dot( right );
|
||||
dist = delta.dot( forward );
|
||||
float collisionRadius = maxDistance + obj->m_radius;
|
||||
|
||||
if( ( fabs( closestApproach ) < maxDistance + obj->m_radius ) && ( dist > -maxDistance ) && ( dist < length + maxDistance ) )
|
||||
if( ( fabs( closestApproach ) < collisionRadius ) && ( dist > collisionRadius * 0.0f ) && ( dist < length - collisionRadius * 0.0f ) )
|
||||
{
|
||||
if( dist < results->distance )
|
||||
{
|
||||
|
@ -30,6 +30,6 @@ struct rayIntersectionResults
|
||||
HEntity getCollisionObject( CEntity* entity );
|
||||
HEntity getCollisionObject( CEntity* entity, float x, float y );
|
||||
CBoundingObject* getContainingObject( const CVector2D& point );
|
||||
bool getRayIntersection( const CVector2D& source, const CVector2D& forward, const CVector2D& right, float length, float maxDistance, rayIntersectionResults* results );
|
||||
bool getRayIntersection( const CVector2D& source, const CVector2D& forward, const CVector2D& right, float length, float maxDistance, CBoundingObject* destinationCollisionObject, rayIntersectionResults* results );
|
||||
|
||||
#endif
|
||||
|
@ -17,6 +17,10 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation )
|
||||
m_base = base;
|
||||
m_actor = new CUnit(m_base->m_actorObject,m_base->m_actorObject->m_Model->Clone());
|
||||
|
||||
|
||||
// HACK: Debugging
|
||||
// assert( m_base->m_name != CStr( "Waypoint" ) );
|
||||
|
||||
// Register the actor with the renderer.
|
||||
|
||||
g_UnitMan.AddUnit( m_actor );
|
||||
@ -33,13 +37,13 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation )
|
||||
|
||||
if( m_base->m_bound_type == CBoundingObject::BOUND_CIRCLE )
|
||||
{
|
||||
m_bounds = new CBoundingCircle( m_position.X, m_position.Z, m_base->m_bound_circle );
|
||||
m_bounds = new CBoundingCircle( m_position.X, m_position.Z, m_base->m_bound_circle );
|
||||
}
|
||||
else if( m_base->m_bound_type == CBoundingObject::BOUND_OABB )
|
||||
{
|
||||
m_bounds = new CBoundingBox( m_position.X, m_position.Z, m_ahead, m_base->m_bound_box );
|
||||
}
|
||||
|
||||
|
||||
snapToGround();
|
||||
updateActorTransforms();
|
||||
|
||||
@ -141,6 +145,7 @@ void CEntity::update( float timestep )
|
||||
{
|
||||
case CEntityOrder::ORDER_GOTO_NOPATHING:
|
||||
case CEntityOrder::ORDER_GOTO_COLLISION:
|
||||
case CEntityOrder::ORDER_GOTO_SMOOTHED:
|
||||
if( processGotoNoPathing( current, timestep ) ) break;
|
||||
return;
|
||||
case CEntityOrder::ORDER_GOTO:
|
||||
@ -200,21 +205,59 @@ void CEntity::pushOrder( CEntityOrder& order )
|
||||
void CEntity::render()
|
||||
{
|
||||
// Rich! Help! ;)
|
||||
// We can loose this later on, I just need a way to see collision boxes temporarily
|
||||
|
||||
// HACK: As in this entire function is a...
|
||||
|
||||
if( !m_orderQueue.empty() )
|
||||
{
|
||||
glShadeModel( GL_FLAT );
|
||||
glBegin( GL_LINE_STRIP );
|
||||
|
||||
std::deque<CEntityOrder>::iterator it;
|
||||
CBoundingObject* destinationCollisionObject;
|
||||
float x0, y0, x, y;
|
||||
|
||||
glVertex3f( m_position.X, m_position.Y + 0.25f /* 20.0f */, m_position.Z );
|
||||
x = m_orderQueue.front().m_data[0].location.x;
|
||||
y = m_orderQueue.front().m_data[0].location.y;
|
||||
|
||||
for( it = m_orderQueue.begin(); it < m_orderQueue.end(); it++ )
|
||||
{
|
||||
float x = it->m_data[0].location.x;
|
||||
float y = it->m_data[0].location.y;
|
||||
if( it->m_type == CEntityOrder::ORDER_PATROL )
|
||||
break;
|
||||
x = it->m_data[0].location.x;
|
||||
y = it->m_data[0].location.y;
|
||||
}
|
||||
destinationCollisionObject = getContainingObject( CVector2D( x, y ) );
|
||||
|
||||
glShadeModel( GL_FLAT );
|
||||
glBegin( GL_LINE_STRIP );
|
||||
|
||||
|
||||
|
||||
glVertex3f( m_position.X, m_position.Y + 0.25f, m_position.Z );
|
||||
|
||||
|
||||
x = m_position.X;
|
||||
y = m_position.Z;
|
||||
|
||||
for( it = m_orderQueue.begin(); it < m_orderQueue.end(); it++ )
|
||||
{
|
||||
x0 = x; y0 = y;
|
||||
x = it->m_data[0].location.x;
|
||||
y = it->m_data[0].location.y;
|
||||
rayIntersectionResults r;
|
||||
CVector2D fwd( x - x0, y - y0 );
|
||||
float l = fwd.length();
|
||||
fwd = fwd.normalize();
|
||||
CVector2D rgt = fwd.beta();
|
||||
if( getRayIntersection( CVector2D( x0, y0 ), fwd, rgt, l, m_bounds->m_radius, destinationCollisionObject, &r ) )
|
||||
{
|
||||
glEnd();
|
||||
glBegin( GL_LINES );
|
||||
glColor3f( 1.0f, 0.0f, 0.0f );
|
||||
glVertex3f( x0 + fwd.x * r.distance, getExactGroundLevel( x0 + fwd.x * r.distance, y0 + fwd.y * r.distance ) + 0.25f, y0 + fwd.y * r.distance );
|
||||
glVertex3f( r.position.x, getExactGroundLevel( r.position.x, r.position.y ) + 0.25f, r.position.y );
|
||||
glEnd();
|
||||
glBegin( GL_LINE_STRIP );
|
||||
glVertex3f( x0, getExactGroundLevel( x0, y0 ), y0 );
|
||||
}
|
||||
switch( it->m_type )
|
||||
{
|
||||
case CEntityOrder::ORDER_GOTO:
|
||||
@ -222,11 +265,15 @@ void CEntity::render()
|
||||
case CEntityOrder::ORDER_GOTO_COLLISION:
|
||||
glColor3f( 1.0f, 0.5f, 0.5f ); break;
|
||||
case CEntityOrder::ORDER_GOTO_NOPATHING:
|
||||
case CEntityOrder::ORDER_GOTO_SMOOTHED:
|
||||
glColor3f( 0.5f, 0.5f, 0.5f ); break;
|
||||
case CEntityOrder::ORDER_PATROL:
|
||||
glColor3f( 0.0f, 1.0f, 0.0f ); break;
|
||||
default:
|
||||
glColor3f( 1.0f, 1.0f, 1.0f ); break;
|
||||
continue;
|
||||
}
|
||||
glVertex3f( x, getExactGroundLevel( x, y ) + 0.25f /* 20.0f */, y );
|
||||
|
||||
glVertex3f( x, getExactGroundLevel( x, y ) + 0.25f, y );
|
||||
}
|
||||
|
||||
glEnd();
|
||||
@ -237,7 +284,7 @@ void CEntity::render()
|
||||
|
||||
|
||||
if( getCollisionObject( this ) ) glColor3f( 0.5f, 0.5f, 1.0f );
|
||||
m_bounds->render( m_position.Y + 0.25f /* 20.0f */ );
|
||||
m_bounds->render( getExactGroundLevel( m_position.X, m_position.Z ) + 0.25f ); //m_position.Y + 0.25f );
|
||||
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,7 @@ class HEntity
|
||||
{
|
||||
friend class CEntityManager;
|
||||
u16 m_handle;
|
||||
private:
|
||||
void addRef();
|
||||
void decRef();
|
||||
HEntity( u16 index );
|
||||
|
@ -6,8 +6,11 @@
|
||||
//
|
||||
// Usage: All orders at this point use the location component of the union.
|
||||
// Orders are: ORDER_GOTO_NOPATHING: Attempts to reach the given destination via a line-of-sight
|
||||
// system. Do not create an order of this type directly; it is
|
||||
// ORDER_GOTO_SMOOTED: system. Do not create an order of these types directly; it is
|
||||
// used to return a path of line segments from the pathfinder.
|
||||
// _SMOOTHED flags to the entity state-control that it's OK to
|
||||
// smooth the corner between segments. _NOPATHING just does
|
||||
// zero-radius turns.
|
||||
// ORDER_GOTO_COLLISION: When the coldet system is trying to get us out of a collision,
|
||||
// it generates these intermediate waypoints. We don't really have
|
||||
// any reason to go to this specific point, so if a better way
|
||||
@ -45,6 +48,7 @@ public:
|
||||
enum
|
||||
{
|
||||
ORDER_GOTO_NOPATHING,
|
||||
ORDER_GOTO_SMOOTHED,
|
||||
ORDER_GOTO_COLLISION,
|
||||
ORDER_GOTO,
|
||||
ORDER_PATROL
|
||||
|
@ -14,13 +14,71 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, float timestep )
|
||||
|
||||
float len = delta.length();
|
||||
|
||||
if( len < 0.1f )
|
||||
// Curve smoothing.
|
||||
// Here there be trig.
|
||||
|
||||
if( current->m_type != CEntityOrder::ORDER_GOTO_SMOOTHED )
|
||||
{
|
||||
m_orderQueue.pop_front();
|
||||
return( false );
|
||||
// We can only really attempt to smooth paths the pathfinder
|
||||
// has flagged for us. If the turning-radius calculations are
|
||||
// applied to other types of waypoint, wierdness happens.
|
||||
// Things like an entity trying to walk to a point inside
|
||||
// his turning radius (which he can't do directly, so he'll
|
||||
// orbit the point indefinately), or just massive deviations
|
||||
// making the paths we calculate useless.
|
||||
// It's also painful trying to watch two entities resolve their
|
||||
// collision when they're both bound by turning constraints.
|
||||
m_ahead = delta / len;
|
||||
m_orientation = atan2( m_ahead.x, m_ahead.y );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_targetorientation = atan2( delta.x, delta.y );
|
||||
|
||||
float deltatheta = m_targetorientation - m_orientation;
|
||||
while( deltatheta > PI ) deltatheta -= 2 * PI;
|
||||
while( deltatheta < -PI ) deltatheta += 2 * PI;
|
||||
|
||||
if( fabs( deltatheta ) > 0.01f )
|
||||
{
|
||||
float maxTurningSpeed = ( m_speed / m_turningRadius ) * timestep;
|
||||
if( deltatheta > 0 )
|
||||
{
|
||||
m_orientation += MIN( deltatheta, maxTurningSpeed );
|
||||
}
|
||||
else
|
||||
m_orientation += MAX( deltatheta, -maxTurningSpeed );
|
||||
|
||||
m_ahead.x = sin( m_orientation );
|
||||
m_ahead.y = cos( m_orientation );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ahead = delta / len;
|
||||
m_orientation = atan2( m_ahead.x, m_ahead.y );
|
||||
}
|
||||
}
|
||||
|
||||
m_ahead = delta / len;
|
||||
if( len < 0.1f )
|
||||
{
|
||||
if( current->m_type == CEntityOrder::ORDER_GOTO_COLLISION )
|
||||
{
|
||||
// Repath.
|
||||
CVector2D destination;
|
||||
while( !m_orderQueue.empty() &&
|
||||
( ( m_orderQueue.front().m_type == CEntityOrder::ORDER_GOTO_COLLISION )
|
||||
|| ( m_orderQueue.front().m_type == CEntityOrder::ORDER_GOTO_NOPATHING )
|
||||
|| ( m_orderQueue.front().m_type == CEntityOrder::ORDER_GOTO_SMOOTHED ) ) )
|
||||
{
|
||||
destination = m_orderQueue.front().m_data[0].location;
|
||||
m_orderQueue.pop_front();
|
||||
}
|
||||
g_Pathfinder.requestPath( me, destination );
|
||||
}
|
||||
else
|
||||
m_orderQueue.pop_front();
|
||||
return( false );
|
||||
}
|
||||
|
||||
if( m_bounds->m_type == CBoundingObject::BOUND_OABB )
|
||||
((CBoundingBox*)m_bounds)->setOrientation( m_ahead );
|
||||
@ -78,7 +136,7 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, float timestep )
|
||||
avoidance.m_type = CEntityOrder::ORDER_GOTO_COLLISION;
|
||||
CVector2D right;
|
||||
right.x = m_ahead.y; right.y = -m_ahead.x;
|
||||
CVector2D avoidancePosition = collide->m_bounds->m_pos + right * ( collide->m_bounds->m_radius * 2.5f );
|
||||
CVector2D avoidancePosition = collide->m_bounds->m_pos + right * ( collide->m_bounds->m_radius + m_bounds->m_radius * 2.5f );
|
||||
avoidance.m_data[0].location = avoidancePosition;
|
||||
if( current->m_type == CEntityOrder::ORDER_GOTO_COLLISION )
|
||||
m_orderQueue.pop_front();
|
||||
@ -91,12 +149,27 @@ bool CEntity::processGotoNoPathing( CEntityOrder* current, float timestep )
|
||||
{
|
||||
// A circle.
|
||||
// TODO: Implement this properly.
|
||||
// Try turning right.
|
||||
// Work out if our path goes to the left or to the right
|
||||
// of this obstacle. Go that way.
|
||||
// Weight a little to the right, too (helps unit-unit collisions)
|
||||
|
||||
CEntityOrder avoidance;
|
||||
avoidance.m_type = CEntityOrder::ORDER_GOTO_COLLISION;
|
||||
CVector2D right;
|
||||
right.x = m_ahead.y; right.y = -m_ahead.x;
|
||||
CVector2D avoidancePosition = collide->m_bounds->m_pos + right * ( collide->m_bounds->m_radius * 2.5f );
|
||||
CVector2D avoidancePosition;
|
||||
|
||||
if( ( collide->m_bounds->m_pos - m_bounds->m_pos ).dot( right ) < 1 )
|
||||
{
|
||||
// Turn right.
|
||||
avoidancePosition = collide->m_bounds->m_pos + right * ( collide->m_bounds->m_radius + m_bounds->m_radius * 2.5f );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Turn left.
|
||||
avoidancePosition = collide->m_bounds->m_pos - right * ( collide->m_bounds->m_radius + m_bounds->m_radius * 2.5f );
|
||||
}
|
||||
|
||||
avoidance.m_data[0].location = avoidancePosition;
|
||||
if( current->m_type == CEntityOrder::ORDER_GOTO_COLLISION )
|
||||
m_orderQueue.pop_front();
|
||||
|
@ -1,7 +1,5 @@
|
||||
#include "PathfindSparse.h"
|
||||
|
||||
#define NODESMOOTH_STEPS 4
|
||||
|
||||
sparsePathTree::sparsePathTree( const CVector2D& _from, const CVector2D& _to, HEntity _entity, CBoundingObject* _destinationCollisionObject )
|
||||
{
|
||||
from = _from; to = _to;
|
||||
@ -13,6 +11,7 @@ sparsePathTree::sparsePathTree( const CVector2D& _from, const CVector2D& _to, HE
|
||||
rightPre = NULL; rightPost = NULL;
|
||||
type = SPF_OPEN_UNVISITED;
|
||||
leftImpossible = false; rightImpossible = false;
|
||||
nextSubtree = 0;
|
||||
}
|
||||
|
||||
sparsePathTree::~sparsePathTree()
|
||||
@ -31,46 +30,58 @@ bool sparsePathTree::slice()
|
||||
|
||||
CVector2D forward = to - from;
|
||||
float len = forward.length();
|
||||
forward /= len;
|
||||
CVector2D right = CVector2D( forward.y, -forward.x );
|
||||
|
||||
// Hit nothing or hit destination; that's OK.
|
||||
if( !getRayIntersection( from, forward, right, len, entity->m_bounds->m_radius * 1.1f, &r ) || ( r.boundingObject == destinationCollisionObject ) )
|
||||
assert( len != 0.0f );
|
||||
|
||||
forward /= len;
|
||||
CVector2D v_right = CVector2D( forward.y, -forward.x );
|
||||
|
||||
if( !getRayIntersection( from, forward, v_right, len, entity->m_bounds->m_radius * 1.1f, destinationCollisionObject, &r ) )
|
||||
{
|
||||
type = SPF_CLOSED_DIRECT;
|
||||
return( true );
|
||||
}
|
||||
|
||||
float turningRadius = ( entity->m_bounds->m_radius + r.boundingObject->m_radius ) * 1.1f;
|
||||
float turningRadius = ( entity->m_bounds->m_radius + r.boundingObject->m_radius ) * 1.1f;
|
||||
|
||||
if( turningRadius < entity->m_turningRadius ) turningRadius = entity->m_turningRadius;
|
||||
|
||||
// Too close, an impossible turn
|
||||
if( r.distance < turningRadius ||
|
||||
r.distance > ( len - turningRadius ) )
|
||||
if( r.distance < turningRadius )
|
||||
{
|
||||
type = SPF_IMPOSSIBLE;
|
||||
return( true );
|
||||
// Too close to make a proper turn; try dodging immediately a long way to the left or right.
|
||||
left = from - v_right * r.boundingObject->m_radius * 2.5f;
|
||||
right = from + v_right * r.boundingObject->m_radius * 2.5f;
|
||||
}
|
||||
else if( r.distance > ( len - turningRadius ) )
|
||||
{
|
||||
// Again, too close to avoid it properly. Try approaching the goal from the left or right.
|
||||
left = to - v_right * r.boundingObject->m_radius * 2.5f;
|
||||
right = to + v_right * r.boundingObject->m_radius * 2.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Dodge to the left or right of the obstacle.
|
||||
// A distance of offsetDistance is sufficient to guarantee we'll make the turn.
|
||||
|
||||
CVector2D delta = r.position - from;
|
||||
float length = delta.length();
|
||||
CVector2D delta = r.position - from;
|
||||
float length = delta.length();
|
||||
|
||||
float offsetDistance = ( turningRadius * length / sqrt( length * length - turningRadius * turningRadius ) );
|
||||
|
||||
float offsetDistance = ( turningRadius * length / sqrt( length * length - turningRadius * turningRadius ) );
|
||||
left = r.position - v_right * offsetDistance;
|
||||
right = r.position + v_right * offsetDistance;
|
||||
}
|
||||
favourLeft = false;
|
||||
if( r.closestApproach < 0 )
|
||||
favourLeft = true;
|
||||
|
||||
|
||||
// First we path to the left...
|
||||
|
||||
left = r.position - right * offsetDistance;
|
||||
|
||||
leftPre = new sparsePathTree( from, left, entity, destinationCollisionObject );
|
||||
leftPost = new sparsePathTree( left, to, entity, destinationCollisionObject );
|
||||
|
||||
// Then we path to the right...
|
||||
|
||||
right = r.position + right * offsetDistance;
|
||||
rightPre = new sparsePathTree( from, right, entity, destinationCollisionObject );
|
||||
rightPost = new sparsePathTree( right, to, entity, destinationCollisionObject );
|
||||
|
||||
@ -87,24 +98,18 @@ bool sparsePathTree::slice()
|
||||
else /* type == SPF_OPEN_PROCESSING */
|
||||
{
|
||||
bool done = false;
|
||||
if( !leftImpossible )
|
||||
while( !done )
|
||||
{
|
||||
if( !done && ( leftPre->type & SPF_OPEN ) )
|
||||
done |= leftPre->slice();
|
||||
if( !done && ( leftPost->type & SPF_OPEN ) )
|
||||
done |= leftPost->slice();
|
||||
if( ( leftPre->type == SPF_IMPOSSIBLE ) || ( leftPost->type == SPF_IMPOSSIBLE ) )
|
||||
leftImpossible = true;
|
||||
}
|
||||
if( !rightImpossible && !done )
|
||||
{
|
||||
if( !done && ( rightPre->type & SPF_OPEN ) )
|
||||
done |= rightPre->slice();
|
||||
if( !done && ( rightPost->type & SPF_OPEN ) )
|
||||
done |= rightPost->slice();
|
||||
if( ( rightPre->type == SPF_IMPOSSIBLE ) || ( rightPost->type == SPF_IMPOSSIBLE ) )
|
||||
rightImpossible = true;
|
||||
if( subtrees[nextSubtree]->type & SPF_OPEN )
|
||||
if( subtrees[nextSubtree]->slice() )
|
||||
done = true;
|
||||
nextSubtree++;
|
||||
nextSubtree %= 4;
|
||||
}
|
||||
if( ( leftPre->type == SPF_IMPOSSIBLE ) || ( leftPost->type == SPF_IMPOSSIBLE ) )
|
||||
leftImpossible = true;
|
||||
if( ( rightPre->type == SPF_IMPOSSIBLE ) || ( rightPost->type == SPF_IMPOSSIBLE ) )
|
||||
rightImpossible = true;
|
||||
if( leftImpossible && rightImpossible )
|
||||
{
|
||||
type = SPF_IMPOSSIBLE;
|
||||
@ -149,14 +154,11 @@ void sparsePathTree::pushResults( std::vector<CVector2D>& nodelist )
|
||||
|
||||
void nodeSmooth( HEntity entity, std::vector<CVector2D>& nodelist )
|
||||
{
|
||||
// All your CPU are belong to us.
|
||||
// But Jan wanted it ;)
|
||||
|
||||
std::vector<CVector2D>::iterator it;
|
||||
CVector2D next = nodelist.front();
|
||||
|
||||
CEntityOrder node;
|
||||
node.m_type = CEntityOrder::ORDER_GOTO_NOPATHING;
|
||||
node.m_type = CEntityOrder::ORDER_GOTO_SMOOTHED;
|
||||
node.m_data[0].location = next;
|
||||
|
||||
entity->m_orderQueue.push_front( node );
|
||||
@ -173,30 +175,30 @@ void nodeSmooth( HEntity entity, std::vector<CVector2D>& nodelist )
|
||||
CVector2D ubar = u.beta();
|
||||
CVector2D vbar = v.beta();
|
||||
float alpha = entity->m_turningRadius * ( ubar - vbar ).length() / ( u + v ).length();
|
||||
u *= alpha;
|
||||
v *= alpha;
|
||||
|
||||
for( int t = NODESMOOTH_STEPS; t >= 0; t-- )
|
||||
{
|
||||
float lambda = t / (float)NODESMOOTH_STEPS;
|
||||
CVector2D arcpoint = current + v * lambda * lambda - u * ( 1 - lambda ) * ( 1 - lambda );
|
||||
node.m_data[0].location = arcpoint;
|
||||
entity->m_orderQueue.push_front( node );
|
||||
}
|
||||
|
||||
node.m_data[0].location = current - u * alpha;
|
||||
entity->m_orderQueue.push_front( node );
|
||||
next = current;
|
||||
}
|
||||
|
||||
// If we try to apply turning constraints to getting onto this path, there's a reasonable
|
||||
// risk the entity will deviate so far from the first path segment that the path becomes
|
||||
// unwalkable for it.
|
||||
entity->m_orderQueue.front().m_type = CEntityOrder::ORDER_GOTO_NOPATHING;
|
||||
}
|
||||
|
||||
void pathSparse( HEntity entity, CVector2D destination )
|
||||
{
|
||||
std::vector<CVector2D> pathnodes;
|
||||
sparsePathTree sparseEngine( CVector2D( entity->m_position.X, entity->m_position.Z ), destination, entity, getContainingObject( destination ) );
|
||||
CVector2D source( entity->m_position.X, entity->m_position.Z );
|
||||
sparsePathTree sparseEngine( source, destination, entity, getContainingObject( destination ) );
|
||||
while( sparseEngine.type & sparsePathTree::SPF_OPEN ) sparseEngine.slice();
|
||||
|
||||
assert( sparseEngine.type & sparsePathTree::SPF_SOLVED ); // Shouldn't be any impossible cases yet.
|
||||
|
||||
if( sparseEngine.type & sparsePathTree::SPF_SOLVED )
|
||||
{
|
||||
sparseEngine.pushResults( pathnodes );
|
||||
pathnodes.push_back( source );
|
||||
nodeSmooth( entity, pathnodes );
|
||||
}
|
||||
else
|
||||
|
@ -47,10 +47,18 @@ struct sparsePathTree
|
||||
bool rightImpossible;
|
||||
CVector2D right;
|
||||
bool favourLeft;
|
||||
sparsePathTree* leftPre;
|
||||
sparsePathTree* leftPost;
|
||||
sparsePathTree* rightPre;
|
||||
sparsePathTree* rightPost;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
sparsePathTree* leftPre;
|
||||
sparsePathTree* leftPost;
|
||||
sparsePathTree* rightPre;
|
||||
sparsePathTree* rightPost;
|
||||
};
|
||||
sparsePathTree* subtrees[4];
|
||||
};
|
||||
unsigned short nextSubtree;
|
||||
sparsePathTree( const CVector2D& from, const CVector2D& to, HEntity entity, CBoundingObject* destinationCollisionObject );
|
||||
~sparsePathTree();
|
||||
bool slice();
|
||||
|
Loading…
Reference in New Issue
Block a user