OMV.Vector3 WalkUpStairs()
{
OMV.Vector3 ret = OMV.Vector3.Zero;
// This test is done if moving forward, not flying and is colliding with something.
// DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}",
// LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count);
m_physicsScene.DetailLog(
"{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4},avHeight={5}",
m_controllingPrim.TargetVelocitySpeed, m_controllingPrim.CollisionsLastTick.Count,
m_controllingPrim.Size.Z);
// Check for stairs climbing if colliding, not flying and moving forward
if (m_controllingPrim.IsColliding
&& !m_controllingPrim.Flying
&& m_controllingPrim.TargetVelocitySpeed > 0.1f)
{
// The range near the character's feet where we will consider stairs
// float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f
// Note: ther is a problem with the computation of the capsule height. Thus RawPosition is off
// from the height. Revisit size and this computation when height is scaled properly.
float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) - BSParam.AvatarStepGroundFudge;
float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight;
// look for a collision point that is near the character's feet and is oriented the same as the character is.
// find the highest 'good' collision.
OMV.Vector3 highestTouchPosition = OMV.Vector3.Zero;
// no m_objCollisionsList :(
foreach (
KeyValuePair<uint, ContactPoint> kvp in m_controllingPrim.CollisionsLastTick.GetCollisionEvents())
{
// Don't care about collisions with the terrain
if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID)
{
OMV.Vector3 touchPosition = kvp.Value.Position;
// DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}",
// LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition);
if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax)
{
// This contact is within the 'near the feet' range.
// The normal should be our contact point to the object so it is pointing away
// thus the difference between our facing orientation and the normal should be small.
OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation;
OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal);
const float PIOver2 = 1.571f; // Used to make unit vector axis into approx radian angles
// m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,avNormal={1},colNormal={2},diff={3}",
// m_controllingPrim.LocalID, directionFacing, touchNormal,
// Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)) );
if ((Math.Abs(directionFacing.Z) * PIOver2) < BSParam.AvatarStepAngle
&& (Math.Abs(touchNormal.Z) * PIOver2) < BSParam.AvatarStepAngle)
{
// The normal should be our contact point to the object so it is pointing away
// thus the difference between our facing orientation and the normal should be small.
float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal));
if (diff < BSParam.AvatarStepApproachFactor)
{
if (highestTouchPosition.Z < touchPosition.Z)
highestTouchPosition = touchPosition;
}
}
}
}
}
m_walkingUpStairs = 0;
// If there is a good step sensing, move the avatar over the step.
if (highestTouchPosition != OMV.Vector3.Zero)
{
// Remember that we are going up stairs. This is needed because collisions
// will stop when we move up so this smoothes out that effect.
m_walkingUpStairs = BSParam.AvatarStepSmoothingSteps;
m_lastStepUp = highestTouchPosition.Z - nearFeetHeightMin;
ret = ComputeStairCorrection(m_lastStepUp);
m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},ret={3}",
m_controllingPrim.LocalID, highestTouchPosition, nearFeetHeightMin, ret);
}
} else
{
// If we used to be going up stairs but are not now, smooth the case where collision goes away while
// we are bouncing up the stairs.
if (m_walkingUpStairs > 0)
{
m_walkingUpStairs--;
ret = ComputeStairCorrection(m_lastStepUp);
}
}
return ret;
}