mirror of
https://github.com/alliedmodders/hl2sdk.git
synced 2025-09-20 04:26:03 +08:00
Added original SDK code for Alien Swarm.
This commit is contained in:
376
game/client/particle_collision.cpp
Normal file
376
game/client/particle_collision.cpp
Normal file
@ -0,0 +1,376 @@
|
||||
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Local fast collision system for particles
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "particle_collision.h"
|
||||
#include "engine/IVDebugOverlay.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#ifdef _XBOX
|
||||
#define __DEBUG_PARTICLE_COLLISION_RETEST 0
|
||||
#else
|
||||
#define __DEBUG_PARTICLE_COLLISION_RETEST 1
|
||||
#endif // _XBOX
|
||||
|
||||
#define __DEBUG_PARTICLE_COLLISION_OVERLAY 0
|
||||
#define __DEBUG_PARTICLE_COLLISION_OVERLAY_LIFETIME 0.1f
|
||||
|
||||
#define NUM_DISCREET_STEPS 8.0f
|
||||
#define NUM_SIMULATION_SECONDS 2.0f
|
||||
|
||||
#define COLLISION_EPSILON 0.01f
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseSimpleCollision::CBaseSimpleCollision( void )
|
||||
{
|
||||
ClearActivePlanes();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : &origin -
|
||||
// radius -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseSimpleCollision::Setup( const Vector &origin, float speed, float gravity )
|
||||
{
|
||||
TestForPlane( origin, Vector( 1, 0, 0 ), speed, gravity );
|
||||
TestForPlane( origin, Vector( -1, 0, 0 ), speed, gravity );
|
||||
TestForPlane( origin, Vector( 0, 1, 0 ), speed, gravity );
|
||||
TestForPlane( origin, Vector( 0, -1, 0 ), speed, gravity );
|
||||
TestForPlane( origin, Vector( 0, 0, 1 ), speed, gravity );
|
||||
TestForPlane( origin, Vector( 0, 0, -1 ), speed, gravity );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Trace line for super-simplified traces
|
||||
// Input : &start - start position
|
||||
// &end - end position
|
||||
// *pTrace - trace structure to fill
|
||||
// coarse - tests again with a real trace unless coarse is set
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseSimpleCollision::TraceLine( const Vector &start, const Vector &end, trace_t *pTrace, bool coarse )
|
||||
{
|
||||
//Iterate over all active planes
|
||||
for ( int i = 0; i < m_nActivePlanes; i++ )
|
||||
{
|
||||
//Must be a valid plane
|
||||
if ( m_collisionPlanes[i].m_Dist == -1.0f )
|
||||
continue;
|
||||
|
||||
//Get our information about the relation to this plane
|
||||
float dot1 = m_collisionPlanes[i].DistTo(start);
|
||||
float dot2 = m_collisionPlanes[i].DistTo(end);
|
||||
|
||||
//Don't consider particles on the backside of planes
|
||||
if ( dot1 < -COLLISION_EPSILON )
|
||||
continue;
|
||||
|
||||
//Must be crossing the plane's boundary
|
||||
if ( ( dot1 > COLLISION_EPSILON ) == ( dot2 > COLLISION_EPSILON ) )
|
||||
continue;
|
||||
|
||||
//Find the intersection point
|
||||
float t = dot1 / (dot1 - dot2);
|
||||
Vector vIntersection = start + (end - start) * t;
|
||||
|
||||
//Fake the collision info
|
||||
pTrace->endpos = vIntersection;
|
||||
pTrace->fraction = t - COLLISION_EPSILON;
|
||||
pTrace->plane.normal = m_collisionPlanes[i].m_Normal;
|
||||
pTrace->plane.dist = m_collisionPlanes[i].m_Dist;
|
||||
|
||||
//If we need an exact trace, test again on a successful hit
|
||||
if ( ( coarse == false ) && ( pTrace->fraction < 1.0f ) )
|
||||
{
|
||||
UTIL_TraceLine( start, end, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, pTrace );
|
||||
}
|
||||
|
||||
#if __DEBUG_PARTICLE_COLLISION_OVERLAY
|
||||
debugoverlay->AddBoxOverlay( vIntersection, Vector(-1,-1,-1), Vector(1,1,1), QAngle(0,0,0), 0, 255, 0, 16, __DEBUG_PARTICLE_COLLISION_OVERLAY_LIFETIME );
|
||||
#endif //__DEBUG_PARTICLE_COLLISION_OVERLAY
|
||||
|
||||
//Done
|
||||
return;
|
||||
}
|
||||
|
||||
//Fell through, so clear all the fields
|
||||
pTrace->plane.normal[0] = 0.0f;
|
||||
pTrace->plane.normal[1] = 0.0f;
|
||||
pTrace->plane.normal[2] = 0.0f;
|
||||
pTrace->plane.dist = 0.0f;
|
||||
pTrace->fraction = 1.0f;
|
||||
pTrace->allsolid = false;
|
||||
pTrace->startsolid = false;
|
||||
pTrace->m_pEnt = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Tests the planes against all others for validity
|
||||
// Input : *plane - plane to test
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseSimpleCollision::ConsiderPlane( cplane_t *plane )
|
||||
{
|
||||
//Test against all other active planes
|
||||
for ( int i = 0; i < m_nActivePlanes; i++ )
|
||||
{
|
||||
if ( m_collisionPlanes[i].m_Dist != -1.0f )
|
||||
{
|
||||
//Test for coplanar
|
||||
if ( ( m_collisionPlanes[i].m_Normal == plane->normal ) && ( m_collisionPlanes[i].m_Dist == plane->dist ) )
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Don't overrun
|
||||
if ( m_nActivePlanes >= MAX_COLLISION_PLANES )
|
||||
return;
|
||||
|
||||
//Take it
|
||||
m_collisionPlanes[m_nActivePlanes].m_Dist = plane->dist;
|
||||
m_collisionPlanes[m_nActivePlanes].m_Normal = plane->normal;
|
||||
m_nActivePlanes++;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Runs a simulation of the average particle's movement, looking for collisions along the way
|
||||
// Input : &start - start of the simulation
|
||||
// &dir - direction of travel
|
||||
// speed - speed of the particle
|
||||
// gravity - gravity being used
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseSimpleCollision::TestForPlane( const Vector &start, const Vector &dir, float speed, float gravity )
|
||||
{
|
||||
trace_t tr;
|
||||
Vector testStart, testEnd;
|
||||
|
||||
testStart = start;
|
||||
|
||||
//Setup our step increments
|
||||
float dStepTime = (NUM_SIMULATION_SECONDS/NUM_DISCREET_STEPS);
|
||||
Vector vStepIncr = dir * ( speed * dStepTime );
|
||||
float flGravIncr = gravity*dStepTime;
|
||||
|
||||
//Simulate collsions in discreet steps
|
||||
for ( int i = 1; i <= NUM_DISCREET_STEPS; i++ )
|
||||
{
|
||||
testEnd = testStart + vStepIncr;
|
||||
testEnd[2] -= flGravIncr * (0.5f*(dStepTime*i)*(dStepTime*i) );
|
||||
|
||||
//Trace the line
|
||||
UTIL_TraceLine( testStart, testEnd, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr );
|
||||
|
||||
//See if we found one
|
||||
if ( tr.fraction != 1.0f )
|
||||
{
|
||||
#if __DEBUG_PARTICLE_COLLISION_OVERLAY
|
||||
debugoverlay->AddLineOverlay( testStart, tr.endpos, 255, 0, 0, true, __DEBUG_PARTICLE_COLLISION_OVERLAY_LIFETIME );
|
||||
|
||||
QAngle angles;
|
||||
|
||||
VectorAngles( tr.plane.normal,angles );
|
||||
angles[PITCH] += 90;
|
||||
|
||||
debugoverlay->AddBoxOverlay( tr.endpos, Vector(-64,-64,0), Vector(64,64,0), angles, 255, 0, 0, 16, __DEBUG_PARTICLE_COLLISION_OVERLAY_LIFETIME );
|
||||
#endif //__DEBUG_PARTICLE_COLLISION_OVERLAY
|
||||
|
||||
//Test the plane against a set of criteria
|
||||
ConsiderPlane( &tr.plane );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//We missed
|
||||
#if __DEBUG_PARTICLE_COLLISION_OVERLAY
|
||||
debugoverlay->AddLineOverlay( testStart, tr.endpos, 0, 128.0f+(128.0f*((float)i/(float)NUM_DISCREET_STEPS)), 0, true, __DEBUG_PARTICLE_COLLISION_OVERLAY_LIFETIME );
|
||||
#endif //__DEBUG_PARTICLE_COLLISION_OVERLAY
|
||||
|
||||
//Save that position for the next round
|
||||
testStart = testEnd;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseSimpleCollision::ClearActivePlanes( void )
|
||||
{
|
||||
for ( int i = 0; i < MAX_COLLISION_PLANES; i++ )
|
||||
{
|
||||
m_collisionPlanes[i].m_Dist = -1.0f;
|
||||
m_collisionPlanes[i].m_Normal.Init();
|
||||
}
|
||||
|
||||
m_nActivePlanes = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// CParticleCollision
|
||||
//
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CParticleCollision::CParticleCollision( void )
|
||||
{
|
||||
m_flGravity = 800.0f;
|
||||
m_flCollisionDampen = 0.5f;
|
||||
m_flAngularCollisionDampen = 0.25f;
|
||||
|
||||
ClearActivePlanes();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Test for surrounding collision surfaces for quick collision testing for the particle system
|
||||
// Input : &origin - starting position
|
||||
// *dir - direction of movement (if NULL, will do a point emission test in four directions)
|
||||
// angularSpread - looseness of the spread
|
||||
// minSpeed - minimum speed
|
||||
// maxSpeed - maximum speed
|
||||
// gravity - particle gravity for the sytem
|
||||
// dampen - dampening amount on collisions
|
||||
//-----------------------------------------------------------------------------
|
||||
void CParticleCollision::Setup( const Vector &origin, const Vector *dir, float angularSpread, float minSpeed, float maxSpeed, float gravity, float dampen )
|
||||
{
|
||||
//Take the information for this simulation
|
||||
m_flGravity = gravity;
|
||||
m_flCollisionDampen = dampen;
|
||||
m_nActivePlanes = 0;
|
||||
|
||||
//We take a rough estimation of the spray
|
||||
float speedAvg = (minSpeed+maxSpeed)*0.5f;
|
||||
|
||||
//Point or directed?
|
||||
if ( dir == NULL )
|
||||
{
|
||||
//Test all around
|
||||
TestForPlane( origin, Vector( 1, 0, 0 ), speedAvg, gravity );
|
||||
TestForPlane( origin, Vector( -1, 0, 0 ), speedAvg, gravity );
|
||||
TestForPlane( origin, Vector( 0, 1, 0 ), speedAvg, gravity );
|
||||
TestForPlane( origin, Vector( 0, -1, 0 ), speedAvg, gravity );
|
||||
TestForPlane( origin, Vector( 0, 0, 1 ), speedAvg, gravity );
|
||||
TestForPlane( origin, Vector( 0, 0, -1 ), speedAvg, gravity );
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector vSkewDir, vRight;
|
||||
QAngle vAngles;
|
||||
|
||||
//FIXME: Quicker conversion?
|
||||
//FIXME: We need to factor in the angular spread instead
|
||||
VectorAngles( *dir, vAngles );
|
||||
AngleVectors( vAngles, NULL, &vRight, NULL );
|
||||
|
||||
//Test straight
|
||||
TestForPlane( origin, *dir, speedAvg, gravity );
|
||||
|
||||
vSkewDir = vRight;
|
||||
|
||||
//Test right
|
||||
TestForPlane( origin, vSkewDir, speedAvg, gravity );
|
||||
|
||||
vSkewDir *= -1.0f;
|
||||
|
||||
//Test left
|
||||
TestForPlane( origin, vSkewDir, speedAvg, gravity );
|
||||
|
||||
#if __DEBUG_PARTICLE_COLLISION_OVERLAY
|
||||
DevMsg( 1, "CParticleCollision: Found %d active plane(s)\n", m_nActivePlanes );
|
||||
#endif //__DEBUG_PARTICLE_COLLISION_OVERLAY
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Simulate movement, with collision
|
||||
// Input : &origin - position of the particle
|
||||
// &velocity - velocity of the particle
|
||||
// &rollDelta - roll delta of the particle
|
||||
// timeDelta - time step
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CParticleCollision::MoveParticle( Vector &origin, Vector &velocity, float *rollDelta, float timeDelta, trace_t *pTrace )
|
||||
{
|
||||
//Don't bother with non-moving particles
|
||||
if ( velocity == vec3_origin )
|
||||
return false;
|
||||
|
||||
//Factor in gravity
|
||||
velocity[2] -= m_flGravity * timeDelta;
|
||||
|
||||
//Move
|
||||
Vector testPosition = ( origin + ( velocity * timeDelta ) );
|
||||
|
||||
//Only collide if we have active planes
|
||||
if ( m_nActivePlanes > 0 )
|
||||
{
|
||||
//Collide
|
||||
TraceLine( origin, testPosition, pTrace );
|
||||
|
||||
//See if we hit something
|
||||
if ( pTrace->fraction != 1.0f )
|
||||
{
|
||||
#if __DEBUG_PARTICLE_COLLISION_RETEST
|
||||
//Retest the collision with a true trace line to avoid errant collisions
|
||||
UTIL_TraceLine( origin, testPosition, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, pTrace );
|
||||
#endif //__DEBUG_RETEST_COLLISION
|
||||
|
||||
//Did we hit anything?
|
||||
if ( pTrace->fraction != 1.0f )
|
||||
{
|
||||
//See if we've settled
|
||||
if ( ( pTrace->plane.normal[2] >= 0.5f ) && ( fabs( velocity[2] ) <= 48.0f ) )
|
||||
{
|
||||
//Leave the particle at the collision point
|
||||
origin += velocity * ( (pTrace->fraction-COLLISION_EPSILON) * timeDelta );
|
||||
|
||||
//Stop the particle
|
||||
velocity = vec3_origin;
|
||||
|
||||
if ( rollDelta != NULL )
|
||||
{
|
||||
*rollDelta = 0.0f;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Move the particle to the collision point
|
||||
origin += velocity * ( (pTrace->fraction-COLLISION_EPSILON) * timeDelta );
|
||||
|
||||
//Find the reflection vector
|
||||
float proj = velocity.Dot( pTrace->plane.normal );
|
||||
velocity += pTrace->plane.normal * (-proj*2.0f);
|
||||
|
||||
//Apply dampening
|
||||
velocity *= random->RandomFloat( (m_flCollisionDampen-0.1f), (m_flCollisionDampen+0.1f) );
|
||||
|
||||
//Dampen the roll of the particles
|
||||
if ( rollDelta != NULL )
|
||||
{
|
||||
(*rollDelta) *= -0.25f;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if __DEBUG_PARTICLE_COLLISION_OVERLAY
|
||||
//Display a false hit
|
||||
debugoverlay->AddBoxOverlay( pTrace->endpos, Vector(-1,-1,-1), Vector(1,1,1), QAngle(0,0,0), 255, 0, 0, 16, __DEBUG_PARTICLE_COLLISION_OVERLAY_LIFETIME );
|
||||
#endif //__DEBUG_PARTICLE_COLLISION_OVERLAY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Simple move, no collision
|
||||
origin = testPosition;
|
||||
|
||||
return false;
|
||||
}
|
Reference in New Issue
Block a user