1
0
forked from 0ad/0ad

# Some fixes to projectiles

- Removed use of erase() in the middle of iterating through projectiles
in CProjectileManager - that was dangerous! Replaced projectiles vector
with a linked list to make it easy and efficient to delete elements in
the middle.
- Fixed animation. It seemed like a problem with updating the Y position
came up and was more apparent as we lowered the turn length.

This was SVN commit r5593.
This commit is contained in:
Matei 2008-02-03 09:10:15 +00:00
parent 0201229520
commit 7773b9b204
5 changed files with 51 additions and 30 deletions

View File

@ -410,10 +410,11 @@ void CGameView::EnumerateObjects(const CFrustum& frustum, SceneCollector* c)
}
}
const std::vector<CProjectile*>& projectiles = pProjectileMan.GetProjectiles();
for (uint i = 0; i < projectiles.size(); ++i)
const std::list<CProjectile*>& projectiles = pProjectileMan.GetProjectiles();
std::list<CProjectile*>::const_iterator it = projectiles.begin();
for (; it != projectiles.end(); ++it)
{
CModel* model = projectiles[i]->GetModel();
CModel* model = (*it)->GetModel();
model->ValidatePosition();
@ -425,7 +426,7 @@ void CGameView::EnumerateObjects(const CFrustum& frustum, SceneCollector* c)
&& losMgr->GetStatus(centre.X, centre.Z, g_Game->GetLocalPlayer()) & LOS_VISIBLE)
{
PROFILE( "submit projectiles" );
c->SubmitRecursive(projectiles[i]->GetModel());
c->SubmitRecursive((*it)->GetModel());
}
}
PROFILE_END( "submit models" );

View File

