This Trac instance is not used for development anymore!

We migrated our development workflow to git and Gitea.
To test the future redirection, replace trac by ariadne in the page URL.

Changeset 379 for ps


Ignore:
Timestamp:
06/03/04 04:20:48 (21 years ago)
Author:
markt
Message:

Pathfinding tweaks; coldet fixes.

Location:
ps/trunk/source
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • ps/trunk/source/graphics/MapReader.cpp

    r348 r379  
    161161                CVector3D position = ((CMatrix3D*)m_Objects[i].m_Transform)->GetTranslation();
    162162
    163                 g_EntityManager.create( templateObject, position, atan2( orient.X, orient.Z ) );
     163                g_EntityManager.create( templateObject, position, atan2( -orient.X, -orient.Z ) );
    164164            }
    165165            else
  • ps/trunk/source/lib/timer.cpp

    r353 r379  
    156156    const float avg_fps = fps_sum / H;
    157157    const float d_avg = avg_fps-fps;
    158     const float max_diff = fminf(5.f, 0.05f*fps);
     158    const float max_diff = __min( 5.f, 0.05f * fps ); //fminf(5.f, 0.05f*fps);
    159159
    160160    if((trend > 0 && (avg_fps > fps || d_avg < -4.f)) ||    // going up, or large drop
  • ps/trunk/source/renderer/Renderer.cpp

    r322 r379  
     1
    12///////////////////////////////////////////////////////////////////////////////
    23//
  • ps/trunk/source/simulation/BoundingObjects.cpp

    r307 r379  
    4747{
    4848    m_pos.x = x; m_pos.y = y;
    49     m_pos += m_offset;
     49    m_pos -= m_offset;
    5050}
    5151
     
    9898    setDimensions( copy->getWidth(), copy->getHeight() );
    9999    setOrientation( u );
     100}
     101
     102CBoundingBox::CBoundingBox( float x, float y, float orientation, float width, float height )
     103{
     104    m_type = BOUND_OABB;
     105    setPosition( x, y );
     106    setDimensions( width, height );
     107    setOrientation( orientation );
     108}
     109
     110CBoundingBox::CBoundingBox( float x, float y, float orientation, CBoundingBox* copy )
     111{
     112    m_type = BOUND_OABB;
     113    m_offset = copy->m_offset;
     114    setPosition( x, y );
     115    setDimensions( copy->getWidth(), copy->getHeight() );
     116    setOrientation( orientation );
    100117}
    101118
  • ps/trunk/source/simulation/BoundingObjects.h

    r357 r379  
    5757    float m_h; // Half this box's height.
    5858    float m_w; // Half this box's width.
    59     CBoundingBox( float x, float y, float orientation, float width, float height )
    60     {
    61         CBoundingBox( x, y, CVector2D( sin( orientation ), cos( orientation ) ), width, height );
    62     }
     59    CBoundingBox( float x, float y, float orientation, float width, float height );
    6360    CBoundingBox( float x, float y, const CVector2D& orientation, float width, float height );
    64     CBoundingBox( float x, float y, float orientation, CBoundingBox* copy )
    65     {
    66         CBoundingBox( x, y, CVector2D( sin( orientation ), cos( orientation ) ), copy );
    67     }
     61    CBoundingBox( float x, float y, float orientation, CBoundingBox* copy );
    6862    CBoundingBox( float x, float y, const CVector2D& orientation, CBoundingBox* copy );
    6963    void setDimensions( float width, float height );
  • ps/trunk/source/simulation/Collision.cpp

    r357 r379  
    5555}
    5656
    57 bool getRayIntersection( const CVector2D& source, const CVector2D& forward, const CVector2D& right, float length, float maxDistance, rayIntersectionResults* results )
     57bool getRayIntersection( const CVector2D& source, const CVector2D& forward, const CVector2D& right, float length, float maxDistance, CBoundingObject* destinationCollisionObject, rayIntersectionResults* results )
    5858{
    5959    std::vector<HEntity>* entities = g_EntityManager.getActive();
     
    7070    {
    7171        assert( (*it)->m_bounds );
     72        if( (*it)->m_bounds == destinationCollisionObject ) continue;
     73        // HACK:
     74        if( (*it)->m_bounds->m_type == CBoundingObject::BOUND_OABB ) continue;
    7275        if( (*it)->m_speed ) continue;
    7376        CBoundingObject* obj = (*it)->m_bounds;
     
    7578        closestApproach = delta.dot( right );
    7679        dist = delta.dot( forward );
     80        float collisionRadius = maxDistance + obj->m_radius;
    7781
    78         if( ( fabs( closestApproach ) < maxDistance + obj->m_radius ) && ( dist > -maxDistance ) && ( dist < length + maxDistance ) )
     82        if( ( fabs( closestApproach ) < collisionRadius ) && ( dist > collisionRadius * 0.0f ) && ( dist < length - collisionRadius * 0.0f ) )
    7983        {
    8084            if( dist < results->distance )
  • ps/trunk/source/simulation/Collision.h

    r357 r379  
    3131HEntity getCollisionObject( CEntity* entity, float x, float y );
    3232CBoundingObject* getContainingObject( const CVector2D& point );
    33 bool getRayIntersection( const CVector2D& source, const CVector2D& forward, const CVector2D& right, float length, float maxDistance, rayIntersectionResults* results );
     33bool getRayIntersection( const CVector2D& source, const CVector2D& forward, const CVector2D& right, float length, float maxDistance, CBoundingObject* destinationCollisionObject, rayIntersectionResults* results );
    3434
    3535#endif
  • ps/trunk/source/simulation/Entity.cpp

    r308 r379  
    1717    m_base = base;
    1818    m_actor = new CUnit(m_base->m_actorObject,m_base->m_actorObject->m_Model->Clone());
     19
     20       
     21    // HACK: Debugging
     22    // assert( m_base->m_name != CStr( "Waypoint" ) );
    1923
    2024    // Register the actor with the renderer.
     
    3438    if( m_base->m_bound_type == CBoundingObject::BOUND_CIRCLE )
    3539    {
    36         m_bounds = new CBoundingCircle( m_position.X, m_position.Z, m_base->m_bound_circle );
     40        m_bounds = new CBoundingCircle( m_position.X, m_position.Z, m_base->m_bound_circle );
    3741    }
    3842    else if( m_base->m_bound_type == CBoundingObject::BOUND_OABB )
     
    4044        m_bounds = new CBoundingBox( m_position.X, m_position.Z, m_ahead, m_base->m_bound_box );
    4145    }
    42    
     46
    4347    snapToGround();
    4448    updateActorTransforms();
     
    142146        case CEntityOrder::ORDER_GOTO_NOPATHING:
    143147        case CEntityOrder::ORDER_GOTO_COLLISION:
     148        case CEntityOrder::ORDER_GOTO_SMOOTHED:
    144149            if( processGotoNoPathing( current, timestep ) ) break;
    145150            return;
     
    201206{
    202207    // Rich! Help! ;)
    203     // We can loose this later on, I just need a way to see collision boxes temporarily
     208
     209    // HACK: As in this entire function is a...
    204210   
    205211    if( !m_orderQueue.empty() )
    206212    {
     213        std::deque<CEntityOrder>::iterator it;
     214        CBoundingObject* destinationCollisionObject;
     215        float x0, y0, x, y;
     216
     217        x = m_orderQueue.front().m_data[0].location.x;
     218        y = m_orderQueue.front().m_data[0].location.y;
     219
     220        for( it = m_orderQueue.begin(); it < m_orderQueue.end(); it++ )
     221        {
     222            if( it->m_type == CEntityOrder::ORDER_PATROL )
     223                break;
     224            x = it->m_data[0].location.x;
     225            y = it->m_data[0].location.y;
     226        }
     227        destinationCollisionObject = getContainingObject( CVector2D( x, y ) );
     228
    207229        glShadeModel( GL_FLAT );
    208230        glBegin( GL_LINE_STRIP );
    209231       
    210         std::deque<CEntityOrder>::iterator it;
    211 
    212         glVertex3f( m_position.X, m_position.Y + 0.25f /* 20.0f */, m_position.Z );
    213 
     232       
     233
     234        glVertex3f( m_position.X, m_position.Y + 0.25f, m_position.Z );
     235
     236       
     237        x = m_position.X;
     238        y = m_position.Z;
     239       
    214240        for( it = m_orderQueue.begin(); it < m_orderQueue.end(); it++ )
    215241        {
    216             float x = it->m_data[0].location.x;
    217             float y = it->m_data[0].location.y;
     242            x0 = x; y0 = y;
     243            x = it->m_data[0].location.x;
     244            y = it->m_data[0].location.y;
     245            rayIntersectionResults r;
     246            CVector2D fwd( x - x0, y - y0 );
     247            float l = fwd.length();
     248            fwd = fwd.normalize();
     249            CVector2D rgt = fwd.beta();
     250            if( getRayIntersection( CVector2D( x0, y0 ), fwd, rgt, l, m_bounds->m_radius, destinationCollisionObject, &r ) )
     251            {
     252                glEnd();
     253                glBegin( GL_LINES );
     254                glColor3f( 1.0f, 0.0f, 0.0f );
     255                glVertex3f( x0 + fwd.x * r.distance, getExactGroundLevel( x0 + fwd.x * r.distance, y0 + fwd.y * r.distance ) + 0.25f, y0 + fwd.y * r.distance );
     256                glVertex3f( r.position.x, getExactGroundLevel( r.position.x, r.position.y ) + 0.25f, r.position.y );
     257                glEnd();
     258                glBegin( GL_LINE_STRIP );
     259                glVertex3f( x0, getExactGroundLevel( x0, y0 ), y0 );
     260            }
    218261            switch( it->m_type )
    219262            {
     
    223266                glColor3f( 1.0f, 0.5f, 0.5f ); break;
    224267            case CEntityOrder::ORDER_GOTO_NOPATHING:
     268            case CEntityOrder::ORDER_GOTO_SMOOTHED:
    225269                glColor3f( 0.5f, 0.5f, 0.5f ); break;
     270            case CEntityOrder::ORDER_PATROL:
     271                glColor3f( 0.0f, 1.0f, 0.0f ); break;
    226272            default:
    227                 glColor3f( 1.0f, 1.0f, 1.0f ); break;
    228             }
    229             glVertex3f( x, getExactGroundLevel( x, y ) + 0.25f /* 20.0f */, y );
     273                continue;
     274            }
     275           
     276            glVertex3f( x, getExactGroundLevel( x, y ) + 0.25f, y );
    230277        }
    231278
     
    238285
    239286    if( getCollisionObject( this ) ) glColor3f( 0.5f, 0.5f, 1.0f );
    240     m_bounds->render( m_position.Y + 0.25f /* 20.0f */ );
     287    m_bounds->render( getExactGroundLevel( m_position.X, m_position.Z ) + 0.25f ); //m_position.Y + 0.25f );
    241288
    242289}
  • ps/trunk/source/simulation/EntityHandles.h

    r357 r379  
    4040    friend class CEntityManager;
    4141    u16 m_handle;
     42private:
    4243    void addRef();
    4344    void decRef();
  • ps/trunk/source/simulation/EntityOrders.h

    r357 r379  
    77// Usage: All orders at this point use the location component of the union.
    88//        Orders are: ORDER_GOTO_NOPATHING: Attempts to reach the given destination via a line-of-sight
    9 //                                          system. Do not create an order of this type directly; it is
     9//                    ORDER_GOTO_SMOOTED:   system. Do not create an order of these types directly; it is
    1010//                                          used to return a path of line segments from the pathfinder.
     11//                                          _SMOOTHED flags to the entity state-control that it's OK to
     12//                                          smooth the corner between segments. _NOPATHING just does
     13//                                          zero-radius turns.
    1114//                    ORDER_GOTO_COLLISION: When the coldet system is trying to get us out of a collision,
    1215//                                          it generates these intermediate waypoints. We don't really have
     
    4649    {
    4750        ORDER_GOTO_NOPATHING,
     51        ORDER_GOTO_SMOOTHED,
    4852        ORDER_GOTO_COLLISION,
    4953        ORDER_GOTO,
  • ps/trunk/source/simulation/EntityStateProcessing.cpp

    r357 r379  
    1515    float len = delta.length();
    1616
     17    // Curve smoothing.
     18    // Here there be trig.
     19
     20    if( current->m_type != CEntityOrder::ORDER_GOTO_SMOOTHED )
     21    {
     22        // We can only really attempt to smooth paths the pathfinder
     23        // has flagged for us. If the turning-radius calculations are
     24        // applied to other types of waypoint, wierdness happens.
     25        // Things like an entity trying to walk to a point inside
     26        // his turning radius (which he can't do directly, so he'll
     27        // orbit the point indefinately), or just massive deviations
     28        // making the paths we calculate useless.
     29        // It's also painful trying to watch two entities resolve their
     30        // collision when they're both bound by turning constraints.
     31        m_ahead = delta / len;
     32        m_orientation = atan2( m_ahead.x, m_ahead.y );
     33    }
     34    else
     35    {
     36        m_targetorientation = atan2( delta.x, delta.y );
     37
     38        float deltatheta = m_targetorientation - m_orientation;
     39        while( deltatheta > PI ) deltatheta -= 2 * PI;
     40        while( deltatheta < -PI ) deltatheta += 2 * PI;
     41
     42        if( fabs( deltatheta ) > 0.01f )
     43        {
     44            float maxTurningSpeed = ( m_speed / m_turningRadius ) * timestep;
     45            if( deltatheta > 0 )
     46            {
     47                m_orientation += MIN( deltatheta, maxTurningSpeed );
     48            }
     49            else
     50                m_orientation += MAX( deltatheta, -maxTurningSpeed );
     51
     52            m_ahead.x = sin( m_orientation );
     53            m_ahead.y = cos( m_orientation );
     54        }
     55        else
     56        {
     57            m_ahead = delta / len;
     58            m_orientation = atan2( m_ahead.x, m_ahead.y );
     59        }
     60    }
     61
    1762    if( len < 0.1f )
    1863    {
    19         m_orderQueue.pop_front();
     64        if( current->m_type == CEntityOrder::ORDER_GOTO_COLLISION )
     65        {
     66            // Repath.
     67            CVector2D destination;
     68            while( !m_orderQueue.empty() &&
     69                ( ( m_orderQueue.front().m_type == CEntityOrder::ORDER_GOTO_COLLISION )
     70                || ( m_orderQueue.front().m_type == CEntityOrder::ORDER_GOTO_NOPATHING )
     71                || ( m_orderQueue.front().m_type == CEntityOrder::ORDER_GOTO_SMOOTHED ) ) )
     72            {
     73                destination = m_orderQueue.front().m_data[0].location;
     74                m_orderQueue.pop_front();
     75            }
     76            g_Pathfinder.requestPath( me, destination );
     77        }
     78        else
     79            m_orderQueue.pop_front();
    2080        return( false );
    2181    }
    22 
    23     m_ahead = delta / len;
    2482
    2583    if( m_bounds->m_type == CBoundingObject::BOUND_OABB )
     
    79137                CVector2D right;
    80138                right.x = m_ahead.y; right.y = -m_ahead.x;
    81                 CVector2D avoidancePosition = collide->m_bounds->m_pos + right * ( collide->m_bounds->m_radius * 2.5f );
     139                CVector2D avoidancePosition = collide->m_bounds->m_pos + right * ( collide->m_bounds->m_radius + m_bounds->m_radius * 2.5f );
    82140                avoidance.m_data[0].location = avoidancePosition;
    83141                if( current->m_type == CEntityOrder::ORDER_GOTO_COLLISION )
     
    92150            // A circle.
    93151            // TODO: Implement this properly.
    94             // Try turning right.
     152            // Work out if our path goes to the left or to the right
     153            // of this obstacle. Go that way.
     154            // Weight a little to the right, too (helps unit-unit collisions)
     155           
    95156            CEntityOrder avoidance;
    96157            avoidance.m_type = CEntityOrder::ORDER_GOTO_COLLISION;
    97158            CVector2D right;
    98159            right.x = m_ahead.y; right.y = -m_ahead.x;
    99             CVector2D avoidancePosition = collide->m_bounds->m_pos + right * ( collide->m_bounds->m_radius * 2.5f );
     160            CVector2D avoidancePosition;
     161
     162            if( ( collide->m_bounds->m_pos - m_bounds->m_pos ).dot( right ) < 1 )
     163            {
     164                // Turn right.
     165                avoidancePosition = collide->m_bounds->m_pos + right * ( collide->m_bounds->m_radius + m_bounds->m_radius * 2.5f );
     166            }
     167            else
     168            {
     169                // Turn left.
     170                avoidancePosition = collide->m_bounds->m_pos - right * ( collide->m_bounds->m_radius + m_bounds->m_radius * 2.5f );
     171            }
     172
    100173            avoidance.m_data[0].location = avoidancePosition;
    101174            if( current->m_type == CEntityOrder::ORDER_GOTO_COLLISION )
  • ps/trunk/source/simulation/PathfindSparse.cpp

    r357 r379  
    11#include "PathfindSparse.h"
    2 
    3 #define NODESMOOTH_STEPS 4
    42
    53sparsePathTree::sparsePathTree( const CVector2D& _from, const CVector2D& _to, HEntity _entity, CBoundingObject* _destinationCollisionObject )
     
    1412    type = SPF_OPEN_UNVISITED;
    1513    leftImpossible = false; rightImpossible = false;
     14    nextSubtree = 0;
    1615}
    1716
     
    3231        CVector2D forward = to - from;
    3332        float len = forward.length();
     33
     34        assert( len != 0.0f );
     35
    3436        forward /= len;
    35         CVector2D right = CVector2D( forward.y, -forward.x );
    36 
    37         // Hit nothing or hit destination; that's OK.
    38         if( !getRayIntersection( from, forward, right, len, entity->m_bounds->m_radius * 1.1f, &r ) || ( r.boundingObject == destinationCollisionObject ) )
     37        CVector2D v_right = CVector2D( forward.y, -forward.x );
     38
     39        if( !getRayIntersection( from, forward, v_right, len, entity->m_bounds->m_radius * 1.1f, destinationCollisionObject, &r ) )
    3940        {
    4041            type = SPF_CLOSED_DIRECT;
     
    4243        }
    4344
    44         float turningRadius = ( entity->m_bounds->m_radius + r.boundingObject->m_radius ) * 1.1f;
     45        float turningRadius = ( entity->m_bounds->m_radius + r.boundingObject->m_radius ) * 1.1f;
    4546       
    4647        if( turningRadius < entity->m_turningRadius ) turningRadius = entity->m_turningRadius;
    4748
    4849        // Too close, an impossible turn
    49         if( r.distance < turningRadius ||
    50             r.distance > ( len - turningRadius ) )
    51         {
    52             type = SPF_IMPOSSIBLE;
    53             return( true );
    54         }
    55 
    56         CVector2D delta = r.position - from;
    57         float length = delta.length();
    58 
    59         float offsetDistance = ( turningRadius * length / sqrt( length * length - turningRadius * turningRadius ) );
    60        
     50        if( r.distance < turningRadius )
     51        {
     52            // Too close to make a proper turn; try dodging immediately a long way to the left or right.
     53            left = from - v_right * r.boundingObject->m_radius * 2.5f;
     54            right = from + v_right * r.boundingObject->m_radius * 2.5f;
     55        }
     56        else if( r.distance > ( len - turningRadius ) )
     57        {
     58            // Again, too close to avoid it properly. Try approaching the goal from the left or right.
     59            left = to - v_right * r.boundingObject->m_radius * 2.5f;
     60            right = to + v_right * r.boundingObject->m_radius * 2.5f;
     61        }
     62        else
     63        {
     64            // Dodge to the left or right of the obstacle.
     65            // A distance of offsetDistance is sufficient to guarantee we'll make the turn.
     66
     67            CVector2D delta = r.position - from;
     68            float length = delta.length();
     69
     70            float offsetDistance = ( turningRadius * length / sqrt( length * length - turningRadius * turningRadius ) );
     71            left = r.position - v_right * offsetDistance;
     72            right = r.position + v_right * offsetDistance;
     73        }
    6174        favourLeft = false;
    6275        if( r.closestApproach < 0 )
    6376            favourLeft = true;
    64 
     77   
    6578        // First we path to the left...
    66 
    67         left = r.position - right * offsetDistance;
     79       
    6880        leftPre = new sparsePathTree( from, left, entity, destinationCollisionObject );
    6981        leftPost = new sparsePathTree( left, to, entity, destinationCollisionObject );
     
    7183        // Then we path to the right...
    7284
    73         right = r.position + right * offsetDistance;
    7485        rightPre = new sparsePathTree( from, right, entity, destinationCollisionObject );
    7586        rightPost = new sparsePathTree( right, to, entity, destinationCollisionObject );
     
    8899    {
    89100        bool done = false;
    90         if( !leftImpossible )
    91         {
    92             if( !done && ( leftPre->type & SPF_OPEN ) )
    93                 done |= leftPre->slice();
    94             if( !done && ( leftPost->type & SPF_OPEN ) )
    95                 done |= leftPost->slice();
    96             if( ( leftPre->type == SPF_IMPOSSIBLE ) || ( leftPost->type == SPF_IMPOSSIBLE ) )
    97                 leftImpossible = true;
    98         }
    99         if( !rightImpossible && !done )
    100         {
    101             if( !done && ( rightPre->type & SPF_OPEN ) )
    102                 done |= rightPre->slice();
    103             if( !done && ( rightPost->type & SPF_OPEN ) )
    104                 done |= rightPost->slice();
    105             if( ( rightPre->type == SPF_IMPOSSIBLE ) || ( rightPost->type == SPF_IMPOSSIBLE ) )
    106                 rightImpossible = true;
    107         }
     101        while( !done )
     102        {
     103            if( subtrees[nextSubtree]->type & SPF_OPEN )
     104                if( subtrees[nextSubtree]->slice() )
     105                    done = true;
     106            nextSubtree++;
     107            nextSubtree %= 4;
     108        }
     109        if( ( leftPre->type == SPF_IMPOSSIBLE ) || ( leftPost->type == SPF_IMPOSSIBLE ) )
     110            leftImpossible = true;
     111        if( ( rightPre->type == SPF_IMPOSSIBLE ) || ( rightPost->type == SPF_IMPOSSIBLE ) )
     112            rightImpossible = true;
    108113        if( leftImpossible && rightImpossible )
    109114        {
     
    150155void nodeSmooth( HEntity entity, std::vector<CVector2D>& nodelist )
    151156{
    152     // All your CPU are belong to us.
    153     // But Jan wanted it ;)
    154 
    155157    std::vector<CVector2D>::iterator it;
    156158    CVector2D next = nodelist.front();
    157159
    158160    CEntityOrder node;
    159     node.m_type = CEntityOrder::ORDER_GOTO_NOPATHING;
     161    node.m_type = CEntityOrder::ORDER_GOTO_SMOOTHED;
    160162    node.m_data[0].location = next;
    161163
     
    174176        CVector2D vbar = v.beta();
    175177        float alpha = entity->m_turningRadius * ( ubar - vbar ).length() / ( u + v ).length();
    176         u *= alpha;
    177         v *= alpha;
    178 
    179         for( int t = NODESMOOTH_STEPS; t >= 0; t-- )
    180         {
    181             float lambda = t / (float)NODESMOOTH_STEPS;
    182             CVector2D arcpoint = current + v * lambda * lambda - u * ( 1 - lambda ) * ( 1 - lambda );
    183             node.m_data[0].location = arcpoint;
    184             entity->m_orderQueue.push_front( node );
    185         }
    186        
     178        node.m_data[0].location = current - u * alpha;
     179        entity->m_orderQueue.push_front( node );
    187180        next = current;
    188181    }
     182   
     183    // If we try to apply turning constraints to getting onto this path, there's a reasonable
     184    // risk the entity will deviate so far from the first path segment that the path becomes
     185    // unwalkable for it.
     186    entity->m_orderQueue.front().m_type = CEntityOrder::ORDER_GOTO_NOPATHING;
    189187}
    190188
     
    192190{
    193191    std::vector<CVector2D> pathnodes;
    194     sparsePathTree sparseEngine( CVector2D( entity->m_position.X, entity->m_position.Z ), destination, entity, getContainingObject( destination ) );
     192    CVector2D source( entity->m_position.X, entity->m_position.Z );
     193    sparsePathTree sparseEngine( source, destination, entity, getContainingObject( destination ) );
    195194    while( sparseEngine.type & sparsePathTree::SPF_OPEN ) sparseEngine.slice();
    196195
     196    assert( sparseEngine.type & sparsePathTree::SPF_SOLVED ); // Shouldn't be any impossible cases yet.
     197
    197198    if( sparseEngine.type & sparsePathTree::SPF_SOLVED )
    198199    {
    199200        sparseEngine.pushResults( pathnodes );
     201        pathnodes.push_back( source );
    200202        nodeSmooth( entity, pathnodes );
    201203    }
  • ps/trunk/source/simulation/PathfindSparse.h

    r357 r379  
    4848    CVector2D right;
    4949    bool favourLeft;
    50     sparsePathTree* leftPre;
    51     sparsePathTree* leftPost;
    52     sparsePathTree* rightPre;
    53     sparsePathTree* rightPost;
     50    union
     51    {
     52        struct
     53        {
     54            sparsePathTree* leftPre;
     55            sparsePathTree* leftPost;
     56            sparsePathTree* rightPre;
     57            sparsePathTree* rightPost;
     58        };
     59        sparsePathTree* subtrees[4];
     60    };
     61    unsigned short nextSubtree;
    5462    sparsePathTree( const CVector2D& from, const CVector2D& to, HEntity entity, CBoundingObject* destinationCollisionObject );
    5563    ~sparsePathTree();
Note: See TracChangeset for help on using the changeset viewer.