in C# by myself and a ton of tutorials and reference material (I can assure you its not a cut and paste job - thats aweful coding!)
and I implemented the collision detection code found at http://www.devmaster...uake3collision/
and it works beautifully with my renderer however when I tried to implement
gravity by tracing a ray under the player the trace never detects a collision
and if it does its returned coordinates are usually nowhere near the Z coordinate of the floor (Z axis being up and down in Quake 3 maps).
I tried to detect the Z coordinate of the floor like in the following example:
m_world.Trace( m_player.position, new Vector3f( m_player.position.X, m_player.position.Y, m_player.position.Z - 5000.0f ) );
Even though my collision detection is almost if not the same as in the link
above I'll post the code anyway. Be warned that I hadn't finished the code
yet so I didn't clean it up or do away with the "input/output" variables like described in the tutorial given above.
public float TraceRay( Vector3f inputStart, Vector3f inputEnd )
{
traceType = TraceType.Ray;
return Trace( inputStart, inputEnd );
}
public float TraceSphere( Vector3f inputStart, Vector3f inputEnd, float radius )
{
traceType = TraceType.Sphere;
traceRadius = radius;
return Trace( inputStart, inputEnd );
}
public float TraceBox( Vector3f inputStart, Vector3f inputEnd, Vector3f inputMins, Vector3f inputMaxs )
{
if( inputMins.X == 0 && inputMins.Y == 0 && inputMins.Z == 0 &&
inputMaxs.X == 0 && inputMaxs.Y == 0 && inputMaxs.Z == 0 )
{
return TraceRay( inputStart, inputEnd );
}
else
{
traceType = TraceType.Box;
traceMins = inputMins;
traceMaxs = inputMaxs;
traceExtents = new Vector3f();
traceExtents.X = -traceMins.X > traceMaxs.X ? -traceMins.X : traceMaxs.X;
traceExtents.Y = -traceMins.Y > traceMaxs.Y ? -traceMins.Y : traceMaxs.Y;
traceExtents.Z = -traceMins.Z > traceMaxs.Z ? -traceMins.Z : traceMaxs.Z;
return Trace( inputStart, inputEnd );
}
}
private float Trace( Vector3f inputStart, Vector3f inputEnd )
{
outputEnd = new Vector3f();
outputNormal = new Vector3f();
outputStartsOut = true;
outputAllSolid = false;
outputFraction = 1.0f;
CheckNode( 0, 0.0f, 1.0f, inputStart, inputEnd );
if( outputFraction == 1.0f )
{
outputEnd = inputEnd;
}
else
{
for( int i = 0; i < 3; i++ )
outputEnd[i] = inputStart[i] + outputFraction * (inputEnd[i] - inputStart[i]);
}
return outputFraction;
}
void CheckNode( int nodeIndex, float startFraction, float endFraction, Vector3f start, Vector3f end )
{
if( outputFraction < startFraction ) return;
if( nodeIndex < 0 )
{
Leaf_t leaf = m_leafs[-(nodeIndex+1)];
for( int i = 0; i < leaf.Brushes; i++ )
{
Brush_t brush = m_brushes[m_leaf_brushes[leaf.FirstBrush+i]];
if( brush.Sides > 0 && (m_textures[brush.Texture].Contents & (int)MASK_PLAYERSOLID) > 0 )
CheckBrush(brush, start, end);
}
return;
}
Node_t node = m_nodes[nodeIndex];
Plane_t plane = m_planes[node.Plane];
float startDistance = Vector3f.DotProduct( start, plane.Normal ) - plane.Distance;
float endDistance = Vector3f.DotProduct( end, plane.Normal ) - plane.Distance;
float offset = 0.0f;
if( traceType == TraceType.Ray )
offset = 0;
else if( traceType == TraceType.Sphere )
offset = traceRadius;
else if( traceType == TraceType.Box )
offset = (float)( Math.Abs( traceExtents.X * plane.Normal.X ) + Math.Abs( traceExtents.Y * plane.Normal.Y ) + Math.Abs( traceExtents.Z * plane.Normal.Z ) );
if( startDistance >= offset && endDistance >= offset )
CheckNode( node.Children[0], startFraction, endFraction, start, end );
else if ( startDistance < -offset && endDistance < -offset )
CheckNode( node.Children[1], startFraction, endFraction, start, end );
else
{
int side;
float fraction1, fraction2, middleFraction;
Vector3f middle = new Vector3f();
if( startDistance < endDistance )
{
side = 1;
float inverseDistance = 1.0f / (startDistance - endDistance);
fraction1 = (startDistance - offset + EPSILON) * inverseDistance;
fraction2 = (startDistance + offset + EPSILON) * inverseDistance;
}
else if( endDistance < startDistance )
{
side = 0;
float inverseDistance = 1.0f / (startDistance - endDistance);
fraction1 = (startDistance + offset + EPSILON) * inverseDistance;
fraction2 = (startDistance - offset - EPSILON) * inverseDistance;
}
else
{
side = 0;
fraction1 = 1.0f;
fraction2 = 0.0f;
}
if( fraction1 < 0.0f )
fraction1 = 0.0f;
else if( fraction1 > 1.0f )
fraction1 = 1.0f;
if( fraction2 < 0.0f )
fraction2 = 0.0f;
else if( fraction2 > 1.0f )
fraction2 = 1.0f;
middleFraction = startFraction + (endFraction - startFraction) * fraction1;
for( int i = 0; i < 3; i++ )
middle[i] = start[i] + fraction1 * (end[i] - start[i]);
CheckNode( node.Children[side], startFraction, middleFraction, start, middle );
middleFraction = startFraction + (endFraction - startFraction) * fraction2;
for( int i = 0; i < 3; i++ )
middle[i] = start[i] + fraction2 * (end[i] - start[i]);
CheckNode( node.Children[side^1], middleFraction, endFraction, middle, end );
}
}
void CheckBrush( Brush_t brush, Vector3f inputStart, Vector3f inputEnd )
{
float startFraction = -1.0f;
float endFraction = 1.0f;
bool startsOut = false;
bool endsOut = false;
Vector3f Normal = new Vector3f();
for( int i = 0; i < brush.Sides; i++ )
{
BrushSide_t brushSide = m_brush_sides[brush.StartingSide+i];
Plane_t plane = m_planes[brushSide.Plane];
float startDistance = 0.0f;
float endDistance = 0.0f;
if( traceType == TraceType.Ray )
{
startDistance = Vector3f.DotProduct( inputStart, plane.Normal ) - plane.Distance;
endDistance = Vector3f.DotProduct( inputEnd, plane.Normal ) - plane.Distance;
}
else if( traceType == TraceType.Sphere )
{
startDistance = Vector3f.DotProduct( inputStart, plane.Normal ) - (plane.Distance + traceRadius);
endDistance = Vector3f.DotProduct( inputEnd, plane.Normal ) - (plane.Distance + traceRadius);
}
else if( traceType == TraceType.Box )
{
Vector3f offset = new Vector3f();
for( int j = 0; i < 3; i++ )
{
if( plane.Normal[j] < 0 )
offset[j] = traceMaxs[j];
else
offset[j] = traceMins[j];
}
startDistance = ( inputStart.X + offset.X ) * plane.Normal.X +
( inputStart.Y + offset.Y ) * plane.Normal.Y +
( inputStart.Z + offset.Z ) * plane.Normal.Z -
plane.Distance;
endDistance = ( inputEnd.X + offset.X ) * plane.Normal.X +
( inputEnd.Y + offset.Y ) * plane.Normal.Y +
( inputEnd.Z + offset.Z ) * plane.Normal.Z -
plane.Distance;
}
if( startDistance > 0 )
startsOut = true;
if( endDistance > 0 )
endsOut = true;
if( startDistance > 0 && endDistance > 0 )
{
return;
}
if( startDistance <= 0 && endDistance <= 0 )
{
continue;
}
if( startDistance > endDistance )
{
float fraction = (startDistance - EPSILON) / (startDistance - endDistance);
if( fraction > startFraction )
{
startFraction = fraction;
Normal = plane.Normal;
}
}
else
{
float fraction = (startDistance + EPSILON) / (startDistance - endDistance);
if( fraction < endFraction )
endFraction = fraction;
}
}
if( startsOut == false )
{
outputStartsOut = false;
if( endsOut == false )
outputAllSolid = true;
return;
}
if( startFraction < endFraction )
{
if( startFraction > -1 && startFraction < outputFraction )
{
if( startFraction < 0 )
startFraction = 0;
outputFraction = startFraction;
outputNormal = Normal;
}
}
}
Thanks for any help!












