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:
parent
cd792eeb8e
commit
0baca62d61
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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__
|
||||
|
@ -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);
|
||||
|
@ -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 );
|
||||
|
@ -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;
|
||||
|
@ -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 );
|
||||
|
@ -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 )
|
||||
{
|
||||
|
@ -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 );
|
||||
|
@ -146,6 +146,7 @@ public:
|
||||
|
||||
int m_sectorDivs;
|
||||
int m_pitchDivs;
|
||||
float m_pitchValue;
|
||||
float m_anchorConformX;
|
||||
float m_anchorConformZ;
|
||||
|
||||
|
@ -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 );
|
||||
}
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user