2004-06-03 20:38:14 +02:00
|
|
|
#include "precompiled.h"
|
|
|
|
|
2004-05-28 04:57:50 +02:00
|
|
|
#include "Collision.h"
|
|
|
|
#include "EntityManager.h"
|
|
|
|
|
2005-05-18 07:32:09 +02:00
|
|
|
#include <float.h>
|
|
|
|
|
2004-05-29 05:32:33 +02:00
|
|
|
CBoundingObject* getContainingObject( const CVector2D& point )
|
|
|
|
{
|
2004-07-20 21:30:35 +02:00
|
|
|
std::vector<HEntity>* entities = g_EntityManager.getExtant();
|
2004-05-29 05:32:33 +02:00
|
|
|
std::vector<HEntity>::iterator it;
|
|
|
|
|
|
|
|
for( it = entities->begin(); it != entities->end(); it++ )
|
|
|
|
{
|
2004-11-15 23:30:01 +01:00
|
|
|
if( !(*it)->m_bounds ) continue;
|
2004-05-29 05:32:33 +02:00
|
|
|
if( (*it)->m_bounds->contains( point ) )
|
|
|
|
{
|
|
|
|
CBoundingObject* bounds = (*it)->m_bounds;
|
|
|
|
delete( entities );
|
|
|
|
return( bounds );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete( entities );
|
|
|
|
return( NULL );
|
|
|
|
}
|
|
|
|
|
2005-05-10 09:13:25 +02:00
|
|
|
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++ )
|
|
|
|
{
|
|
|
|
if( !(*it)->m_bounds ) continue;
|
|
|
|
if( (*it)->m_bounds->contains( point ) )
|
|
|
|
{
|
|
|
|
CEntity* e = (*it);
|
|
|
|
delete( entities );
|
|
|
|
return( e );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete( entities );
|
|
|
|
return( NULL );
|
|
|
|
}
|
|
|
|
|
2004-07-23 12:56:52 +02:00
|
|
|
CBoundingObject* getCollisionObject( CBoundingObject* bounds )
|
|
|
|
{
|
|
|
|
std::vector<HEntity>* entities = g_EntityManager.getExtant();
|
|
|
|
std::vector<HEntity>::iterator it;
|
|
|
|
|
|
|
|
for( it = entities->begin(); it != entities->end(); it++ )
|
|
|
|
{
|
2004-11-15 23:30:01 +01:00
|
|
|
if( !(*it)->m_bounds ) continue;
|
2004-07-23 12:56:52 +02:00
|
|
|
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 );
|
|
|
|
}
|
|
|
|
|
2004-05-28 04:57:50 +02:00
|
|
|
HEntity getCollisionObject( CEntity* entity )
|
|
|
|
{
|
2004-11-15 23:30:01 +01:00
|
|
|
#ifndef NDEBUG
|
2005-06-28 06:06:25 +02:00
|
|
|
debug_assert( entity->m_bounds );
|
2004-11-15 23:30:01 +01:00
|
|
|
#else
|
|
|
|
if( !entity->m_bounds ) return( HEntity() );
|
|
|
|
#endif
|
2004-05-28 04:57:50 +02:00
|
|
|
|
2004-07-20 21:30:35 +02:00
|
|
|
std::vector<HEntity>* entities = g_EntityManager.getExtant();
|
2004-05-28 04:57:50 +02:00
|
|
|
std::vector<HEntity>::iterator it;
|
|
|
|
|
|
|
|
for( it = entities->begin(); it != entities->end(); it++ )
|
|
|
|
{
|
2004-11-15 23:30:01 +01:00
|
|
|
if( !(*it)->m_bounds ) continue;
|
2004-05-28 04:57:50 +02:00
|
|
|
if( (*it)->m_bounds == entity->m_bounds ) continue;
|
|
|
|
if( entity->m_bounds->intersects( (*it)->m_bounds ) )
|
|
|
|
{
|
|
|
|
HEntity collisionObject = *it;
|
|
|
|
delete( entities );
|
|
|
|
return( collisionObject );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete( entities );
|
2004-06-02 18:11:32 +02:00
|
|
|
return HEntity();
|
2004-05-28 04:57:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
HEntity getCollisionObject( CEntity* entity, float x, float y )
|
|
|
|
{
|
|
|
|
float _x = entity->m_bounds->m_pos.x;
|
|
|
|
float _y = entity->m_bounds->m_pos.y;
|
|
|
|
entity->m_bounds->setPosition( x, y );
|
|
|
|
HEntity _e = getCollisionObject( entity );
|
|
|
|
entity->m_bounds->setPosition( _x, _y );
|
|
|
|
return( _e );
|
2004-05-29 05:32:33 +02:00
|
|
|
}
|
|
|
|
|
2004-06-03 04:20:48 +02:00
|
|
|
bool getRayIntersection( const CVector2D& source, const CVector2D& forward, const CVector2D& right, float length, float maxDistance, CBoundingObject* destinationCollisionObject, rayIntersectionResults* results )
|
2004-05-29 05:32:33 +02:00
|
|
|
{
|
2005-05-10 09:13:25 +02:00
|
|
|
std::vector<CEntity*> entities;
|
|
|
|
g_EntityManager.GetExtant( entities );
|
|
|
|
|
|
|
|
std::vector<CEntity*>::iterator it;
|
2004-05-29 05:32:33 +02:00
|
|
|
|
|
|
|
float closestApproach, dist;
|
|
|
|
|
|
|
|
CVector2D delta;
|
|
|
|
|
|
|
|
results->distance = length + maxDistance;
|
|
|
|
results->boundingObject = NULL;
|
|
|
|
|
2005-05-10 09:13:25 +02:00
|
|
|
for( it = entities.begin(); it != entities.end(); it++ )
|
2004-05-29 05:32:33 +02:00
|
|
|
{
|
2004-11-15 23:30:01 +01:00
|
|
|
if( !(*it)->m_bounds ) continue;
|
2004-06-03 04:20:48 +02:00
|
|
|
if( (*it)->m_bounds == destinationCollisionObject ) continue;
|
2004-08-03 01:14:54 +02:00
|
|
|
|
2004-11-11 08:09:32 +01:00
|
|
|
// TODO MT: Replace this with something based on whether the unit is actually moving.
|
|
|
|
if( (*it)->m_orderQueue.size() ) continue;
|
|
|
|
|
2004-05-29 05:32:33 +02:00
|
|
|
CBoundingObject* obj = (*it)->m_bounds;
|
|
|
|
delta = obj->m_pos - source;
|
|
|
|
closestApproach = delta.dot( right );
|
|
|
|
dist = delta.dot( forward );
|
2004-06-03 04:20:48 +02:00
|
|
|
float collisionRadius = maxDistance + obj->m_radius;
|
2004-05-29 05:32:33 +02:00
|
|
|
|
2004-06-03 04:20:48 +02:00
|
|
|
if( ( fabs( closestApproach ) < collisionRadius ) && ( dist > collisionRadius * 0.0f ) && ( dist < length - collisionRadius * 0.0f ) )
|
2004-05-29 05:32:33 +02:00
|
|
|
{
|
|
|
|
if( dist < results->distance )
|
|
|
|
{
|
|
|
|
results->boundingObject = obj;
|
|
|
|
results->closestApproach = closestApproach;
|
|
|
|
results->distance = dist;
|
2005-05-10 09:13:25 +02:00
|
|
|
results->Entity = (*it);
|
2004-05-29 05:32:33 +02:00
|
|
|
results->position = obj->m_pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( results->boundingObject ) return( true );
|
|
|
|
return( false );
|
2004-06-02 18:11:32 +02:00
|
|
|
}
|
2005-05-10 09:13:25 +02:00
|
|
|
|
|
|
|
void GetProjectileIntersection( const CVector2D& position, const CVector2D& axis, float length, RayIntersects& results )
|
|
|
|
{
|
|
|
|
results.clear();
|
|
|
|
|
|
|
|
std::vector<CEntity*> entities;
|
|
|
|
g_EntityManager.GetExtant( entities );
|
|
|
|
|
|
|
|
float dist, closestApproach, l;
|
|
|
|
CVector2D delta;
|
|
|
|
|
|
|
|
std::vector<CEntity*>::iterator it;
|
|
|
|
for( it = entities.begin(); it != entities.end(); it++ )
|
|
|
|
{
|
|
|
|
CBoundingObject* obj = (*it)->m_bounds;
|
|
|
|
delta = obj->m_pos - position;
|
|
|
|
closestApproach = delta.betadot( axis );
|
|
|
|
if( fabs( closestApproach ) > obj->m_radius )
|
|
|
|
continue; // Safe, doesn't get close enough.
|
|
|
|
dist = delta.dot( axis );
|
|
|
|
// I just want to see if this will work before I simplify the maths
|
|
|
|
l = sqrt( obj->m_radius * obj->m_radius - closestApproach * closestApproach );
|
|
|
|
if( dist > 0 )
|
|
|
|
{
|
|
|
|
// Forward...
|
|
|
|
if( ( dist - length ) > l )
|
|
|
|
continue; // OK, won't reach it.
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Backward...
|
|
|
|
if( -dist > l )
|
|
|
|
continue; // OK, started far enough away
|
|
|
|
}
|
|
|
|
|
|
|
|
if( obj->m_type == CBoundingObject::BOUND_OABB )
|
|
|
|
{
|
|
|
|
// Run a more accurate test against the box
|
|
|
|
CBoundingBox* box = (CBoundingBox*)obj;
|
|
|
|
const float EPSILON = 0.0001f;
|
|
|
|
float first = FLT_MAX, last = -FLT_MAX;
|
|
|
|
CVector2D delta2;
|
|
|
|
|
|
|
|
// Test against those sides of the box parallel with it's u vector.
|
|
|
|
float t = box->m_u.y * axis.x - axis.y * box->m_u.x;
|
|
|
|
float abs_t = fabs( t );
|
|
|
|
if( abs_t >= EPSILON )
|
|
|
|
{
|
|
|
|
// If not parallel,
|
|
|
|
delta2 = delta - box->m_v * box->m_w;
|
|
|
|
if( fabs( axis.y * delta2.x - axis.x * delta2.y ) < box->m_d * abs_t )
|
|
|
|
{
|
|
|
|
// Possible intersection with one side
|
|
|
|
float pos = ( box->m_u.y * delta2.x - box->m_u.x * delta2.y ) / t;
|
|
|
|
if( pos < first ) first = pos;
|
|
|
|
if( pos > last ) last = pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
delta2 = delta + box->m_v * box->m_w;
|
|
|
|
if( fabs( axis.y * delta2.x - axis.x * delta2.y ) < box->m_d * abs_t )
|
|
|
|
{
|
|
|
|
// Possible intersection with one side
|
|
|
|
float pos = ( box->m_u.y * delta2.x - box->m_u.x * delta2.y ) / t;
|
|
|
|
if( pos < first ) first = pos;
|
|
|
|
if( pos > last ) last = pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Next test against those sides of the box parallel with it's v vector.
|
|
|
|
t = box->m_v.y * axis.x - axis.y * box->m_v.x;
|
|
|
|
abs_t = fabs( t );
|
|
|
|
if( abs_t >= EPSILON )
|
|
|
|
{
|
|
|
|
// If not parallel,
|
|
|
|
delta2 = delta - box->m_u * box->m_d;
|
|
|
|
if( fabs( axis.y * delta2.x - axis.x * delta2.y ) < box->m_w * abs_t )
|
|
|
|
{
|
|
|
|
// Possible intersection with one side
|
|
|
|
float pos = ( box->m_v.y * delta2.x - box->m_v.x * delta2.y ) / t;
|
|
|
|
if( pos < first ) first = pos;
|
|
|
|
if( pos > last ) last = pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
delta2 = delta + box->m_u * box->m_d;
|
|
|
|
if( fabs( axis.y * delta2.x - axis.x * delta2.y ) < box->m_w * abs_t )
|
|
|
|
{
|
|
|
|
// Possible intersection with one side
|
|
|
|
float pos = ( box->m_v.y * delta2.x - box->m_v.x * delta2.y ) / t;
|
|
|
|
if( pos < first ) first = pos;
|
|
|
|
if( pos > last ) last = pos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Then work out if we actually hit it within the given range.
|
|
|
|
if( last < 0.0f )
|
|
|
|
continue; // No, we started far enough 'after' there.
|
|
|
|
if( first > length )
|
|
|
|
continue; // No, we haven't yet moved far enough to hit it.
|
|
|
|
}
|
|
|
|
|
|
|
|
results.push_back( *it );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static RayIntersects SharedResults;
|
|
|
|
|
|
|
|
RayIntersects& GetProjectileIntersection( const CVector2D& position, const CVector2D& axis, float length )
|
|
|
|
{
|
|
|
|
GetProjectileIntersection( position, axis, length, SharedResults );
|
|
|
|
return( SharedResults );
|
|
|
|
}
|