1
0
forked from 0ad/0ad

# Fixes to terrain conformance and movement speed bonus.

- Simplified CTerrain::getSlopeAngleFace and made it work correctly in
all cases (before, it sometimes returned NAN and used an overly
complicated method based on 8 angle sectors instead of a "continuous"
method).
- Removed the EntityMovement event - instead, movement speed modifier is
calculated in C++ for performance.

This was SVN commit r4339.
This commit is contained in:
Matei 2006-09-16 20:13:40 +00:00
parent cd792eeb8e
commit 0baca62d61
12 changed files with 45 additions and 121 deletions

View File

@ -210,102 +210,25 @@ float CTerrain::getSlope(float x, float z) const
return MAX(MAX(h00, h01), MAX(h10, h11)) -
MIN(MIN(h00, h01), MIN(h10, h11));
}
CVector2D CTerrain::getSlopeAngleFace(float x, float y, CEntity*& entity ) const
CVector2D CTerrain::getSlopeAngleFace( CEntity* entity ) const
{
//side start at 0 at -180 degrees, and end up at 7 at 180 degrees
int side;
bool invert;
float top, bottom, topZ, bottomZ;
float fCell = (float)CELL_SIZE;
x /= fCell;
y /= fCell;
int xi = (int)floor(x);
int yi = (int)floor(y);
CVector3D flat(0.0f, 0.0f, 0.0f);
CVector3D flatZ = flat;
CVector2D ret;
side = entity->findSector( 8, entity->m_orientation.Y, DEGTORAD(360.0f) ) - 1;
//Wrap around
if ( side < 0 )
side += 8;
//Keep it in bounds
clampCoordToMap(xi);
clampCoordToMap(yi);
float h00 = m_Heightmap[yi*m_MapSize + xi] * HEIGHT_SCALE;
float h01 = m_Heightmap[yi*m_MapSize + xi + m_MapSize] * HEIGHT_SCALE;
float h10 = m_Heightmap[yi*m_MapSize + xi + 1] * HEIGHT_SCALE;
float h11 = m_Heightmap[yi*m_MapSize + xi + m_MapSize + 1] * HEIGHT_SCALE;
//Find heights
if ( side == 0 || side == 7 )
{
top = (h00 + h10)/2.0f;
bottom = (h01 + h11)/2.0f;
topZ = (h00 + h01)/2.0f;
bottomZ = (h10 + h11)/2.0f;
flat.Z = sqrtf(SQR(CELL_SIZE) - SQR(top-bottom));
flatZ.X = sqrtf(SQR(CELL_SIZE) - SQR(topZ-bottomZ));
}
else if ( side == 1 || side == 2 )
{
top = (h00 + h01)/2.0f;
bottom = (h10 + h11)/2.0f;
topZ = (h01 + h11)/2.0f;
bottomZ = (h00 + h10)/2.0f;
flat.X = sqrtf(SQR(CELL_SIZE) - SQR(top-bottom));
flatZ.Z = sqrtf(SQR(CELL_SIZE) - SQR(topZ-bottomZ));
}
else if ( side == 3 || side == 4 )
{
top = (h01 + h11)/2.0f;
bottom = (h00 + h10)/2.0f;
topZ = (h11 + h10)/2.0f;
bottomZ = (h00 + h01)/2.0f;
flat.Z = sqrtf(SQR(CELL_SIZE) - SQR(top-bottom));
flatZ.X = sqrtf(SQR(CELL_SIZE) - SQR(topZ-bottomZ));
}
else
{
top = (h11 + h10)/2.0f;
bottom = (h00 + h01)/2.0f;
topZ = (h00 + h10)/2.0f;
bottomZ = (h01 + h11)/2.0f;
flat.X = sqrtf(SQR(CELL_SIZE) - SQR(top-bottom));
flatZ.Z = sqrtf(SQR(CELL_SIZE) - SQR(topZ-bottomZ));
}
CVector3D elevated=flat;
elevated.Y = top-bottom;
if ( elevated.Y > 0.0f )
invert=false;
else
invert=true;
elevated.Y = fabs(elevated.Y);
elevated.Normalize();
flat.Normalize();
if ( invert )
ret.x = -acosf( elevated.Dot(flat) );
else
ret.x = acosf( elevated.Dot(flat) );
//Z component
elevated = flatZ;
elevated.Y = topZ-bottomZ;
if ( elevated.Y > 0.0f )
invert=true;
else
invert=false;
elevated.Y = fabs(elevated.Y);
elevated.Normalize();
flatZ.Normalize();
if ( invert )
ret.y = -acosf( elevated.Dot(flatZ) );
else
ret.y = acosf( elevated.Dot(flatZ) );
const float D = 0.1f; // Amount to look forward to calculate the slope
float x = entity->m_position.X;
float z = entity->m_position.Z;
float y = getExactGroundLevel(x, z);
// Get forward slope and use it as the x angle
CVector2D d = entity->m_ahead.normalize() * D;
float dy = getExactGroundLevel(x+d.x, z+d.y) - y;
ret.x = atan2(dy, D);
// Get sideways slope and use it as the y angle
CVector2D d2(-d.y, d.x);
float dy2 = getExactGroundLevel(x+d2.x, z+d2.y) - y;
ret.y = atan2(dy2, D);
return ret;
}

