void RagdollComputeExactBbox( const ragdoll_t &ragdoll, const Vector &origin, Vector &outMins, Vector &outMaxs ) { outMins = origin; outMaxs = origin; for ( int i = 0; i < ragdoll.listCount; i++ ) { Vector mins, maxs; Vector objectOrg; QAngle objectAng; IPhysicsObject *pObject = ragdoll.list[i].pObject; pObject->GetPosition( &objectOrg, &objectAng ); physcollision->CollideGetAABB( mins, maxs, pObject->GetCollide(), objectOrg, objectAng ); for ( int j = 0; j < 3; j++ ) { if ( mins[j] < outMins[j] ) { outMins[j] = mins[j]; } if ( maxs[j] > outMaxs[j] ) { outMaxs[j] = maxs[j]; } } } }
void CPlayerPickupController::Init( CBasePlayer *pPlayer, CBaseEntity *pObject ) { m_pPlayer = pPlayer; IPhysicsObject *pPhysics = pObject->VPhysicsGetObject(); Vector position; QAngle angles; pPhysics->GetPosition( &position, &angles ); m_grabController.SetMaxImpulse( Vector(20*100,20*100,20*100), AngularImpulse(20*180,20*180,20*180) ); m_grabController.AttachEntity( pObject, pPhysics, position, angles ); // Holster player's weapon if ( m_pPlayer->GetActiveWeapon() ) { if ( !m_pPlayer->GetActiveWeapon()->Holster() ) { Shutdown(); return; } } m_pPlayer->m_Local.m_iHideHUD |= HIDEHUD_WEAPONS; m_pPlayer->SetUseEntity( this ); matrix3x4_t tmp; ComputePlayerMatrix( tmp ); VectorITransform( position, tmp, m_positionPlayerSpace ); // UNDONE: This algorithm needs a bit more thought. REVISIT. // put the bottom of the object arms' length below eye level // get bottommost point of object Vector bottom = physcollision->CollideGetExtent( pPhysics->GetCollide(), vec3_origin, angles, Vector(0,0,-1) ); // get the real eye origin Vector playerEye = pPlayer->EyePosition(); // move target up so that bottom of object is at PLAYER_HOLD_LEVEL z in local space // float delta = PLAYER_HOLD_LEVEL_EYES - bottom.z - m_positionPlayerSpace.z; float delta = 0; // player can reach down 2ft below his feet float maxPickup = (playerEye.z + PLAYER_HOLD_LEVEL_EYES) - (pPlayer->GetAbsMins().z - PLAYER_REACH_DOWN_DISTANCE); delta = clamp( delta, pPlayer->WorldAlignMins().z, maxPickup ); m_positionPlayerSpace.z += delta; m_anglesPlayerSpace = TransformAnglesToLocalSpace( angles, tmp ); m_anglesPlayerSpace = AlignAngles( m_anglesPlayerSpace, DOT_30DEGREE ); // re-transform and check angles = TransformAnglesToWorldSpace( m_anglesPlayerSpace, tmp ); VectorTransform( m_positionPlayerSpace, tmp, position ); // hackhack: Move up to eye position for the check float saveZ = position.z; position.z = playerEye.z; CheckObjectPosition( position, angles, position ); // move back to original position position.z = saveZ; VectorITransform( position, tmp, m_positionPlayerSpace ); }
void QueueSave( CBaseEntity *pOwner, typedescription_t *pTypeDesc, void **ppPhysObj, PhysInterfaceId_t type ) { if ( !pOwner ) return; bool fOnlyNotingExistence = !pOwner->ShouldSavePhysics(); QueuedItem_t item; item.ppPhysObj = ppPhysObj; item.header.hEntity = pOwner; item.header.type = type; item.header.nObjects = ( !fOnlyNotingExistence ) ? pTypeDesc->fieldSize : 0; item.header.fieldName = AllocPooledString( pTypeDesc->fieldName ); // A pooled string is used here because there is no way // right now to save a non-string_t string and have it // compressed in the save symbol tables. Furthermore, // the field name would normally be in the string // pool anyway. (toml 12-10-02) item.header.modelName = NULL_STRING; memset( &item.header.bbox, 0, sizeof( item.header.bbox ) ); item.header.sphere.radius = 0; if ( !fOnlyNotingExistence && type == PIID_IPHYSICSOBJECT ) { // Don't doing the box thing for things like wheels on cars IPhysicsObject *pPhysObj = (IPhysicsObject *)(*ppPhysObj); if ( pPhysObj ) { item.header.modelName = GetModelName( pPhysObj ); item.header.iCollide = physcollision->CollideIndex( pPhysObj->GetCollide() ); if ( item.header.modelName == NULL_STRING ) { BBox_t *pBBox = GetBBox( pPhysObj ); if ( pBBox != NULL ) { item.header.bbox = *pBBox; } else { if ( pPhysObj && pPhysObj->GetSphereRadius() != 0 ) { item.header.sphere.radius = pPhysObj->GetSphereRadius(); } else { DevMsg( "Don't know how to save model for physics object (class \"%s\")\n", pOwner->GetClassname() ); } } } } } m_QueuedSaves.Insert( item ); }
void CBoneFollower::SetObjectCollisionBox( void ) { Vector absmins, absmaxs; IPhysicsObject *pPhysics = VPhysicsGetObject(); if ( pPhysics ) { physcollision->CollideGetAABB( absmins, absmaxs, pPhysics->GetCollide(), GetAbsOrigin(), GetAbsAngles() ); SetAbsMins( absmins ); SetAbsMaxs( absmaxs ); } }
//----------------------------------------------------------------------------- // Expand trigger bounds.. //----------------------------------------------------------------------------- void CCollisionProperty::ComputeVPhysicsSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs ) { bool bSetBounds = false; IPhysicsObject *pPhysicsObject = GetOuter()->VPhysicsGetObject(); if ( pPhysicsObject ) { if ( pPhysicsObject->GetCollide() ) { physcollision->CollideGetAABB( pVecWorldMins, pVecWorldMaxs, pPhysicsObject->GetCollide(), GetCollisionOrigin(), GetCollisionAngles() ); bSetBounds = true; } else if ( pPhysicsObject->GetSphereRadius( ) ) { float flRadius = pPhysicsObject->GetSphereRadius( ); Vector vecExtents( flRadius, flRadius, flRadius ); VectorSubtract( GetCollisionOrigin(), vecExtents, *pVecWorldMins ); VectorAdd( GetCollisionOrigin(), vecExtents, *pVecWorldMaxs ); bSetBounds = true; } } if ( !bSetBounds ) { *pVecWorldMins = GetCollisionOrigin(); *pVecWorldMaxs = *pVecWorldMins; } // Also, lets expand for the trigger bounds also if ( IsSolidFlagSet( FSOLID_USE_TRIGGER_BOUNDS ) ) { Vector vecWorldTriggerMins, vecWorldTriggerMaxs; WorldSpaceTriggerBounds( &vecWorldTriggerMins, &vecWorldTriggerMaxs ); VectorMin( vecWorldTriggerMins, *pVecWorldMins, *pVecWorldMins ); VectorMax( vecWorldTriggerMaxs, *pVecWorldMaxs, *pVecWorldMaxs ); } }
bool CStatueProp::TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr ) { IPhysicsObject *pPhysObject = VPhysicsGetObject(); if ( pPhysObject ) { Vector vecPosition; QAngle vecAngles; pPhysObject->GetPosition( &vecPosition, &vecAngles ); const CPhysCollide *pScaledCollide = pPhysObject->GetCollide(); physcollision->TraceBox( ray, pScaledCollide, vecPosition, vecAngles, &tr ); return tr.DidHit(); } return false; }
bool CBoneFollower::Init( CBaseEntity *pOwner, const char *pModelName, solid_t &solid, const Vector &position, const QAngle &orientation ) { SetOwnerEntity( pOwner ); UTIL_SetModel( this, pModelName ); AddEffects( EF_NODRAW ); // invisible m_modelIndex = modelinfo->GetModelIndex( pModelName ); m_solidIndex = solid.index; SetAbsOrigin( position ); SetAbsAngles( orientation ); SetMoveType( MOVETYPE_PUSH ); SetSolid( SOLID_VPHYSICS ); SetCollisionGroup( pOwner->GetCollisionGroup() ); AddSolidFlags( FSOLID_CUSTOMRAYTEST | FSOLID_CUSTOMBOXTEST ); solid.params.pGameData = (void *)this; IPhysicsObject *pPhysics = VPhysicsInitShadow( false, false, &solid ); if ( !pPhysics ) return false; // we can't use the default model bounds because each entity is only one bone of the model // so compute the OBB of the physics model and use that. Vector mins, maxs; physcollision->CollideGetAABB( &mins, &maxs, pPhysics->GetCollide(), vec3_origin, vec3_angle ); SetCollisionBounds( mins, maxs ); pPhysics->SetCallbackFlags( pPhysics->GetCallbackFlags() | CALLBACK_GLOBAL_TOUCH ); pPhysics->EnableGravity( false ); // This is not a normal shadow controller that is trying to go to a space occupied by an entity in the game physics // This entity is not running PhysicsPusher(), so Vphysics is supposed to move it // This line of code informs vphysics of that fact if ( pOwner->IsNPC() ) { pPhysics->GetShadowController()->SetPhysicallyControlled( true ); } return true; }
//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- bool CGrabController::UpdateObject( CBasePlayer *pPlayer, float flError ) { CBaseEntity *pEntity = GetAttached(); if ( !pEntity || ComputeError() > flError || pPlayer->GetGroundEntity() == pEntity || !pEntity->VPhysicsGetObject() ) { return false; } //Adrian: Oops, our object became motion disabled, let go! IPhysicsObject *pPhys = pEntity->VPhysicsGetObject(); if ( pPhys && pPhys->IsMoveable() == false ) { return false; } Vector forward, right, up; QAngle playerAngles = pPlayer->EyeAngles(); AngleVectors( playerAngles, &forward, &right, &up ); float pitch = AngleDistance(playerAngles.x,0); if( !m_bAllowObjectOverhead ) { playerAngles.x = clamp( pitch, -75, 75 ); } else { playerAngles.x = clamp( pitch, -90, 75 ); } // Now clamp a sphere of object radius at end to the player's bbox Vector radial = physcollision->CollideGetExtent( pPhys->GetCollide(), vec3_origin, pEntity->GetAbsAngles(), -forward ); Vector player2d = pPlayer->CollisionProp()->OBBMaxs(); float playerRadius = player2d.Length2D(); float radius = playerRadius + fabs(DotProduct( forward, radial )); float distance = 24 + ( radius * 2.0f ); // Add the prop's distance offset distance += m_flDistanceOffset; Vector start = pPlayer->Weapon_ShootPosition(); Vector end = start + ( forward * distance ); trace_t tr; CTraceFilterSkipTwoEntities traceFilter( pPlayer, pEntity, COLLISION_GROUP_NONE ); Ray_t ray; ray.Init( start, end ); enginetrace->TraceRay( ray, MASK_SOLID_BRUSHONLY, &traceFilter, &tr ); if ( tr.fraction < 0.5 ) { end = start + forward * (radius*0.5f); } else if ( tr.fraction <= 1.0f ) { end = start + forward * ( distance - radius ); } Vector playerMins, playerMaxs, nearest; pPlayer->CollisionProp()->WorldSpaceAABB( &playerMins, &playerMaxs ); Vector playerLine = pPlayer->CollisionProp()->WorldSpaceCenter(); CalcClosestPointOnLine( end, playerLine+Vector(0,0,playerMins.z), playerLine+Vector(0,0,playerMaxs.z), nearest, NULL ); if( !m_bAllowObjectOverhead ) { Vector delta = end - nearest; float len = VectorNormalize(delta); if ( len < radius ) { end = nearest + radius * delta; } } //Show overlays of radius if ( g_debug_physcannon.GetBool() ) { NDebugOverlay::Box( end, -Vector( 2,2,2 ), Vector(2,2,2), 0, 255, 0, true, 0 ); NDebugOverlay::Box( GetAttached()->WorldSpaceCenter(), -Vector( radius, radius, radius), Vector( radius, radius, radius ), 255, 0, 0, true, 0.0f ); } QAngle angles = TransformAnglesFromPlayerSpace( m_attachedAnglesPlayerSpace, pPlayer ); // If it has a preferred orientation, update to ensure we're still oriented correctly. Pickup_GetPreferredCarryAngles( pEntity, pPlayer, pPlayer->EntityToWorldTransform(), angles ); // We may be holding a prop that has preferred carry angles if ( m_bHasPreferredCarryAngles ) { matrix3x4_t tmp; ComputePlayerMatrix( pPlayer, tmp ); angles = TransformAnglesToWorldSpace( m_vecPreferredCarryAngles, tmp ); } matrix3x4_t attachedToWorld; Vector offset; AngleMatrix( angles, attachedToWorld ); VectorRotate( m_attachedPositionObjectSpace, attachedToWorld, offset ); SetTargetPosition( end - offset, angles ); return true; }