Early form of collision detection/avoidance added.
This was SVN commit r272.
This commit is contained in:
parent
e326147f9e
commit
089472eb24
@ -269,8 +269,16 @@ static void Render()
|
||||
RenderTerrain();
|
||||
RenderModels();
|
||||
g_Renderer.FlushFrame();
|
||||
/*
|
||||
glPushAttrib( GL_ENABLE_BIT );
|
||||
glDisable( GL_LIGHTING );
|
||||
glDisable( GL_TEXTURE_2D );
|
||||
glColor3f( 1.0f, 0.0f, 1.0f );
|
||||
|
||||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
// g_EntityManager.renderAll(); // <-- collision outlines...
|
||||
|
||||
glPopAttrib();
|
||||
*/
|
||||
|
||||
// overlay mode
|
||||
glPushAttrib(GL_ENABLE_BIT);
|
||||
@ -310,6 +318,8 @@ static void Render()
|
||||
g_GUI.Draw();
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// restore
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
@ -471,7 +481,7 @@ int main(int argc, char* argv[])
|
||||
#endif
|
||||
|
||||
|
||||
font = font_load("fonts/verdana.fnt");
|
||||
font = font_load("fonts/verdana18.fnt");
|
||||
|
||||
// set renderer options from command line options - NOVBO must be set before opening the renderer
|
||||
g_Renderer.SetOption(CRenderer::OPT_NOVBO,g_NoGLVBO);
|
||||
|
@ -17,8 +17,6 @@ XERCES_CPP_NAMESPACE_USE
|
||||
|
||||
bool CBaseEntity::loadXML( CStr filename )
|
||||
{
|
||||
// I can only assume Rich knows what this does ;)
|
||||
|
||||
bool parseOK = false;
|
||||
|
||||
// Initialize XML library
|
||||
@ -71,12 +69,52 @@ bool CBaseEntity::loadXML( CStr filename )
|
||||
DOMNode *value_node= child_element->getChildNodes()->item(0);
|
||||
CStr element_value=value_node ? XMLString::transcode(value_node->getNodeValue()) : "";
|
||||
|
||||
if (element_name==CStr("Name")) {
|
||||
if( element_name == CStr( "Name" ) )
|
||||
{
|
||||
m_name = element_value;
|
||||
} else if (element_name==CStr("Actor")) {
|
||||
}
|
||||
else if( element_name == CStr( "Actor" ) )
|
||||
{
|
||||
m_actorObject = g_ObjMan.FindObject( element_value );
|
||||
} else if (element_name==CStr("Speed")) {
|
||||
}
|
||||
else if( element_name == CStr( "Speed" ) )
|
||||
{
|
||||
m_speed = element_value.ToFloat();
|
||||
}
|
||||
else if( element_name == CStr( "Size" ) )
|
||||
{
|
||||
if( !m_bound_circle )
|
||||
m_bound_circle = new CBoundingCircle();
|
||||
CStr radius = XMLString::transcode( child_element->getAttribute( XMLString::transcode( "Radius" ) ) );
|
||||
m_bound_circle->setRadius( radius.ToFloat() );
|
||||
m_bound_type = CBoundingObject::BOUND_CIRCLE;
|
||||
}
|
||||
else if( element_name == CStr( "Footprint" ) )
|
||||
{
|
||||
if( !m_bound_box )
|
||||
m_bound_box = new CBoundingBox();
|
||||
CStr width = XMLString::transcode( child_element->getAttribute( XMLString::transcode( "Width" ) ) );
|
||||
CStr height = XMLString::transcode( child_element->getAttribute( XMLString::transcode( "Height" ) ) );
|
||||
|
||||
m_bound_box->setDimensions( width.ToFloat(), height.ToFloat() );
|
||||
m_bound_type = CBoundingObject::BOUND_OABB;
|
||||
}
|
||||
else if( element_name == CStr( "BoundsOffset" ) )
|
||||
{
|
||||
CStr x = XMLString::transcode( child_element->getAttribute( XMLString::transcode( "x" ) ) );
|
||||
CStr y = XMLString::transcode( child_element->getAttribute( XMLString::transcode( "y" ) ) );
|
||||
|
||||
if( !m_bound_circle )
|
||||
m_bound_circle = new CBoundingCircle();
|
||||
if( !m_bound_box )
|
||||
m_bound_box = new CBoundingBox();
|
||||
|
||||
m_bound_circle->m_offset.x = x.ToFloat();
|
||||
m_bound_circle->m_offset.y = y.ToFloat();
|
||||
m_bound_box->m_offset.x = x.ToFloat();
|
||||
m_bound_box->m_offset.y = y.ToFloat();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,10 +22,12 @@
|
||||
#include "ObjectEntry.h"
|
||||
|
||||
#include "EntityProperties.h"
|
||||
#include "BoundingObjects.h"
|
||||
|
||||
class CBaseEntity
|
||||
{
|
||||
public:
|
||||
CBaseEntity() { m_bound_circle = NULL; m_bound_box = NULL; }
|
||||
// Load from XML
|
||||
bool loadXML( CStr filename );
|
||||
|
||||
@ -34,6 +36,10 @@ public:
|
||||
CObjectEntry* m_actorObject;
|
||||
|
||||
CStr m_name;
|
||||
CBoundingCircle* m_bound_circle;
|
||||
CBoundingBox* m_bound_box;
|
||||
CBoundingObject::EBoundingType m_bound_type;
|
||||
|
||||
float m_speed;
|
||||
|
||||
// Extended properties table
|
||||
|
@ -1,12 +1,17 @@
|
||||
#include "BoundingObjects.h"
|
||||
#include "ogl.h"
|
||||
#include "terrain/MathUtil.h"
|
||||
#include "stdio.h"
|
||||
#include "assert.h"
|
||||
|
||||
bool CBoundingObject::intersects( CBoundingObject* obj )
|
||||
{
|
||||
CVector2D delta = pos - obj->pos;
|
||||
if( !delta.within( trivialRejectionRadius + obj->trivialRejectionRadius ) )
|
||||
CVector2D delta = m_pos - obj->m_pos;
|
||||
|
||||
if( !delta.within( m_radius + obj->m_radius ) )
|
||||
return( false );
|
||||
|
||||
if( obj->type > type )
|
||||
if( obj->m_type > m_type ) // More complex types get the burden of processing.
|
||||
{
|
||||
return( obj->_intersects( this, &delta ) );
|
||||
}
|
||||
@ -14,68 +19,112 @@ bool CBoundingObject::intersects( CBoundingObject* obj )
|
||||
return( _intersects( obj, &delta ) );
|
||||
}
|
||||
|
||||
void CBoundingCircle::setPosition( float _x, float _y )
|
||||
CBoundingCircle::CBoundingCircle( float x, float y, float radius )
|
||||
{
|
||||
pos.x = _x; pos.y = _y;
|
||||
m_type = BOUND_CIRCLE;
|
||||
setPosition( x, y );
|
||||
setRadius( radius );
|
||||
}
|
||||
|
||||
void CBoundingCircle::setRadius( float _radius )
|
||||
CBoundingCircle::CBoundingCircle( float x, float y, CBoundingCircle* copy )
|
||||
{
|
||||
r = _radius;
|
||||
trivialRejectionRadius = _radius * _radius;
|
||||
m_type = BOUND_CIRCLE;
|
||||
m_offset = copy->m_offset;
|
||||
setPosition( x, y );
|
||||
setRadius( copy->m_radius );
|
||||
}
|
||||
|
||||
void CBoundingObject::setPosition( float x, float y )
|
||||
{
|
||||
m_pos.x = x; m_pos.y = y;
|
||||
m_pos += m_offset;
|
||||
}
|
||||
|
||||
void CBoundingCircle::setRadius( float radius )
|
||||
{
|
||||
m_radius = radius;
|
||||
}
|
||||
|
||||
bool CBoundingCircle::_intersects( CBoundingObject* obj, CVector2D* delta )
|
||||
{
|
||||
// Easy enough. Trivial rejection is sufficient.
|
||||
assert( obj->m_type == BOUND_CIRCLE );
|
||||
// Easy enough. The only time this gets called is a circle-circle collision,
|
||||
// but we know the circles collide (they passed the trivial rejection step)
|
||||
return( true );
|
||||
}
|
||||
|
||||
CBoundingBox::CBoundingBox( float _x, float _y, float _orientation, float _width, float _height )
|
||||
void CBoundingCircle::render( float height )
|
||||
{
|
||||
setPosition( _x, _y );
|
||||
setDimensions( _width, _height );
|
||||
setOrientation( _orientation );
|
||||
glBegin( GL_LINE_LOOP );
|
||||
|
||||
for( int i = 0; i < 10; i++ )
|
||||
{
|
||||
float ang = i * 2 * PI / 10.0f;
|
||||
float x = m_pos.x + m_radius * sin( ang );
|
||||
float y = m_pos.y + m_radius * cos( ang );
|
||||
glVertex3f( x, height, y );
|
||||
}
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void CBoundingBox::setPosition( float _x, float _y )
|
||||
CBoundingBox::CBoundingBox( float x, float y, const CVector2D& u, float width, float height )
|
||||
{
|
||||
pos.x = _x; pos.y = _y;
|
||||
m_type = BOUND_OABB;
|
||||
setPosition( x, y );
|
||||
setDimensions( width, height );
|
||||
setOrientation( u );
|
||||
}
|
||||
|
||||
void CBoundingBox::setDimensions( float _width, float _height )
|
||||
CBoundingBox::CBoundingBox( float x, float y, const CVector2D& u, CBoundingBox* copy )
|
||||
{
|
||||
w = _width / 2.0f;
|
||||
h = _height / 2.0f;
|
||||
trivialRejectionRadius = ( w * w ) + ( h * h );
|
||||
m_type = BOUND_OABB;
|
||||
m_offset = copy->m_offset;
|
||||
setPosition( x, y );
|
||||
setDimensions( copy->getWidth(), copy->getHeight() );
|
||||
setOrientation( u );
|
||||
}
|
||||
|
||||
void CBoundingBox::setOrientation( float _orientation )
|
||||
void CBoundingBox::setDimensions( float width, float height )
|
||||
{
|
||||
u.x = sin( _orientation );
|
||||
u.y = cos( _orientation );
|
||||
v.x = u.y;
|
||||
v.y = -u.x;
|
||||
m_w = width / 2.0f;
|
||||
m_h = height / 2.0f;
|
||||
m_radius = sqrt( ( m_w * m_w ) + ( m_h * m_h ) );
|
||||
}
|
||||
|
||||
void CBoundingBox::setOrientation( float orientation )
|
||||
{
|
||||
m_u.x = sin( orientation );
|
||||
m_u.y = cos( orientation );
|
||||
m_v.x = m_u.y;
|
||||
m_v.y = -m_u.x;
|
||||
}
|
||||
|
||||
void CBoundingBox::setOrientation( const CVector2D& u )
|
||||
{
|
||||
m_u = u;
|
||||
m_v.x = m_u.y;
|
||||
m_v.y = -m_u.x;
|
||||
}
|
||||
|
||||
bool CBoundingBox::_intersects( CBoundingObject* obj, CVector2D* delta )
|
||||
{
|
||||
if( obj->type == BOUND_CIRCLE )
|
||||
if( obj->m_type == BOUND_CIRCLE )
|
||||
{
|
||||
// Imperfect but quick...
|
||||
|
||||
CBoundingCircle* c = (CBoundingCircle*)obj;
|
||||
float deltah = fabs( delta->dot( u ) );
|
||||
if( deltah > ( h + c->r ) ) return( false );
|
||||
float deltaw = fabs( delta->dot( v ) );
|
||||
if( deltaw > ( w + c->r ) ) return( false );
|
||||
float deltah = fabs( delta->dot( m_u ) );
|
||||
if( deltah > ( m_h + c->m_radius ) ) return( false );
|
||||
float deltaw = fabs( delta->dot( m_v ) );
|
||||
if( deltaw > ( m_w + c->m_radius ) ) return( false );
|
||||
return( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Another OABB:
|
||||
|
||||
// Seperable axis theorem. (Optimizations: Algorithmic done, really low-level stuff not.)
|
||||
// Seperable axis theorem. (Optimizations: Algorithmic done, low-level stuff not.)
|
||||
// Debugging this can often be quite entertaining.
|
||||
|
||||
CBoundingBox* b = (CBoundingBox*)obj;
|
||||
@ -95,67 +144,86 @@ bool CBoundingBox::_intersects( CBoundingObject* obj, CVector2D* delta )
|
||||
// Note that a trivial-rejection test has already taken place by this point.
|
||||
|
||||
float uv, vu, uu, vv, prj1, prj2, dm;
|
||||
uv = u.dot( b->v );
|
||||
vu = v.dot( b->u );
|
||||
uu = u.dot( b->u );
|
||||
vv = v.dot( b->v );
|
||||
uv = m_u.dot( b->m_v );
|
||||
vu = m_v.dot( b->m_u );
|
||||
uu = m_u.dot( b->m_u );
|
||||
vv = m_v.dot( b->m_v );
|
||||
|
||||
// Project box 2 onto v-axis of box 1
|
||||
|
||||
prj1 = fabs( vu * b->h + vv * b->w );
|
||||
prj2 = fabs( vu * b->h - vv * b->h );
|
||||
dm = delta->dot( v );
|
||||
prj1 = fabs( vu * b->m_h + vv * b->m_w );
|
||||
prj2 = fabs( vu * b->m_h - vv * b->m_h );
|
||||
dm = delta->dot( m_v );
|
||||
|
||||
if( prj1 > prj2 )
|
||||
{
|
||||
if( ( dm - prj1 ) > w ) return( false );
|
||||
if( ( dm - prj1 ) > m_w ) return( false );
|
||||
}
|
||||
else
|
||||
if( ( dm - prj2 ) > w ) return( false );
|
||||
if( ( dm - prj2 ) > m_w ) return( false );
|
||||
|
||||
// Project box 2 onto u-axis of box 1
|
||||
|
||||
prj1 = fabs( uu * b->h + uv * b->w );
|
||||
prj2 = fabs( uu * b->h - uv * b->w );
|
||||
dm = delta->dot( u );
|
||||
prj1 = fabs( uu * b->m_h + uv * b->m_w );
|
||||
prj2 = fabs( uu * b->m_h - uv * b->m_w );
|
||||
dm = delta->dot( m_u );
|
||||
|
||||
if( prj1 > prj2 )
|
||||
{
|
||||
if( ( dm - prj1 ) > h ) return( false );
|
||||
if( ( dm - prj1 ) > m_h ) return( false );
|
||||
}
|
||||
else
|
||||
if( ( dm - prj2 ) > h ) return( false );
|
||||
if( ( dm - prj2 ) > m_h ) return( false );
|
||||
|
||||
// Project box 1 onto v-axis of box 2
|
||||
|
||||
prj1 = fabs( uv * h + vv * w );
|
||||
prj2 = fabs( uv * h - vv * w );
|
||||
prj1 = fabs( uv * m_h + vv * m_w );
|
||||
prj2 = fabs( uv * m_h - vv * m_w );
|
||||
|
||||
if( prj1 > prj2 )
|
||||
{
|
||||
if( ( dm - prj1 ) > b->w ) return( false );
|
||||
if( ( dm - prj1 ) > b->m_w ) return( false );
|
||||
}
|
||||
else
|
||||
if( ( dm - prj2 ) > b->w ) return( false );
|
||||
if( ( dm - prj2 ) > b->m_w ) return( false );
|
||||
|
||||
// Project box 1 onto u-axis of box 2
|
||||
|
||||
prj1 = fabs( uu * h + vu * w );
|
||||
prj2 = fabs( uu * h - vu * w );
|
||||
prj1 = fabs( uu * m_h + vu * m_w );
|
||||
prj2 = fabs( uu * m_h - vu * m_w );
|
||||
|
||||
if( prj1 > prj2 )
|
||||
{
|
||||
if( ( dm - prj1 ) > b->h ) return( false );
|
||||
if( ( dm - prj1 ) > b->m_h ) return( false );
|
||||
}
|
||||
else
|
||||
if( ( dm - prj2 ) > b->h ) return( false );
|
||||
if( ( dm - prj2 ) > b->m_h ) return( false );
|
||||
|
||||
// And a partridge in a pear tree...
|
||||
|
||||
return( true );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void CBoundingBox::render( float height )
|
||||
{
|
||||
glBegin( GL_LINE_LOOP );
|
||||
|
||||
CVector2D p;
|
||||
|
||||
p = m_pos + m_u * m_h + m_v * m_w;
|
||||
glVertex3f( p.x, height, p.y );
|
||||
|
||||
p = m_pos + m_u * m_h - m_v * m_w;
|
||||
glVertex3f( p.x, height, p.y );
|
||||
|
||||
p = m_pos - m_u * m_h - m_v * m_w;
|
||||
glVertex3f( p.x, height, p.y );
|
||||
|
||||
p = m_pos - m_u * m_h + m_v * m_w;
|
||||
glVertex3f( p.x, height, p.y );
|
||||
|
||||
glEnd();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -10,35 +10,7 @@
|
||||
#ifndef BOUNDING_OBJECTS_INCLUDED
|
||||
#define BOUNDING_OBJECTS_INCLUDED
|
||||
|
||||
#include "Prometheus.h"
|
||||
|
||||
class CVector2D
|
||||
{
|
||||
public:
|
||||
float x;
|
||||
float y;
|
||||
CVector2D() {}
|
||||
CVector2D( float _x, float _y )
|
||||
{
|
||||
x = _x; y = _y;
|
||||
}
|
||||
static inline float dot( CVector2D& u, CVector2D& v )
|
||||
{
|
||||
return( u.x * v.x + u.y * v.y );
|
||||
}
|
||||
inline float dot( CVector2D& u )
|
||||
{
|
||||
return( dot( *this, u ) );
|
||||
}
|
||||
inline CVector2D operator-( CVector2D& u )
|
||||
{
|
||||
return( CVector2D( x - u.x, y - u.y ) );
|
||||
}
|
||||
inline bool within( float dist )
|
||||
{
|
||||
return( ( x * x + y * y ) <= ( dist * dist ) );
|
||||
}
|
||||
};
|
||||
#include "Vector2D.h"
|
||||
|
||||
class CBoundingBox;
|
||||
class CBoundingCircle;
|
||||
@ -46,42 +18,58 @@ class CBoundingCircle;
|
||||
class CBoundingObject
|
||||
{
|
||||
public:
|
||||
CBoundingObject() {}
|
||||
enum CBoundingType
|
||||
CBoundingObject() { m_offset.x = 0; m_offset.y = 0; }
|
||||
enum EBoundingType
|
||||
{
|
||||
BOUND_CIRCLE,
|
||||
BOUND_OABB
|
||||
};
|
||||
CBoundingType type;
|
||||
CVector2D pos;
|
||||
float trivialRejectionRadius;
|
||||
EBoundingType m_type;
|
||||
CVector2D m_pos;
|
||||
CVector2D m_offset;
|
||||
float m_radius;
|
||||
void setPosition( float x, float y );
|
||||
bool intersects( CBoundingObject* obj );
|
||||
virtual bool _intersects( CBoundingObject* obj, CVector2D* delta ) = 0;
|
||||
|
||||
virtual void render( float height ) = 0; // Temporary
|
||||
};
|
||||
|
||||
class CBoundingCircle : public CBoundingObject
|
||||
{
|
||||
public:
|
||||
float r;
|
||||
CBoundingCircle( float _x, float _y, float _radius );
|
||||
void setPosition( float _x, float _y );
|
||||
void setRadius( float _radius );
|
||||
CBoundingCircle() { m_type = BOUND_OABB; }
|
||||
CBoundingCircle( float x, float y, float radius );
|
||||
CBoundingCircle( float x, float y, CBoundingCircle* copy );
|
||||
void setRadius( float radius );
|
||||
bool _intersects( CBoundingObject* obj, CVector2D* delta );
|
||||
void render( float height ); // Temporary
|
||||
};
|
||||
|
||||
class CBoundingBox : public CBoundingObject
|
||||
{
|
||||
public:
|
||||
CVector2D u; // Unit vector along the direction of this box's height.
|
||||
CVector2D v; // Unit vector along the direction of this box's width.
|
||||
float h; // Half this box's height.
|
||||
float w; // Half this box's width.
|
||||
CBoundingBox( float _x, float _y, float _orientation, float _width, float _height );
|
||||
void setPosition( float _x, float _y );
|
||||
void setDimensions( float _width, float _height );
|
||||
void setOrientation( float _orientation );
|
||||
CBoundingBox() { m_type = BOUND_OABB; }
|
||||
CVector2D m_u; // Unit vector along the direction of this box's height.
|
||||
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, 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, const CVector2D& orientation, CBoundingBox* copy );
|
||||
void setDimensions( float width, float height );
|
||||
void setOrientation( float orientation );
|
||||
void setOrientation( const CVector2D& orientation );
|
||||
float getWidth() const { return( 2.0f * m_w ); };
|
||||
float getHeight() const { return( 2.0f * m_h ); };
|
||||
bool _intersects( CBoundingObject* obj, CVector2D* delta );
|
||||
void render( float height ); // Temporary
|
||||
};
|
||||
|
||||
#endif
|
@ -1,11 +1,12 @@
|
||||
// Last modified: May 15 2004, Mark Thompson (mark@wildfiregames.com)
|
||||
|
||||
#include "Entity.h"
|
||||
#include "Model.h"
|
||||
#include "Terrain.h"
|
||||
#include "EntityManager.h"
|
||||
#include "BaseEntityCollection.h"
|
||||
|
||||
#include "Renderer.h"
|
||||
#include "Model.h"
|
||||
#include "Terrain.h"
|
||||
|
||||
CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation )
|
||||
{
|
||||
@ -27,6 +28,18 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation )
|
||||
m_position = position;
|
||||
m_orientation = orientation;
|
||||
|
||||
m_ahead.x = sin( orientation );
|
||||
m_ahead.y = cos( 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 );
|
||||
}
|
||||
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();
|
||||
|
||||
@ -44,11 +57,22 @@ bool isWaypoint( CEntity* e )
|
||||
void CEntity::updateActorTransforms()
|
||||
{
|
||||
CMatrix3D m;
|
||||
|
||||
m._11 = -m_ahead.y; m._12 = 0.0f; m._13 = -m_ahead.x; m._14 = m_position.X;
|
||||
m._21 = 0.0f; m._22 = 1.0f; m._23 = 0.0f; m._24 = m_position.Y;
|
||||
m._31 = m_ahead.x; m._32 = 0.0f; m._33 = -m_ahead.y; m._34 = m_position.Z;
|
||||
m._41 = 0.0f; m._42 = 0.0f; m._43 = 0.0f; m._44 = 1.0f;
|
||||
|
||||
/* Equivalent to:
|
||||
|
||||
m.SetYRotation( m_orientation );
|
||||
|
||||
m.Translate( m_position );
|
||||
|
||||
But the matrix multiplication seemed such a waste when we already have a forward vector
|
||||
|
||||
*/
|
||||
|
||||
m_actor->m_Model->SetTransform( m );
|
||||
}
|
||||
|
||||
@ -108,34 +132,97 @@ void CEntity::update( float timestep )
|
||||
switch( current->m_type )
|
||||
{
|
||||
case CEntityOrder::ORDER_GOTO_NOPATHING:
|
||||
case CEntityOrder::ORDER_GOTO_COLLISION:
|
||||
{
|
||||
float deltax = (float)current->m_data[0].location.x - m_position.X;
|
||||
float deltay = (float)current->m_data[0].location.y - m_position.Z;
|
||||
CVector2D delta;
|
||||
delta.x = (float)current->m_data[0].location.x - m_position.X;
|
||||
delta.y = (float)current->m_data[0].location.y - m_position.Z;
|
||||
|
||||
m_targetorientation = atan2( -deltax, -deltay );
|
||||
float deltatheta = m_targetorientation - m_orientation;
|
||||
if( deltatheta > PI )
|
||||
deltatheta -= 2 * PI;
|
||||
if( deltatheta < -PI )
|
||||
deltatheta += 2 * PI;
|
||||
m_ahead = delta.normalize();
|
||||
|
||||
/*
|
||||
if( deltatheta > 1.0f * timestep )
|
||||
deltatheta = 1.0f * timestep;
|
||||
if( deltatheta < -1.0f * timestep )
|
||||
deltatheta = -1.0f * timestep;
|
||||
*/
|
||||
if( m_bounds->m_type == CBoundingObject::BOUND_OABB )
|
||||
((CBoundingBox*)m_bounds)->setOrientation( m_ahead );
|
||||
|
||||
m_orientation += deltatheta;
|
||||
float len = delta.length();
|
||||
|
||||
float len = sqrt( deltax * deltax + deltay * deltay );
|
||||
float scale = timestep * m_speed;
|
||||
|
||||
if( scale > len )
|
||||
scale = len;
|
||||
|
||||
deltax = -sinf( m_orientation ) * scale; deltay = -cosf( m_orientation ) * scale;
|
||||
m_position.X += deltax;
|
||||
m_position.Z += deltay;
|
||||
delta = m_ahead * scale;
|
||||
|
||||
m_position.X += delta.x;
|
||||
m_position.Z += delta.y;
|
||||
m_bounds->setPosition( m_position.X, m_position.Z );
|
||||
|
||||
HEntity collide = getCollisionObject();
|
||||
|
||||
if( collide )
|
||||
{
|
||||
// Hit something. Take a step back.
|
||||
m_position.X -= delta.x;
|
||||
m_position.Z -= delta.y;
|
||||
|
||||
m_bounds->setPosition( m_position.X, m_position.Z );
|
||||
|
||||
// Are we still hitting it?
|
||||
if( collide->m_bounds->intersects( m_bounds ) )
|
||||
{
|
||||
// Oh dear. Most likely explanation is that this unit was created
|
||||
// within the bounding area of another entity.
|
||||
// Try a little boost of speed, to help resolve the situation more quickly.
|
||||
m_position.X += delta.x * 2.0f;
|
||||
m_position.Z += delta.y * 2.0f;
|
||||
m_bounds->setPosition( m_position.X, m_position.Z );
|
||||
return;
|
||||
}
|
||||
|
||||
if( collide->m_bounds->m_type == CBoundingObject::BOUND_OABB )
|
||||
{
|
||||
// And it's square.
|
||||
// TODO: Implement this case properly.
|
||||
|
||||
// HACK: See if this thing we've hit is likely to be our destination. If so, just skip to our next waypoint.
|
||||
// Otherwise, turn right (as with circle collisions)
|
||||
|
||||
if( len < collide->m_bounds->m_radius * 2.0f )
|
||||
{
|
||||
m_orderQueue.pop_front();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
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 );
|
||||
avoidance.m_data[0].location = avoidancePosition;
|
||||
if( current->m_type == CEntityOrder::ORDER_GOTO_COLLISION )
|
||||
m_orderQueue.pop_front();
|
||||
m_orderQueue.push_front( avoidance );
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// A circle.
|
||||
// TODO: Implement this properly.
|
||||
// Try turning right.
|
||||
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 );
|
||||
avoidance.m_data[0].location = avoidancePosition;
|
||||
if( current->m_type == CEntityOrder::ORDER_GOTO_COLLISION )
|
||||
m_orderQueue.pop_front();
|
||||
m_orderQueue.push_front( avoidance );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
snapToGround();
|
||||
updateActorTransforms();
|
||||
@ -199,6 +286,7 @@ void CEntity::dispatch( CMessage* msg )
|
||||
pushOrder( patrol );
|
||||
waypoints->erase( it );
|
||||
}
|
||||
delete( waypoints );
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -209,34 +297,49 @@ void CEntity::pushOrder( CEntityOrder& order )
|
||||
m_orderQueue.push_back( order );
|
||||
}
|
||||
|
||||
void PASAPScenario()
|
||||
void CEntity::render()
|
||||
{
|
||||
// Entity demo. I don't know where this information is going to come from for pre-PASAP.
|
||||
// So, it's hardcoded here. *shrug*
|
||||
// Rich! Help! ;)
|
||||
// We can loose this later on, I just need a way to see collision boxes temporarily
|
||||
|
||||
/*
|
||||
float waypoints[4][2] = { { 12.0f, 64.0f },
|
||||
{ 28.0f, 64.0f },
|
||||
{ 56.0f, 52.0f },
|
||||
{ 24.0f, 28.0f } };
|
||||
*/
|
||||
glColor3f( 1.0f, 1.0f, 1.0f );
|
||||
if( getCollisionObject() ) glColor3f( 0.5f, 0.5f, 1.0f );
|
||||
m_bounds->render( m_position.Y + 0.25f );
|
||||
}
|
||||
|
||||
/*
|
||||
HEntity CEntity::getCollisionObject()
|
||||
{
|
||||
if( !m_bounds ) return( HEntity() );
|
||||
std::vector<HEntity>* entities = g_EntityManager.getActive();
|
||||
std::vector<HEntity>::iterator it;
|
||||
|
||||
for( int i = 0; i < 4; i++ )
|
||||
for( it = entities->begin(); it != entities->end(); it++ )
|
||||
{
|
||||
HEntity bob = g_EntityManager.create( "Prometheus Dude", CVector3D( waypoints[i][0], 0.0f, waypoints[i][1] ), 0.0f );
|
||||
|
||||
for( int t = 0; t < 4; t++ )
|
||||
{
|
||||
CEntityOrder march_of_bob;
|
||||
march_of_bob.m_type = CEntityOrder::ORDER_PATROL ;
|
||||
march_of_bob.m_data[0].location.x = waypoints[(i+t+1)%4][0];
|
||||
march_of_bob.m_data[0].location.y = waypoints[(i+t+1)%4][1];
|
||||
|
||||
bob->pushOrder( march_of_bob );
|
||||
}
|
||||
if( *it == me ) continue;
|
||||
if( (*it)->m_bounds )
|
||||
if( m_bounds->intersects( (*it)->m_bounds ) )
|
||||
{
|
||||
HEntity collisionObject = *it;
|
||||
delete( entities );
|
||||
return( collisionObject );
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
delete( entities );
|
||||
return( HEntity() );
|
||||
}
|
||||
|
||||
HEntity CEntity::getCollisionObject( float x, float y )
|
||||
{
|
||||
float _x = m_bounds->m_pos.x;
|
||||
float _y = m_bounds->m_pos.y;
|
||||
m_bounds->setPosition( x, y );
|
||||
HEntity _e = getCollisionObject();
|
||||
m_bounds->setPosition( _x, _y );
|
||||
return( _e );
|
||||
}
|
||||
|
||||
void PASAPScenario()
|
||||
{
|
||||
// Got rid of all the hardcoding that was here.
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
// Entity.h
|
||||
//
|
||||
// Last modified: 22 May 04, Mark Thompson mot20@cam.ac.uk / mark@wildfiregames.com
|
||||
// Last modified: 26 May 04, Mark Thompson mot20@cam.ac.uk / mark@wildfiregames.com
|
||||
//
|
||||
// Entity class.
|
||||
//
|
||||
@ -15,10 +15,12 @@
|
||||
//
|
||||
// snapToGround(): Called every frame, this will ensure the entity never takes flight.
|
||||
// updateActorTransforms(): Must be called every time the position of this entity changes.
|
||||
// Also remember to update the collision object if you alter the position directly.
|
||||
//
|
||||
// Some notes: update() and dispatch() /can/ be called directly without ill effects,
|
||||
// but it's preferable to go through the Entity manager and the Scheduler, respectively.
|
||||
//
|
||||
// Collision detection/avoidance is now present in some form; this is a work in progress.
|
||||
|
||||
#ifndef ENTITY_INCLUDED
|
||||
#define ENTITY_INCLUDED
|
||||
@ -27,6 +29,8 @@
|
||||
#include "EntityProperties.h"
|
||||
|
||||
#include "BaseEntity.h"
|
||||
#include "Vector2D.h"
|
||||
#include "BoundingObjects.h"
|
||||
#include "Vector3D.h"
|
||||
#include "Unit.h"
|
||||
#include "UnitManager.h"
|
||||
@ -45,7 +49,9 @@ public:
|
||||
CStr m_name;
|
||||
float m_speed;
|
||||
CVector3D m_position;
|
||||
CBoundingObject* m_bounds;
|
||||
float m_targetorientation;
|
||||
CVector2D m_ahead;
|
||||
float m_orientation;
|
||||
CBaseEntity* m_base;
|
||||
CUnit* m_actor;
|
||||
@ -65,9 +71,12 @@ public:
|
||||
void dispatch( CMessage* msg );
|
||||
void update( float timestep );
|
||||
void updateActorTransforms();
|
||||
void render();
|
||||
float getExactGroundLevel( float x, float y );
|
||||
void snapToGround();
|
||||
void pushOrder( CEntityOrder& order );
|
||||
HEntity getCollisionObject();
|
||||
HEntity getCollisionObject( float x, float y );
|
||||
};
|
||||
|
||||
#endif
|
@ -39,6 +39,11 @@ void HEntity::operator=( const HEntity& copy )
|
||||
addRef();
|
||||
}
|
||||
|
||||
bool HEntity::operator ==( const HEntity& test ) const
|
||||
{
|
||||
return( m_handle == test.m_handle );
|
||||
}
|
||||
|
||||
void HEntity::addRef()
|
||||
{
|
||||
if( m_handle != INVALID_HANDLE )
|
||||
@ -57,14 +62,14 @@ void HEntity::decRef()
|
||||
}
|
||||
}
|
||||
|
||||
CEntity* HEntity::operator->()
|
||||
CEntity* HEntity::operator->() const
|
||||
{
|
||||
assert( m_handle != INVALID_HANDLE );
|
||||
assert( g_EntityManager.m_entities[m_handle].m_refcount != 0 );
|
||||
return( g_EntityManager.m_entities[m_handle].m_entity );
|
||||
}
|
||||
|
||||
CEntity& HEntity::operator*()
|
||||
CEntity& HEntity::operator*() const
|
||||
{
|
||||
assert( m_handle != INVALID_HANDLE );
|
||||
assert( g_EntityManager.m_entities[m_handle].m_refcount != 0 );
|
||||
|
@ -43,11 +43,13 @@ class HEntity
|
||||
void decRef();
|
||||
HEntity( u16 index );
|
||||
public:
|
||||
CEntity& operator*();
|
||||
CEntity* operator->();
|
||||
CEntity& operator*() const;
|
||||
CEntity* operator->() const;
|
||||
HEntity();
|
||||
HEntity( const HEntity& copy );
|
||||
void operator=( const HEntity& copy );
|
||||
bool operator==( const HEntity& test ) const;
|
||||
operator bool() const { return( m_handle != INVALID_HANDLE ); }
|
||||
~HEntity();
|
||||
};
|
||||
|
||||
|
@ -39,6 +39,15 @@ std::vector<HEntity>* CEntityManager::matches( EntityPredicate predicate )
|
||||
return( matchlist );
|
||||
}
|
||||
|
||||
std::vector<HEntity>* CEntityManager::getActive()
|
||||
{
|
||||
std::vector<HEntity>* activelist = new std::vector<HEntity>;
|
||||
for( int i = 0; i < MAX_HANDLES; i++ )
|
||||
if( m_entities[i].m_refcount )
|
||||
activelist->push_back( HEntity( i ) );
|
||||
return( activelist );
|
||||
}
|
||||
|
||||
void CEntityManager::dispatchAll( CMessage* msg )
|
||||
{
|
||||
for( int i = 0; i < MAX_HANDLES; i++ )
|
||||
@ -53,4 +62,11 @@ void CEntityManager::updateAll( float timestep )
|
||||
m_entities[i].m_entity->update( timestep );
|
||||
}
|
||||
|
||||
void CEntityManager::renderAll()
|
||||
{
|
||||
for( int i = 0; i < MAX_HANDLES; i++ )
|
||||
if( m_entities[i].m_refcount )
|
||||
m_entities[i].m_entity->render();
|
||||
}
|
||||
|
||||
bool CEntityManager::m_extant = false;
|
@ -39,7 +39,9 @@ public:
|
||||
HEntity create( CStr templatename, CVector3D position, float orientation );
|
||||
void updateAll( float timestep );
|
||||
void dispatchAll( CMessage* msg );
|
||||
void renderAll(); // TODO MT: What's the correct way to hook this up to the renderer?
|
||||
std::vector<HEntity>* matches( EntityPredicate predicate );
|
||||
std::vector<HEntity>* getActive();
|
||||
static inline bool extant() // True if the singleton is actively maintaining handles. When false, system is shutting down, handles are quietly dumped.
|
||||
{
|
||||
return( m_extant );
|
||||
|
@ -8,6 +8,10 @@
|
||||
// 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
|
||||
// used to return a path of line segments from the pathfinder.
|
||||
// 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
|
||||
// comes along, this order can be deleted.
|
||||
// ORDER_GOTO: Attempts to reach the given destination. Uses the pathfinder
|
||||
// to... er... find the path.
|
||||
// Create this order when a standard movement or movement waypoint
|
||||
@ -26,18 +30,12 @@
|
||||
#define ORDER_MAX_DATA 1
|
||||
|
||||
#include "EntityHandles.h"
|
||||
#include "Vector2D.h"
|
||||
|
||||
struct SOrderData
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
} location;
|
||||
u64 data; // miscellaneous
|
||||
};
|
||||
CVector2D location;
|
||||
u64 data; // miscellaneous
|
||||
HEntity entity;
|
||||
};
|
||||
|
||||
@ -47,6 +45,7 @@ public:
|
||||
enum
|
||||
{
|
||||
ORDER_GOTO_NOPATHING,
|
||||
ORDER_GOTO_COLLISION,
|
||||
ORDER_GOTO,
|
||||
ORDER_PATROL
|
||||
} m_type;
|
||||
|
@ -164,7 +164,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
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user