@ -43,18 +43,12 @@ CProjectile::CProjectile( const CModel* Actor, const CVector3D& Position, const
double t = s / m_Speed_H;
// Required vertical velocity at launch:
m_Speed_V = (float)( d_h / t + GRAVITY_2 * t );
m_Speed_V_Previous = m_Speed_V;
}
CProjectile::~CProjectile()
{
CProjectileManager& projectileManager = g_Game->GetWorld()->GetProjectileManager();
std::vector<CProjectile*>::iterator it;
for( it = projectileManager.m_Projectiles.begin(); it != projectileManager.m_Projectiles.end(); ++it )
if( *it == this )
{
projectileManager.m_Projectiles.erase( it );
break;
}
delete( m_Actor );
}
@ -63,10 +57,10 @@ bool CProjectile::Update( size_t timestep_millis )
m_Position_Previous = m_Position;
m_Position.X += timestep_millis * m_Axis.x * m_Speed_H;
m_Position.Z += timestep_millis * m_Axis.y * m_Speed_H;
m_Position.Y += (float)( timestep_millis * ( m_Speed_V - timestep_millis * GRAVITY_2 ) );
m_Speed_V_Previous = m_Speed_V;
m_Speed_V -= (float)( timestep_millis * GRAVITY );
float height = m_Position.Y - g_Game->GetWorld()->GetTerrain()->GetExactGroundLevel( m_Position.X, m_Position.Z );
if( height < 0.0f )
@ -100,8 +94,8 @@ void CProjectile::Interpolate( size_t timestep_millis )
{
m_Position_Graphics.X = m_Position_Previous.X + timestep_millis * m_Speed_H * m_Axis.x;
m_Position_Graphics.Z = m_Position_Previous.Z + timestep_millis * m_Speed_H * m_Axis.y;
m_Position_Graphics.Y = (float)( m_Position_Previous.Y + timestep_millis * ( m_Speed_V - timestep_millis * GRAVITY_2 ) );
float dh_dt = (float)( m_Speed_V - timestep_millis * GRAVITY );
m_Position_Graphics.Y = (float)( m_Position_Previous.Y + timestep_millis * ( m_Speed_V_Previous - timestep_millis * GRAVITY_2 ) );
float dh_dt = (float)( m_Speed_V_Previous - timestep_millis * GRAVITY );
float scale = 1 / sqrt( m_Speed_H * m_Speed_H + dh_dt * dh_dt );
float scale2 = m_Speed_H * scale;
@ -248,8 +242,12 @@ CProjectileManager::~CProjectileManager()
void CProjectileManager::DeleteAll()
{
while( !( m_Projectiles.empty() ) )
delete( m_Projectiles[0] ); // removes itself from m_Projectiles
std::list<CProjectile*>::iterator it;
for (it = m_Projectiles.begin(); it != m_Projectiles.end(); ++it)
{
delete *it;
}
m_Projectiles.clear();
}
CProjectile* CProjectileManager::AddProjectile( const CModel* Actor, const CVector3D& Position, const CVector3D& Target, float Speed, CEntity* Originator, const CScriptObject& ImpactScript, const CScriptObject& MissScript )
@ -261,23 +259,38 @@ CProjectile* CProjectileManager::AddProjectile( const CModel* Actor, const CVect
void CProjectileManager::DeleteProjectile( CProjectile* p )
{
delete( p );
m_Projectiles.erase( std::find(m_Projectiles.begin(), m_Projectiles.end(), p) );
delete p;
}
void CProjectileManager::UpdateAll( size_t timestep )
{
m_LastTurnLength = timestep;
for( size_t i = 0; i < m_Projectiles.size(); )
if( !( m_Projectiles[i]->Update( timestep ) ) )
delete( m_Projectiles[i] ); // removes itself from m_Projectiles
std::list<CProjectile*>::iterator it;
for (it = m_Projectiles.begin(); it != m_Projectiles.end();)
{
CProjectile* p = *it;
if (!p->Update(timestep))
{
// Projectile is dead due to having hit the ground or something
std::list<CProjectile*>::iterator old = it;
it++;
m_Projectiles.erase(old);
delete p;
}
else
i++;
{
// Update completed successfully
it++;
}
}
}
void CProjectileManager::InterpolateAll( double relativeOffset )
{
size_t absoluteOffset = (size_t)( (double)m_LastTurnLength * relativeOffset );
std::vector<CProjectile*>::iterator it;
std::list<CProjectile*>::iterator it;
for( it = m_Projectiles.begin(); it != m_Projectiles.end(); ++it )
(*it)->Interpolate( absoluteOffset );
}

View File

@ -33,6 +33,7 @@ class CProjectile : public CJSObject<CProjectile>, public IEventTarget
// Horizontal and vertical velocities
float m_Speed_H;
float m_Speed_V;
float m_Speed_V_Previous;
CEntity* m_Originator;
@ -89,7 +90,7 @@ public:
void UpdateAll( size_t timestep );
void InterpolateAll( double frametime );
inline const std::vector<CProjectile*>& GetProjectiles() { return m_Projectiles; }
inline const std::list<CProjectile*>& GetProjectiles() { return m_Projectiles; }
CProjectile* AddProjectile( const CModel* Actor, const CVector3D& Position, const CVector3D& Target, float Speed, CEntity* Originator, const CScriptObject& ImpactScript, const CScriptObject& MissScript );
// Only if you have some reason to prematurely get rid of a projectile.
@ -100,7 +101,7 @@ private:
size_t m_LastTurnLength;
// Maintain a list of the projectiles in the world
std::vector<CProjectile*> m_Projectiles;
std::list<CProjectile*> m_Projectiles;
};
#endif

View File

@ -12,8 +12,8 @@ CSinglePlayerTurnManager *g_SinglePlayerTurnManager=NULL;
CTurnManager::CTurnManager()
{
for (int i=0;i<3;i++)
m_Batches[i].m_TurnLength=DEFAULT_TURN_LENGTH;
for (int i=0; i<3; i++)
m_Batches[i].m_TurnLength = DEFAULT_TURN_LENGTH;
}
void CTurnManager::ClearBatch(uint batch)
@ -144,3 +144,8 @@ void CSinglePlayerTurnManager::QueueLocalCommand(CNetMessage *pMsg)
{
QueueMessage(2, pMsg);
}
bool CSinglePlayerTurnManager::NewTurnReady()
{
return true;
}

View File

@ -102,16 +102,16 @@ public:
uint GetTurnLength();
// Called by CSimulation when the current turn time has passed.
virtual void NewTurn()=0;
virtual void NewTurn() = 0;
// Used by CSimulation to ask whether it can call NewTurn.
virtual bool NewTurnReady() { return true; }
virtual bool NewTurnReady() = 0;
// Apply a function to all messages in a given batch.
void IterateBatch(uint batch, BatchIteratorFunc *func, void *userdata);
// Queue a command originating from the local player.
virtual void QueueLocalCommand(CNetMessage *pMsg)=0;
virtual void QueueLocalCommand(CNetMessage *pMsg) = 0;
};
class CSinglePlayerTurnManager: public CTurnManager
@ -121,6 +121,7 @@ public:
virtual void NewTurn();
virtual void QueueLocalCommand(CNetMessage *pMsg);
virtual bool NewTurnReady();
};
extern CSinglePlayerTurnManager *g_SinglePlayerTurnManager;