//------------------------------------------------------------------------ void CVehicleSeatActionRotateTurret::UpdatePartRotation(EVehicleTurretRotationType eType, float frameTime) { CRY_ASSERT( eType < eVTRT_NumRotationTypes ); const float threshold = 0.01f; if (frameTime > 0.08f) frameTime = 0.08f; CVehiclePartBase* pPart = m_rotations[eType].m_pPart; IVehiclePart* pParent = pPart->GetParent(); IActor* pActor = m_pSeat->GetPassengerActor(); float rot_dir = fsgnf(m_rotations[eType].m_action); float max_rotation = fabsf(m_rotations[eType].m_action); float rot_speed = DEG2RAD(fabsf(m_rotations[eType].m_speed)) * GetDamageSpeedMul(pPart); float delta = rot_dir * rot_speed * frameTime; delta += m_rotations[eType].m_aimAssist; delta = fmod(delta, gf_PI2); if (delta > gf_PI) delta -= gf_PI2; if (delta < -gf_PI) delta += gf_PI2; Limit( delta, -max_rotation, max_rotation); Ang3 deltaAngles(ZERO); if (eType == eVTRT_Pitch) deltaAngles.x = delta; else if (eType == eVTRT_Yaw) deltaAngles.z = delta; else CRY_ASSERT(false && "Unknown turret rotation"); Matrix34 tm = pPart->GetLocalBaseTM(); Ang3 angles = Ang3::GetAnglesXYZ(tm) + deltaAngles; float lerp = 0.f; if (eType == eVTRT_Pitch) { Vec3 yAxis = m_rotations[eVTRT_Yaw].m_pPart->GetLocalBaseTM().GetColumn1(); yAxis.z = 0.f; yAxis.normalize(); lerp = 0.5f - 0.5f * yAxis.y; Limit(lerp, 0.0f, 1.0f); } // clamp to limits if (m_rotations[eType].m_minLimitF != 0.0f || m_rotations[eType].m_maxLimit != 0.0f) { // Different clamp angles facing forwards/backwards float minLimit = m_rotations[eType].m_minLimitF + (m_rotations[eType].m_minLimitB - m_rotations[eType].m_minLimitF) * lerp; float angle = (eType == eVTRT_Pitch) ? angles.x : angles.z; if (angle > m_rotations[eType].m_maxLimit || angle < minLimit) { angle = clamp_tpl(angle, minLimit, m_rotations[eType].m_maxLimit); m_rotations[eType].m_currentValue = 0.f; if (eType == eVTRT_Pitch) angles.x = angle; else angles.z = angle; } } m_rotations[eType].m_orientation.Set(Quat::CreateRotationXYZ(angles)); m_rotations[eType].m_orientation.Update(frameTime); m_rotations[eType].m_action = 0.0f; m_rotations[eType].m_aimAssist = 0.0f; Matrix34 newTM(m_rotations[eType].m_orientation.Get().GetNormalized()); newTM.SetTranslation(tm.GetTranslation()); pPart->SetLocalBaseTM(newTM); // store world-space rotation const Matrix34 &worldTM = pPart->GetWorldTM(); m_rotations[eType].m_prevWorldQuat = Quat(worldTM); CRY_ASSERT(m_rotations[eType].m_prevWorldQuat.IsValid()); // now update the turret sound based on the calculated rotation speed UpdateRotationSound(eType, delta, frameTime); }
//------------------------------------------------------------------------ void CVehicleDamageBehaviorDetachPart::OnDamageEvent(EVehicleDamageBehaviorEvent event, const SVehicleDamageBehaviorEventParams& behaviorParams) { if (event == eVDBE_Repair) return; if (!m_detachedEntityId && behaviorParams.componentDamageRatio >= 1.0f) { CVehiclePartBase* pPart = (CVehiclePartBase*)m_pVehicle->GetPart(m_partName.c_str()); if (!pPart || !pPart->GetStatObj()) return; if (max(1.f-behaviorParams.randomness, pPart->GetDetachProbability()) < cry_random(0.0f, 1.0f)) return; IEntity* pDetachedEntity = SpawnDetachedEntity(); if (!pDetachedEntity) return; m_detachedEntityId = pDetachedEntity->GetId(); const Matrix34& partWorldTM = pPart->GetWorldTM(); pDetachedEntity->SetWorldTM(partWorldTM); MovePartToTheNewEntity(pDetachedEntity, pPart); SEntityPhysicalizeParams physicsParams; physicsParams.mass = pPart->GetMass(); physicsParams.type = PE_RIGID; physicsParams.nSlot = 0; pDetachedEntity->Physicalize(physicsParams); IPhysicalEntity* pPhysics = pDetachedEntity->GetPhysics(); if (pPhysics) { pe_params_part params; params.flagsOR = geom_collides|geom_floats; params.flagsColliderAND = ~geom_colltype3; params.flagsColliderOR = geom_colltype0; pPhysics->SetParams(¶ms); pe_action_add_constraint ac; ac.flags = constraint_inactive|constraint_ignore_buddy; ac.pBuddy = m_pVehicle->GetEntity()->GetPhysics(); ac.pt[0].Set(0,0,0); pPhysics->Action(&ac); // after 1s, remove the constraint again m_pVehicle->SetTimer(-1, 1000, this); // set the impulse const Vec3& velocity = m_pVehicle->GetStatus().vel; Vec3 baseForce = m_pVehicle->GetEntity()->GetWorldTM().TransformVector(pPart->GetDetachBaseForce()); baseForce *= cry_random(6.0f, 10.0f); pe_action_impulse actionImpulse; actionImpulse.impulse = physicsParams.mass * (velocity + baseForce); actionImpulse.angImpulse = physicsParams.mass * Vec3(cry_random(-1.0f,1.0f), cry_random(-1.0f,1.0f), cry_random(-1.0f,1.0f)); actionImpulse.iApplyTime = 1; pPhysics->Action(&actionImpulse); } // copy vehicle's material to new entity (fixes detaching parts from vehicles with different paints), // or specify the destroyed material if it exists IStatObj* pExternalStatObj = pPart->GetExternalGeometry(false); // Get undamaged external geometry (if any) IMaterial *pMaterial = pExternalStatObj ? pExternalStatObj->GetMaterial() : m_pVehicle->GetEntity()->GetMaterial(); if(event == eVDBE_VehicleDestroyed || event == eVDBE_Hit) { if (pExternalStatObj) { if (IStatObj* pStatObj = pPart->GetExternalGeometry(true)) // Try to get the destroyed, external geometry material pMaterial = pStatObj->GetMaterial(); } else if (m_pVehicle->GetDestroyedMaterial()) // If there is no external geometry, try the vehicle's destroyed material { pMaterial = m_pVehicle->GetDestroyedMaterial(); } } pDetachedEntity->SetMaterial(pMaterial); AttachParticleEffect(pDetachedEntity, m_pEffect); if (m_notifyMovement) { SVehicleMovementEventParams params; params.iValue = pPart->GetIndex(); m_pVehicle->GetMovement()->OnEvent(IVehicleMovement::eVME_PartDetached, params); } } }
void CVehicleSeatActionRotateTurret::DoUpdate(const float frameTime) { FUNCTION_PROFILER(GetISystem(), PROFILE_ACTION); if (gEnv->IsClient() && m_pVehicle->IsProbablyDistant() && !m_pVehicle->GetGameObject()->IsProbablyVisible()) return; // AI use the aim goal to control their rotation (remote usage too) if (!m_aimGoal.IsZero()) { UpdateAimGoal(); } // now update each rotation type for (int i = 0; i < eVTRT_NumRotationTypes; ++i) { if (m_rotations[i].m_pPart) { MaintainPartRotationWorldSpace((EVehicleTurretRotationType)i); } } // Cache the helper position before applying any rotation IActor* pActor = m_pSeat->GetPassengerActor(); bool checkRotation = (m_rotTestHelpers[0] && m_rotTestHelpers[1] && pActor); Vec3 oldHelperPos = checkRotation ? m_rotTestHelpers[1]->GetWorldSpaceTranslation() : Vec3(ZERO); Matrix34 oldMatrices[eVTRT_NumRotationTypes]; for (int i = 0; i < eVTRT_NumRotationTypes; ++i) { if (m_rotations[i].m_pPart) { oldMatrices[i] = m_rotations[i].m_pPart->GetLocalBaseTM(); UpdatePartRotation((EVehicleTurretRotationType)i, frameTime); } } // Check for turret collisions if (checkRotation) { // need to test the new rotations before applying them. Sweep a sphere between the two helpers and check for collisions... static IPhysicalEntity* pSkipEntities[10]; int numSkip = m_pVehicle->GetSkipEntities(pSkipEntities, 10); primitives::sphere sphere; sphere.center = m_rotTestHelpers[0]->GetWorldSpaceTranslation(); sphere.r = m_rotTestRadius; geom_contact* pContact = NULL; Vec3 dir = m_rotTestHelpers[1]->GetWorldSpaceTranslation() - sphere.center; float hit = gEnv->pPhysicalWorld->PrimitiveWorldIntersection(sphere.type, &sphere, dir, ent_static | ent_terrain | ent_rigid | ent_sleeping_rigid, &pContact, 0, (geom_colltype_player << rwi_colltype_bit) | rwi_stop_at_pierceable, 0, 0, 0, pSkipEntities, numSkip); if (hit > 0.001f && pContact) { // there was a collision. check whether the barrel is moving towards the collision point or not... if not, ignore the collision. #if ENABLE_VEHICLE_DEBUG if (VehicleCVars().v_debugdraw > 0) { CPersistantDebug* pPD = CCryAction::GetCryAction()->GetPersistantDebug(); pPD->Begin("VehicleCannon", false); ColorF col(1.0f, 0.0f, 0.0f, 1.0f); if (pContact && hit > 0.0f) { pPD->AddSphere(pContact->pt, 0.1f, col, 30.0f); } } #endif Vec3 endPos = m_rotTestHelpers[1]->GetWorldSpaceTranslation(); Vec3 moveDir = endPos - oldHelperPos; Vec3 hitDir = pContact->pt - oldHelperPos; if (moveDir.Dot(hitDir) > 0.0f) { // reset as though the rotation never happened. for (int i = 0; i < eVTRT_NumRotationTypes; ++i) { if (m_rotations[i].m_pPart) { CVehiclePartBase* pPart = m_rotations[i].m_pPart; pPart->SetLocalBaseTM(oldMatrices[i]); const Matrix34 &worldTM = pPart->GetWorldTM(); m_rotations[i].m_prevWorldQuat = Quat(worldTM); m_rotations[i].m_orientation.Set(Quat(Matrix33(oldMatrices[i]))); } } } } } m_aimGoalPriority = 0; }