View File

@ -69,7 +69,7 @@ public:
float getSlope(float x, float z) const ;
//Find the slope of in X and Z axes depending on the way the entity is facing
CVector2D getSlopeAngleFace(float x, float y, CEntity*& entity) const;
CVector2D getSlopeAngleFace(CEntity* entity) const;
// resize this terrain such that each side has given number of patches
void Resize(u32 size);

View File

@ -24,7 +24,6 @@ enum EEventType
EVENT_NOTIFICATION,
EVENT_FORMATION,
EVENT_IDLE,
EVENT_MOVEMENT,
EVENT_LAST,
// Projectile events
@ -55,7 +54,6 @@ static const wchar_t* const EventNames[EVENT_LAST] =
/* EVENT_NOTIFICATION */ L"onNotification", /*When we receive a notification */
/* EVENT_FORMATION */ L"onFormation", /* When this unit does something with a formation */
/* EVENT_IDLE */ L"onIdle", /* When this unit becomes idle, do something */
/* EVENT_MOVEMENT */ L"onMovement" /*Triggered by processGotoHelper(), when unit moves */
};
#endif // #ifndef EVENTTYPES_H__

View File

@ -100,7 +100,7 @@ CEntity* getCollisionEntity( CBoundingObject* bounds, CPlayer* player, const CSt
return( NULL );
}
HEntity getCollisionObject( CEntity* entity )
HEntity getCollisionObject( CEntity* entity, bool enablePassThroughAllies )
{
#ifndef NDEBUG
debug_assert( entity->m_bounds );
@ -116,8 +116,13 @@ HEntity getCollisionObject( CEntity* entity )
{
if( !(*it)->m_bounds ) continue;
if( (*it)->m_bounds == entity->m_bounds ) continue;
if( entity->m_base->m_passThroughAllies && (*it)->m_base->m_passThroughAllies
&& entity->GetPlayer() == (*it)->GetPlayer() ) continue;
if( enablePassThroughAllies
&& entity->m_base->m_passThroughAllies
&& (*it)->m_base->m_passThroughAllies
&& entity->GetPlayer() == (*it)->GetPlayer() )
continue;
if( entity->m_bounds->intersects( (*it)->m_bounds ) )
{
HEntity collisionObject = HEntity((*it)->me);

View File

@ -35,7 +35,7 @@ struct rayIntersectionResults
typedef std::vector<CEntity*> RayIntersects;
HEntity getCollisionObject( CEntity* entity );
HEntity getCollisionObject( CEntity* entity, bool enablePassThroughAllies=true );
HEntity getCollisionObject( CEntity* entity, float x, float y );
CBoundingObject* getCollisionObject( CBoundingObject* bounds, CPlayer* player=0, const CStrW* ignoreClass=0 );
CEntity* getCollisionEntity( CBoundingObject* bounds, CPlayer* player=0, const CStrW* ignoreClass=0 );

View File

@ -296,7 +296,7 @@ void CEntityManager::conformAll()
if( isEntityRefd(i) )
{
CEntity* entity = m_entities[i].m_entity;
CVector2D targetXZ = g_Game->GetWorld()->GetTerrain()->getSlopeAngleFace( entity->m_position.X, entity->m_position.Z, entity );
CVector2D targetXZ = g_Game->GetWorld()->GetTerrain()->getSlopeAngleFace(entity );
while( targetXZ.x > PI ) targetXZ.x -= 2 * PI;
while( targetXZ.x < -PI ) targetXZ.x += 2 * PI;

View File

@ -87,7 +87,7 @@ void CEntity::ScriptingInit()
/* Any inherited property MUST be added to EntityTemplate.cpp as well */
AddClassProperty( L"actions.move.speedCurr", &CEntity::m_speed );
AddClassProperty( L"actions.move.speed", &CEntity::m_speed );
AddClassProperty( L"actions.move.run.speed", &CEntity::m_runSpeed );
AddClassProperty( L"actions.move.run.rangemin", &CEntity::m_runMinRange );
AddClassProperty( L"actions.move.run.range", &CEntity::m_runMaxRange );

View File

@ -57,9 +57,14 @@ float CEntity::chooseMovementSpeed( float distance )
{
bool should_run = shouldRun(distance);
const float speed = should_run? m_runSpeed : m_speed;
float speed = should_run? m_runSpeed : m_speed;
const char* anim_name = should_run? "run" : "walk";
// Modify the speed based on the slope of the terrain in our direction (obtained from our x orientation)
float angle = m_orientation_unclamped.x;
int sector = ia32_rintf( angle / (PI/2) * m_base->m_pitchDivs );
speed -= sector * m_base->m_pitchValue;
// TODO: the animation code requires unicode for now. will be changed to
// 8bit later (for consistency; note that filenames etc. need not be
// unicode), so remove this then.
@ -147,8 +152,7 @@ uint CEntity::processGotoHelper( CEntityOrder* current, size_t timestep_millis,
m_ahead = delta / len;
m_orientation.Y = m_targetorientation;
}
CEntity* _this = this;
CVector2D targetXZ = g_Game->GetWorld()->GetTerrain()->getSlopeAngleFace( m_position.X, m_position.Z, _this );
CVector2D targetXZ = g_Game->GetWorld()->GetTerrain()->getSlopeAngleFace(this);
while( targetXZ.x > PI ) targetXZ.x -= 2 * PI;
while( targetXZ.x < -PI ) targetXZ.x += 2 * PI;
@ -161,8 +165,8 @@ uint CEntity::processGotoHelper( CEntityOrder* current, size_t timestep_millis,
m_orientation_unclamped.x = targetXZ.x;
m_orientation_unclamped.y = targetXZ.y;
CMovementEvent evt( m_orientation_unclamped.x );
DispatchEvent(&evt);
//CMovementEvent evt( m_orientation_unclamped.x );
//DispatchEvent(&evt);
if( m_bounds && m_bounds->m_type == CBoundingObject::BOUND_OABB )
((CBoundingBox*)m_bounds)->setOrientation( m_ahead );
@ -186,7 +190,11 @@ uint CEntity::processGotoHelper( CEntityOrder* current, size_t timestep_millis,
{
m_bounds->setPosition( m_position.X, m_position.Z );
collide = getCollisionObject( this );
// For now, ignore passThroughAllies for low-level movement (but leave it on for long-range
// pathfinding); ideally we will enable pass-through-allies only for the long-range pathing
// and when the unit is moving to assume its place in a formation, since it looks bad to have
// units stand on each other otherwise.
collide = getCollisionObject( this, false );
if( collide )
{

View File

@ -391,7 +391,7 @@ void CEntityTemplate::ScriptingInit()
AddClassProperty( L"traits.id.classes", (GetFn)&CEntityTemplate::getClassSet, (SetFn)&CEntityTemplate::setClassSet );
AddClassProperty( L"actions.move.speedCurr", &CEntityTemplate::m_speed );
AddClassProperty( L"actions.move.speed", &CEntityTemplate::m_speed );
AddClassProperty( L"actions.move.turningRadius", &CEntityTemplate::m_turningRadius );
AddClassProperty( L"actions.move.run.speed", &CEntityTemplate::m_runSpeed );
AddClassProperty( L"actions.move.run.rangeMin", &CEntityTemplate::m_runMinRange );
@ -422,6 +422,7 @@ void CEntityTemplate::ScriptingInit()
AddClassProperty( L"traits.rally.height", &CEntityTemplate::m_rallyHeight );
AddClassProperty( L"traits.flankPenalty.sectors", &CEntityTemplate::m_sectorDivs );
AddClassProperty( L"traits.pitch.sectors", &CEntityTemplate::m_pitchDivs );
AddClassProperty( L"traits.pitch.value", &CEntityTemplate::m_pitchValue );
AddClassProperty( L"traits.rank.width", &CEntityTemplate::m_rankWidth );
AddClassProperty( L"traits.rank.height", &CEntityTemplate::m_rankHeight );
AddClassProperty( L"traits.rank.name", &CEntityTemplate::m_rankName );

View File

@ -146,6 +146,7 @@ public:
int m_sectorDivs;
int m_pitchDivs;
float m_pitchValue;
float m_anchorConformX;
float m_anchorConformZ;

View File

@ -121,9 +121,3 @@ CIdleEvent::CIdleEvent( CEntityOrder order, int notifyType ) : CScriptEvent( L"i
AddLocalProperty( L"target", &m_target );
AddLocalProperty( L"location", &m_location );
}
CMovementEvent::CMovementEvent( float slope ) : CScriptEvent( L"movementEvent", EVENT_MOVEMENT, false )
{
m_slope = slope;
AddLocalProperty( L"slope", &m_slope );
}

View File

@ -139,10 +139,4 @@ class CIdleEvent : public CScriptEvent
public:
CIdleEvent( CEntityOrder order, int notifyType );
};
class CMovementEvent : public CScriptEvent
{
float m_slope;
public:
CMovementEvent( float slope );
};
#endif