//----------------------------------------------------------------------------- // Purpose: Grenades aren't solid to players, so players don't get stuck on // them when they're lying on the ground. We still want thrown grenades // to bounce of players though, so manually trace ahead and see if we'd // hit something that we'd like the grenade to "collide" with. //----------------------------------------------------------------------------- void CTFWeaponBaseGrenadeProj::VPhysicsUpdate( IPhysicsObject *pPhysics ) { BaseClass::VPhysicsUpdate( pPhysics ); Vector vel; AngularImpulse angVel; pPhysics->GetVelocity( &vel, &angVel ); Vector start = GetAbsOrigin(); // find all entities that my collision group wouldn't hit, but COLLISION_GROUP_NONE would and bounce off of them as a ray cast CTraceFilterCollisionGrenades filter( this, GetThrower() ); trace_t tr; UTIL_TraceLine( start, start + vel * gpGlobals->frametime, CONTENTS_HITBOX|CONTENTS_MONSTER|CONTENTS_SOLID, &filter, &tr ); bool bHitEnemy = false; if ( tr.m_pEnt && tr.m_pEnt->GetTeamNumber() != GetTeamNumber() ) { bHitEnemy = true; } if ( tr.startsolid ) { if ( (m_bInSolid == false && m_bCollideWithTeammates == true) || ( m_bInSolid == false && bHitEnemy == true ) ) { // UNDONE: Do a better contact solution that uses relative velocity? vel *= -GRENADE_COEFFICIENT_OF_RESTITUTION; // bounce backwards pPhysics->SetVelocity( &vel, NULL ); } m_bInSolid = true; return; } m_bInSolid = false; if ( tr.DidHit() ) { Touch( tr.m_pEnt ); if ( m_bCollideWithTeammates == true || bHitEnemy == true ) { // reflect velocity around normal vel = -2.0f * tr.plane.normal * DotProduct(vel,tr.plane.normal) + vel; // absorb 80% in impact vel *= GetElasticity(); if ( bHitEnemy == true ) { vel *= 0.5f; } angVel *= -0.5f; pPhysics->SetVelocity( &vel, &angVel ); } } }
void CBaseGrenadeProjectile::ResolveFlyCollisionCustom( trace_t &trace, Vector &vecVelocity ) { //Assume all surfaces have the same elasticity float flSurfaceElasticity = 1.0; //Don't bounce off of players with perfect elasticity if( trace.m_pEnt && trace.m_pEnt->IsPlayer() ) { flSurfaceElasticity = 0.3; } // if its breakable glass and we kill it, don't bounce. // give some damage to the glass, and if it breaks, pass // through it. bool breakthrough = false; if( trace.m_pEnt && FClassnameIs( trace.m_pEnt, "func_breakable" ) ) { breakthrough = true; } if( trace.m_pEnt && FClassnameIs( trace.m_pEnt, "func_breakable_surf" ) ) { breakthrough = true; } if (breakthrough) { CTakeDamageInfo info( this, this, 10, DMG_CLUB ); trace.m_pEnt->DispatchTraceAttack( info, GetAbsVelocity(), &trace ); ApplyMultiDamage(); if( trace.m_pEnt->m_iHealth <= 0 ) { // slow our flight a little bit Vector vel = GetAbsVelocity(); vel *= 0.4; SetAbsVelocity( vel ); return; } } float flTotalElasticity = GetElasticity() * flSurfaceElasticity; flTotalElasticity = clamp( flTotalElasticity, 0.0f, 0.9f ); // NOTE: A backoff of 2.0f is a reflection Vector vecAbsVelocity; PhysicsClipVelocity( GetAbsVelocity(), trace.plane.normal, vecAbsVelocity, 2.0f ); vecAbsVelocity *= flTotalElasticity; // Get the total velocity (player + conveyors, etc.) VectorAdd( vecAbsVelocity, GetBaseVelocity(), vecVelocity ); float flSpeedSqr = DotProduct( vecVelocity, vecVelocity ); // Stop if on ground. if ( trace.plane.normal.z > 0.7f ) // Floor { // Verify that we have an entity. CBaseEntity *pEntity = trace.m_pEnt; Assert( pEntity ); SetAbsVelocity( vecAbsVelocity ); if ( flSpeedSqr < ( 30 * 30 ) ) { if ( pEntity->IsStandable() ) { SetGroundEntity( pEntity ); } // Reset velocities. SetAbsVelocity( vec3_origin ); SetLocalAngularVelocity( vec3_angle ); //align to the ground so we're not standing on end QAngle angle; VectorAngles( trace.plane.normal, angle ); // rotate randomly in yaw angle[1] = random->RandomFloat( 0, 360 ); // TODO: rotate around trace.plane.normal SetAbsAngles( angle ); } else { Vector vecDelta = GetBaseVelocity() - vecAbsVelocity; Vector vecBaseDir = GetBaseVelocity(); VectorNormalize( vecBaseDir ); float flScale = vecDelta.Dot( vecBaseDir ); VectorScale( vecAbsVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, vecVelocity ); VectorMA( vecVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, GetBaseVelocity() * flScale, vecVelocity ); PhysicsPushEntity( vecVelocity, &trace ); } } else { // If we get *too* slow, we'll stick without ever coming to rest because // we'll get pushed down by gravity faster than we can escape from the wall. if ( flSpeedSqr < ( 30 * 30 ) ) { // Reset velocities. SetAbsVelocity( vec3_origin ); SetLocalAngularVelocity( vec3_angle ); } else { SetAbsVelocity( vecAbsVelocity ); } } BounceSound(); }