1
0
forked from 0ad/0ad

#When appropriate (i.e. wheeled units), units will align with the slope of the terrain. *JS documentation

*added CTerrain::getSlopeAngle[Face]() which returns the angle in
radians of the slope of the terrain.  getSlopeAngleFace should be used
for entities because it takes into account which way the entity is
facing, which allows for negative angles.
*the max and min graphical rotation for the slope is under traits.pitch.
This is used so that you can have certain units such as infantry that
don't rotate very far go down steep slopes but not rotate too much.
*JS documentation in docs/JSReg.rtf -- I put in most of the relevant
global functions; still needs entity functions.

This was SVN commit r3794.
This commit is contained in:
pyrolink 2006-04-22 05:52:23 +00:00
parent 2702a268ef
commit b5d9da29c1
10 changed files with 212 additions and 40 deletions

BIN
docs/JSReg.rtf Normal file

Binary file not shown.

View File

@ -19,8 +19,6 @@
#include "CStr.h"
#include "NUSpline.h"
#include <list>
#include <map>
/*
Andrew (aka pyrolink)

View File

@ -390,8 +390,6 @@ void CGameView::CameraLock(float x, float y, float z, bool smooth)
m_ViewCamera.m_Orientation.Translate(x, y, z);
m_ViewCamera.m_Orientation._24=height;
}
}
}

View File

@ -53,8 +53,6 @@ bool CTerrain::Initialize(u32 size,const u16* data)
// store terrain size
m_MapSize=(size*PATCH_SIZE)+1;
m_MapSizePatches=size;
// WaterManager *WaterMgr = g_Renderer.GetWaterManager();
// WaterMgr->InitWave();
// allocate data for new terrain
m_Heightmap=new u16[m_MapSize*m_MapSize];
m_Patches=new CPatch[m_MapSizePatches*m_MapSizePatches];
@ -204,10 +202,166 @@ float CTerrain::getSlope(float x, float z) const
float h01 = m_Heightmap[zi*m_MapSize + xi + m_MapSize];
float h10 = m_Heightmap[zi*m_MapSize + xi + 1];
float h11 = m_Heightmap[zi*m_MapSize + xi + m_MapSize + 1];
//Difference of highest point from lowest point
return MAX(MAX(h00, h01), MAX(h10, h11)) -
MIN(MIN(h00, h01), MIN(h10, h11));
}
float CTerrain::getSlopeAngle( float x, float y ) const
{
float fCell = (float)CELL_SIZE;
x /= fCell;
y /= fCell;
int xi = (int)floor(x);
int yi = (int)floor(y);
//Keep it in bounds
if (xi < 0)
xi = 0;
else if (xi >= (int)m_MapSize-1)
xi = m_MapSize - 2;
if (yi < 0)
yi = 0;
else if (yi >= (int)m_MapSize-1)
yi = m_MapSize - 2;
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;
CVector3D flat, elevated;
float low, high;
if ( h00 < h01 && h00 < h10 && h00 < h11 )
low = h00;
else if ( h01 < h10 && h01 < h11 )
low = h01;
else if ( h10 < h11 )
low = h10;
else
low = h11;
//Find correct vector representing the flat version of the vector from low to high points
if ( h00 > h01 && h00 > h10 && h00 > h11 )
{
high = h00;
if ( low == h10 )
flat = CVector3D( fCell, 0.0f, 0.0f );
else if ( low == h01 )
flat = CVector3D( 0.0f, 0.0f, fCell );
else if ( low == h11 )
flat = CVector3D( fCell, 0.0f, fCell );
}
else if ( h01 > h10 && h01 > h11 )
{
high = h01;
if ( low == h00 )
flat = CVector3D( 0.0f, 0.0f, fCell );
else if ( low == h01 )
flat = CVector3D( fCell, 0.0f, fCell );
else if ( low == h11 )
flat = CVector3D( fCell, 0.0f, 0.0f );
}
else if ( h10 > h11 )
{
high = h10;
if ( low == h00 )
flat = CVector3D( fCell, 0.0f, 0.0f );
else if ( low == h01 )
flat = CVector3D( fCell, 0.0f, fCell );
else if ( low == h11 )
flat = CVector3D( 0.0f, 0.0f, fCell );
}
else
{
high = h11;
if ( low == h10 )
flat = CVector3D( 0.0f, 0.0f, fCell );
else if ( low == h01 )
flat = CVector3D( fCell, 0.0f, 0.0f );
else if ( low == h00 )
flat = CVector3D( fCell, 0.0f, fCell );
}
elevated = flat;
elevated.Y = high - low;
elevated.Normalize();
flat.Normalize();
return acosf( flat.Dot( elevated ) );
}
float CTerrain::getSlopeAngleFace(float x, float y, float orientation) const
{
bool right; //true means use 0,0 and 1,1; false means use 1,0 and 0,1
bool invert;
float top, bottom;
x /= (float)CELL_SIZE;
y /= (float)CELL_SIZE;
int xi = (int)floor(x);
int yi = (int)floor(y);
CVector3D flat( (float)CELL_SIZE, 0.0f, (float)CELL_SIZE );
CVector3D elevated=flat;
float a0 = DEGTORAD(0.0f);
float a90 = DEGTORAD(90.0f);
float a180 = DEGTORAD(180.0f);
float neg = DEGTORAD(-90.0f);
float a45 = DEGTORAD(45.0f);
float a135 = DEGTORAD(135.0f);
//Find which side it's facing; use that and the opposite
if ( orientation > 0.0f && orientation < DEGTORAD(90.0f) )
right = true;
else if ( orientation > DEGTORAD(90.0f) && orientation < DEGTORAD(180.0f) )
right = false;
else if ( orientation < DEGTORAD(-180.0f) && orientation > DEGTORAD(-90.0f) )
right = true;
else
right = false;
//Keep it in bounds
if (xi < 0)
xi = 0;
else if (xi >= (int)m_MapSize-1)
xi = m_MapSize - 2;
if (yi < 0)
yi = 0;
else if (yi >= (int)m_MapSize-1)
yi = m_MapSize - 2;
if ( right )
{
bottom = m_Heightmap[yi*m_MapSize + xi]*HEIGHT_SCALE;
top = m_Heightmap[yi*m_MapSize+m_MapSize + xi + 1]*HEIGHT_SCALE;
if ( (orientation > DEGTORAD(-45.0f) && orientation < 0.0f) ||
(orientation < DEGTORAD(135.0f) && orientation > 0.0f) )
elevated.Y = top-bottom;
else
elevated.Y = bottom-top;
}
else
{
bottom = m_Heightmap[yi*m_MapSize + xi + 1]*HEIGHT_SCALE;
top = m_Heightmap[yi*m_MapSize+m_MapSize + xi]*HEIGHT_SCALE;
if ( (orientation > DEGTORAD(-135.0f) && orientation < 0.0f) ||
(orientation < DEGTORAD(45.0f) && orientation > 0.0f) )
elevated.Y = top-bottom;
else
elevated.Y = bottom-top;
}
if ( elevated.Y > 0.0f )
invert=false;
else
invert=true;
elevated.Y = fabs(elevated.Y);
elevated.Normalize();
flat.Normalize();
float ret = elevated.Dot(flat);
if (invert)
return -acosf(ret);
return acosf(ret);
}
float CTerrain::getExactGroundLevel(float x, float z) const
{

View File

@ -45,7 +45,9 @@ public:
inline float getExactGroundLevel(const CVector2D& v) const { return getExactGroundLevel(v.x, v.y); }
float getSlope(float x, float z) const ;
float getSlopeAngle( float x, float y) const; //In radians
//Same as above, but picks the two vertices that the unit is facing (front+back) for slope
float getSlopeAngleFace(float x, float y, float orientation) const;
// resize this terrain such that each side has given number of patches
void Resize(u32 size);

View File

@ -49,6 +49,8 @@ CBaseEntity::CBaseEntity()
AddProperty( L"traits.stamina.border_name", &m_staminaBorderName );
AddProperty( L"traits.angle_penalty.sectors", &m_sectorDivs );
AddProperty( L"traits.angle_penalty.value", &m_sectorPenalty );
AddProperty( L"traits.pitch.max_actor", &m_maxActorPitch );
AddProperty( L"traits.pitch.min_actor", &m_minActorPitch );
AddProperty( L"traits.rank.width", &m_rankWidth );
AddProperty( L"traits.rank.height", &m_rankHeight );
AddProperty( L"traits.rank.name", &m_rankName );

View File

@ -113,6 +113,9 @@ public:
int m_sectorDivs;
float m_sectorPenalty;
float m_maxActorPitch;
float m_minActorPitch;
float m_turningRadius;
CScriptObject m_EventHandlers[EVENT_LAST];

View File

@ -79,6 +79,8 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons
AddProperty( L"traits.stamina.border_name", &m_staminaBorderName );
AddProperty( L"traits.angle_penalty.sectors", &m_sectorDivs);
AddProperty( L"traits.angle_penalty.value", &m_sectorPenalty );
AddProperty( L"traits.pitch.max_actor", &m_maxActorPitch );
AddProperty( L"traits.pitch.min_actor", &m_minActorPitch );
AddProperty( L"traits.rank.width", &m_rankWidth );
AddProperty( L"traits.rank.height", &m_rankHeight );
AddProperty( L"traits.rank.name", &m_rankName );
@ -101,10 +103,6 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons
AddHandler( t, &m_EventHandlers[t] );
}
// FIXME: janwas: this was uninitialized, which leads to disaster if
// its value happens to be positive.
// setting to what seems to be a reasonable default.
m_sectorDivs = 4;
if ( m_sectorDivs >= 0 )
{
m_sectorAngles.resize(m_sectorDivs);
@ -143,6 +141,7 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons
m_graphics_orientation = m_orientation;
m_actor_transform_valid = false;
m_pitchOrientation = m_pitchOrientation_previous = m_graphics_pitchOrientation = 0.0f;
m_destroyed = false;
m_selected = false;
@ -158,7 +157,7 @@ CEntity::CEntity( CBaseEntity* base, CVector3D position, float orientation, cons
m_currentRequest = 0;
m_destroyNotifiers = true;
m_formationSlot = -1;
m_formationSlot = -1;
m_formation = -1;
m_grouped = -1;
@ -277,29 +276,22 @@ void CEntity::SetPlayer(CPlayer *pPlayer)
void CEntity::updateActorTransforms()
{
CMatrix3D m;
CMatrix3D mX;
float Cos = cosf( m_graphics_orientation );
float Sin = sinf( m_graphics_orientation );
float s = sin( m_graphics_orientation );
float c = cos( m_graphics_orientation );
m._11 = -c;
m._12 = 0.0f;
m._13 = -s;
m._14 = m_graphics_position.X;
m._21 = 0.0f;
m._22 = 1.0f;
m._23 = 0.0f;
m._24 = m_graphics_position.Y;
m._31 = s;
m._32 = 0.0f;
m._33 = -c;
m._34 = m_graphics_position.Z;
m._41 = 0.0f;
m._42 = 0.0f;
m._43 = 0.0f;
m._44 = 1.0f;
m._11=-Cos; m._12=0.0f; m._13=-Sin; m._14=0.0f;
m._21=0.0f; m._22=1.0f; m._23=0.0f; m._24=0.0f;
m._31=Sin; m._32=0.0f; m._33=-Cos; m._34=0.0f;
m._41=0.0f; m._42=0.0f; m._43=0.0f; m._44=1.0f;
mX.SetXRotation( m_graphics_pitchOrientation );
mX = m*mX;
mX.Translate(m_graphics_position);
//m.RotateX(m_graphics_pitchOrientation);
if( m_actor )
m_actor->GetModel()->SetTransform( m );
m_actor->GetModel()->SetTransform( mX );
}
void CEntity::snapToGround()
@ -382,7 +374,8 @@ void CEntity::update( size_t timestep )
{
m_position_previous = m_position;
m_orientation_previous = m_orientation;
m_pitchOrientation_previous = m_pitchOrientation;
CalculateRun( timestep );
CalculateHealth( timestep );
@ -809,6 +802,7 @@ void CEntity::repath()
void CEntity::reorient()
{
m_orientation = m_graphics_orientation;
m_pitchOrientation = m_graphics_pitchOrientation;
m_ahead.x = sin( m_orientation );
m_ahead.y = cos( m_orientation );
if( m_bounds->m_type == CBoundingObject::BOUND_OABB )
@ -855,7 +849,8 @@ void CEntity::interpolate( float relativeoffset )
{
CVector3D old_graphics_position = m_graphics_position;
float old_graphics_orientation = m_graphics_orientation;
float old_graphics_pitchOrientation = m_graphics_pitchOrientation;
m_graphics_position = Interpolate<CVector3D>( m_position_previous, m_position, relativeoffset );
// Avoid wraparound glitches for interpolating angles.
@ -864,7 +859,13 @@ void CEntity::interpolate( float relativeoffset )
while( m_orientation > m_orientation_previous + PI )
m_orientation_previous += 2 * PI;
while( m_pitchOrientation < m_pitchOrientation_previous - PI )
m_pitchOrientation_previous -= 2 * PI;
while( m_pitchOrientation > m_pitchOrientation_previous + PI )
m_pitchOrientation_previous += 2 * PI;
m_graphics_orientation = Interpolate<float>( m_orientation_previous, m_orientation, relativeoffset );
m_graphics_pitchOrientation = Interpolate<float>( m_pitchOrientation_previous, m_pitchOrientation, relativeoffset );
// Mark the actor transform data as invalid if the entity has moved since
// the last call to 'interpolate'.
@ -872,10 +873,13 @@ void CEntity::interpolate( float relativeoffset )
// calling snapToGround, which is slow. TODO: This may need to be adjusted to
// handle flying units or moving terrain.
if( m_graphics_orientation != old_graphics_orientation ||
m_graphics_position.X != old_graphics_position.X ||
m_graphics_position.Z != old_graphics_position.Z )
m_graphics_position.X != old_graphics_position.X ||
m_graphics_position.Z != old_graphics_position.Z ||
m_graphics_pitchOrientation != old_graphics_pitchOrientation
)
{
m_actor_transform_valid = false;
}
// Update the actor transform data when necessary.
if( !m_actor_transform_valid )
{

View File

@ -79,6 +79,9 @@ public:
float m_runRegenRate;
float m_runDecayRate;
float m_maxActorPitch;
float m_minActorPitch;
float m_healthRegenRate;
float m_healthRegenStart;
float m_healthDecayRate;
@ -168,6 +171,10 @@ public:
float m_orientation;
float m_orientation_previous;
float m_graphics_orientation;
float m_pitchOrientation;
float m_pitchOrientation_previous;
float m_graphics_pitchOrientation;
// If the actor's current transform data is valid (i.e. the entity hasn't
// moved since it was last calculated, and the terrain hasn't been changed).

View File

@ -89,13 +89,11 @@ uint CEntity::processGotoHelper( CEntityOrder* current, size_t timestep_millis,
float scale = processChooseMovement( len ) * timestep;
// Note: Easy optimization: flag somewhere that this unit
// is already pointing the way, and don't do this
// trig every time.right
m_targetorientation = atan2( delta.x, delta.y );
float deltatheta = m_targetorientation - (float)m_orientation;
while( deltatheta > PI ) deltatheta -= 2 * PI;
while( deltatheta < -PI ) deltatheta += 2 * PI;
@ -136,6 +134,12 @@ uint CEntity::processGotoHelper( CEntityOrder* current, size_t timestep_millis,
m_ahead = delta / len;
m_orientation = m_targetorientation;
}
float targetpitch = g_Game->GetWorld()->GetTerrain()->getSlopeAngleFace( m_position.X, m_position.Z, m_orientation );
while( targetpitch > PI ) targetpitch -= 2 * PI;
while( targetpitch < -PI ) targetpitch += 2 * PI;
m_pitchOrientation = clamp( targetpitch, m_minActorPitch, m_maxActorPitch );
if( m_bounds && m_bounds->m_type == CBoundingObject::BOUND_OABB )
((CBoundingBox*)m_bounds)->setOrientation( m_ahead );