void CBaseGrabHandler::IgnoreCollision(EntityId eID,unsigned int flags,bool ignore) { IEntity *pGrab = gEnv->pEntitySystem->GetEntity(eID); IPhysicalEntity *ppGrab = pGrab ? pGrab->GetPhysics() : NULL; if(!ppGrab) return; if(ignore) { // NOTE Dez 14, 2006: <pvl> this whole block just fills in // a request structure and passes it to physics IEntity *pEnt = m_pActor->GetEntity(); pe_action_add_constraint ac; ac.flags = constraint_inactive|constraint_ignore_buddy; ac.pBuddy = pEnt->GetPhysics(); ac.pt[0].Set(0,0,0); ICharacterInstance *pCharacter = pEnt->GetCharacter(0); IPhysicalEntity *pPhysEnt = pCharacter?pCharacter->GetISkeletonPose()->GetCharacterPhysics(-1):NULL; if(pPhysEnt) { pe_simulation_params sp; pPhysEnt->GetParams(&sp); if(sp.iSimClass <= 2) ac.pBuddy = pPhysEnt; } ppGrab->Action(&ac); } else { // NOTE Dez 14, 2006: <pvl> the same as the other branch - just // fill in a request and pass it to the physics engine pe_action_update_constraint uc; uc.bRemove = 1; ppGrab->Action(&uc); } // NOTE Dez 14, 2006: <pvl> flag manipulation is basically a legacy // code - probably not used anymore, scheduled for removal. if(flags) { pe_params_part pp; pp.flagsAND = pp.flagsColliderAND = ~flags; pp.flagsOR = pp.flagsColliderOR = flags * (ignore?0:1); pe_status_nparts status_nparts; for(pp.ipart = ppGrab->GetStatus(&status_nparts)-1; pp.ipart>=0; pp.ipart--) ppGrab->SetParams(&pp); } }
void CIntersectionAssistanceUnit::OnDetectObjectEmbedded() { m_embedState = eES_Embedded; // How do we react to the bad news? if(m_resolutionPolicy == eRP_DeleteObject) { CGameRules *pGameRules=g_pGame->GetGameRules(); assert(pGameRules); if (pGameRules) { pGameRules->ScheduleEntityRemoval(m_subjectEntityId, 0.0f, true); } } else { IEntity* pEntity = gEnv->pEntitySystem->GetEntity(m_subjectEntityId); if(pEntity) { IPhysicalEntity* pPhysical = pEntity->GetPhysics(); if(pPhysical) { // Force entity to sleep (for now) pe_action_awake pa; pa.bAwake = 0; pPhysical->Action( &pa ); } } } }
bool CBaseGrabHandler::StartDrop() { IEntity *pGrab = gEnv->pEntitySystem->GetEntity(m_grabStats.grabId); IPhysicalEntity *pGrabPhys = pGrab ? pGrab->GetPhysics() : NULL; if (pGrabPhys && m_grabStats.throwVector.len2()>0.01f) { pe_action_set_velocity asv; asv.v = m_grabStats.throwVector; asv.w.x = -1.0f + (cry_rand()/(float)RAND_MAX*(float)(2.0f)); asv.w.y = -1.0f + (cry_rand()/(float)RAND_MAX*(float)(2.0f)); asv.w.z = -1.0f + (cry_rand()/(float)RAND_MAX*(float)(2.0f)); asv.w.NormalizeSafe(); asv.w *= 2.0f; pGrabPhys->Action(&asv); } if (m_grabStats.grabId>0) { m_grabStats.dropId = m_grabStats.grabId; m_grabStats.resetFlagsDelay = 1.0f; m_pActor->CreateScriptEvent("droppedObject",(float)m_grabStats.grabId); if (pGrab) DisableGrabbedAnimatedCharacter (false); } m_grabStats.Reset(); return true; }
void CBaseGrabHandler::Update(float frameTime) { //we have to restore the grabbed object collision flag at some point after the throw. if(m_grabStats.dropId>0) { m_grabStats.resetFlagsDelay -= frameTime; if(m_grabStats.resetFlagsDelay<0.001f) { IgnoreCollision(m_grabStats.dropId,m_grabStats.collisionFlags,false); m_grabStats.dropId = 0; } } if(m_grabStats.grabId<1) return; if(m_pActor->GetHealth()<=0) { StartDrop(); return; } IEntity *pGrab = gEnv->pEntitySystem->GetEntity(m_grabStats.grabId); if(pGrab) { bool grabbing(m_grabStats.grabDelay>0.001f); if(!grabbing || m_grabStats.usingAnimation) UpdatePosVelRot(frameTime); } else { //in case the grabber lost the grabbed object, reset the ignore collision flags // FIXME Dez 14, 2006: <pvl> the following should be done by // calling IgnoreCollisions() but that function requires // id of the grabbed object => needs refactoring IPhysicalEntity *pActorPhys = m_pActor->GetEntity()->GetPhysics(); if(pActorPhys) { pe_action_update_constraint uc; uc.bRemove = 1; pActorPhys->Action(&uc); } } // TODO Sep 13, 2007: <pvl> I strongly suspect releaseIKTime is redundant now. // NOTE Sep 13, 2007: <pvl> note that all timeouts are dodgy here since there's // no guarantee that the grabbing/throwing animation starts playing immediately // after the grabbing command is issued. if(m_grabStats.releaseIKTime>0.001f && m_grabStats.grabDelay < 0.001f) m_grabStats.releaseIKTime -= frameTime; }
void CFlowConvoyNode::AwakeCoaches() //awake the physics { pe_action_awake aa; aa.bAwake=1; for (size_t i = 0; i < m_coaches.size(); ++i) { IPhysicalEntity* pPhysics = m_coaches[i].m_pEntity->GetPhysics(); pPhysics->Action(&aa); } }
void CReplayActor::OnRagdollized() { if(!m_ragdollImpulse.impulse.IsZero()) { IPhysicalEntity* pPhys = GetEntity()->GetPhysics(); CRY_ASSERT(pPhys && pPhys->GetType()==PE_ARTICULATED); pPhys->Action(&m_ragdollImpulse); } m_ragdollImpulse.impulse.zero(); }
void CReplayActor::ApplyRagdollImpulse( pe_action_impulse& impulse ) { IPhysicalEntity* pPhys = GetEntity()->GetPhysics(); if(!pPhys || pPhys->GetType()!=PE_ARTICULATED) { m_ragdollImpulse = impulse; } else { pPhys->Action(&impulse); } }
//------------------------------------------------------------------------ void CVehicleDamageBehaviorImpulse::OnDamageEvent(EVehicleDamageBehaviorEvent event, const SVehicleDamageBehaviorEventParams& behaviorParams) { if (event == eVDBE_Hit || event == eVDBE_VehicleDestroyed || event == eVDBE_ComponentDestroyed) { IEntity* pEntity = m_pVehicle->GetEntity(); CRY_ASSERT(pEntity); IPhysicalEntity* pPhysEntity = pEntity->GetPhysics(); if (!pPhysEntity) return; pe_status_dynamics dyn; pPhysEntity->GetStatus(&dyn); float vehicleMass = dyn.mass; float r = cry_random(0.0f, 2.f); float impulseForce = cry_random(m_forceMin, m_forceMax) * vehicleMass; Vec3 impulseDir(m_impulseDir); if (!m_worldSpace) impulseDir = m_pVehicle->GetEntity()->GetWorldTM().TransformVector(impulseDir); pe_action_impulse actionImpulse; Vec3& impulse = actionImpulse.impulse; Vec3& angImpulse = actionImpulse.angImpulse; impulse = impulseDir * impulseForce; angImpulse = m_pVehicle->GetEntity()->GetWorldTM().TransformVector(m_angImpulse); if (r <= 0.75f) { float r1 = cry_random(-0.35f, 0.35f); angImpulse += dyn.v * r1 * max(1.0f, dyn.w.GetLength()); angImpulse *= vehicleMass; } else { float r1 = cry_random(-0.25f, 0.25f); float r2 = cry_random(-0.5f, 0.5f); impulse.z += abs(dyn.v.y) * r1 * vehicleMass; angImpulse.x += dyn.v.y * r2 * vehicleMass * max(1.0f, dyn.w.GetLength() * 1.5f); } if (m_pImpulseLocation) actionImpulse.point = m_pImpulseLocation->GetWorldSpaceTranslation(); pPhysEntity->Action(&actionImpulse); } }
void CNetPlayerInput::UpdateInterpolation() { Vec3 desiredPosition = m_curInput.position; Vec3 desiredVelocity = m_curInput.deltaMovement * g_pGameCVars->pl_netSerialiseMaxSpeed; // Use the physics pos as the entity position is a frame behind at this point IPhysicalEntity * pent = m_pPlayer->GetEntity()->GetPhysics(); pe_status_pos psp; pent->GetStatus(&psp); Vec3 entPos = psp.pos; pe_status_living psl; psl.velGround.zero(); pent->GetStatus(&psl); float dt = gEnv->pTimer->GetFrameTime(); // New data? if (m_newInterpolation) m_lerper.AddNewPoint(m_curInput.position, desiredVelocity, entPos, m_curInput.standingOn); bool bInAirOrJumping = m_pPlayer->GetActorStats()->inAir > 0.01f || m_pPlayer->GetActorStats()->onGround < 0.01f; // Predict CNetLerper::SPrediction prediction; m_lerper.Update(gEnv->pTimer->GetFrameTime(), entPos, prediction, psl.velGround, bInAirOrJumping); // Update lerp velocity m_lerpVel = prediction.lerpVel; // Should Snap if (prediction.shouldSnap) { m_pPlayer->GetEntity()->SetPos(prediction.predictedPos); pe_action_set_velocity actionVel; actionVel.v = prediction.lerpVel; pent->Action(&actionVel); } #if !defined(_RELEASE) // Debug Draw if (g_pGameCVars->pl_debugInterpolation) m_lerper.DebugDraw(prediction, entPos, m_newInterpolation); else SAFE_DELETE(m_lerper.m_debug); #endif m_newInterpolation = false; }
//----------------------------------------------------------------------- void CSpectacularKill::DeathBlow(CActor& targetActor) { CRY_ASSERT_MESSAGE(m_isBusy, "spectacular kill should be in progress when triggering the death blow"); if (!m_isBusy) return; if (targetActor.IsDead()) return; Vec3 targetDir = targetActor.GetEntity()->GetForwardDir(); { HitInfo hitInfo; hitInfo.shooterId = m_pOwner->GetEntityId(); hitInfo.targetId = targetActor.GetEntityId(); hitInfo.damage = 99999.0f; // CERTAIN_DEATH hitInfo.dir = targetDir; hitInfo.normal = -hitInfo.dir; // this has to be in an opposite direction from the hitInfo.dir or the hit is ignored as a 'backface' hit hitInfo.type = CGameRules::EHitType::StealthKill; g_pGame->GetGameRules()->ClientHit(hitInfo); } // WARNING: RagDollize resets the entity's rotation! // [7/30/2010 davidr] FixMe: If the entity isn't dead here (because is immortal or any other reason) ragdollizing it will // leave it on an inconsistent state (usually only reproducible on debug scenarios) targetActor.GetGameObject()->SetAspectProfile(eEA_Physics, eAP_Ragdoll); // Give a small nudge in the hit direction to make the target fall over const SSpectacularKillParams* pSpectacularKillParams = GetParamsForClass(targetActor.GetEntity()->GetClass()); CRY_ASSERT(pSpectacularKillParams); if (pSpectacularKillParams && (pSpectacularKillParams->impulseScale > 0.0f) && (pSpectacularKillParams->impulseBone != -1)) { const float killDeathBlowVelocity = pSpectacularKillParams->impulseScale; // desired velocity after impulse in meters per second IPhysicalEntity* pTargetPhysics = targetActor.GetEntity()->GetPhysics(); if (pTargetPhysics) { pe_simulation_params simulationParams; pTargetPhysics->GetParams(&simulationParams); pe_action_impulse impulse; impulse.partid = pSpectacularKillParams->impulseBone; impulse.impulse = targetDir*killDeathBlowVelocity*simulationParams.mass; // RagDollize reset the entity's rotation so I have to use the value I cached earlier pTargetPhysics->Action(&impulse); } } m_deathBlowState = eDBS_Done; }
void ResetVelocity(SActivationInfo* pActInfo) { IEntity* pGraphEntity = pActInfo->pEntity; if (pGraphEntity) { IPhysicalEntity* pPhysicalEntity = pGraphEntity->GetPhysics(); if (pPhysicalEntity && pPhysicalEntity->GetType() != PE_STATIC) { pe_action_set_velocity setVel; setVel.v.zero(); setVel.w.zero(); pPhysicalEntity->Action(&setVel); } } }
void CFists::RaiseWeapon(bool raise, bool faster /*= false*/) { //Only when colliding something while running if(raise && (GetCurrentAnimState()==eFAS_RUNNING || GetCurrentAnimState()==eFAS_JUMPING) && !IsWeaponRaised()) { if((m_fm && m_fm->IsFiring())||(m_melee && m_melee->IsFiring())) return; PlayAction(g_pItemStrings->raise); SetDefaultIdleAnimation( eIGS_FirstPerson,g_pItemStrings->idle_relaxed); SetWeaponRaised(true); //Also give the player some impulse into the opposite direction CActor *pPlayer = GetOwnerActor(); Vec3 pos; if(pPlayer) { IPhysicalEntity* playerPhysics = pPlayer->GetEntity()->GetPhysics(); if(playerPhysics) { IMovementController *pMC = pPlayer->GetMovementController(); if(pMC) { SMovementState state; pMC->GetMovementState(state); pe_action_impulse impulse; impulse.iApplyTime = 1; impulse.impulse = -state.eyeDirection*600.0f; playerPhysics->Action(&impulse); pos = state.eyePosition + state.eyeDirection*0.5f; } } } GetScheduler()->TimerAction(GetCurrentAnimationTime(eIGS_FirstPerson), CSchedulerAction<EndRaiseWeaponAction>::Create(EndRaiseWeaponAction(this)), true); //Sound and FX feedback CollisionFeeback(pos,m_currentAnimState); } else if(!raise) SetWeaponRaised(false); }
void CRecoil::RecoilImpulse(const Vec3& firingPos, const Vec3& firingDir) { if (m_recoilParams.impulse > 0.f) { EntityId id = (m_pWeapon->GetHostId()) ? m_pWeapon->GetHostId() : m_pWeapon->GetOwnerId(); IEntity* pEntity = gEnv->pEntitySystem->GetEntity(id); IPhysicalEntity* pPhysicalEntity = pEntity ? pEntity->GetPhysics() : NULL; if (pPhysicalEntity) { pe_action_impulse impulse; impulse.impulse = -firingDir * m_recoilParams.impulse; impulse.point = firingPos; pPhysicalEntity->Action(&impulse); } } }
void CLocalPlayerComponent::UpdateStumble( const float frameTime ) { IEntity * pEntity = m_rPlayer.GetEntity(); IPhysicalEntity * pPhysEntity = pEntity->GetPhysics(); if ( pPhysEntity ) { pe_status_dynamics dynamics; pPhysEntity->GetStatus( &dynamics ); if ( m_playerStumble.Update( frameTime, dynamics ) ) { pe_action_impulse ai; ai.impulse = m_playerStumble.GetCurrentActionImpulse(); pPhysEntity->Action( &ai ); } } }
//------------------------------------------------------------------------ void CVehicleActionEntityAttachment::Update(const float deltaTime) { if(m_isAttached) return; IEntitySystem *pEntitySystem = gEnv->pEntitySystem; assert(pEntitySystem); IEntity *pEntity = pEntitySystem->GetEntity(m_entityId); if(!pEntity) return; IPhysicalEntity *pPhysEntity = pEntity->GetPhysics(); if(!pPhysEntity) return; pe_simulation_params paramsSim; float gravity; if(pPhysEntity->GetParams(¶msSim)) gravity = abs(paramsSim.gravity.z); else gravity = 9.82f; pe_status_dynamics dyn; if(pPhysEntity->GetStatus(&dyn)) { pe_action_impulse impulse; impulse.impulse = Matrix33(pEntity->GetWorldTM()) * Vec3(0.0f, 0.0f, 1.0f) * g_parachuteForce * gravity; impulse.impulse = impulse.impulse - dyn.v; impulse.impulse *= dyn.mass * deltaTime; impulse.iSource = 3; pPhysEntity->Action(&impulse); } m_timer -= deltaTime; if(m_timer <= 0.0f || dyn.v.z >= 0.0f) m_pVehicle->SetObjectUpdate(this, IVehicle::eVOU_NoUpdate); }
void CLivingEntitySample::OnPrePhysicsUpdate() { IEntity* pEntity = GetEntity(); IPhysicalEntity* pPhysEntity = pEntity->GetPhysics(); if ( pPhysEntity == NULL ) { return; } // The desired speed is chosen with a value within the motion capabilities // of the walk animation used for this sample. const float desiredSpeed = 1.5f; const Vec3 desiredLocalDirection = CalculateDesiredLocalDirection(); const Vec3 desiredLocalVelocity = desiredLocalDirection * desiredSpeed; const Quat worldOrientation = pEntity->GetWorldRotation(); const Vec3 desiredWorldVelocity = worldOrientation * desiredLocalVelocity; pe_action_move pam; pam.dir = desiredWorldVelocity; pPhysEntity->Action( &pam ); }
void CVehicleWeaponControlled::Update(SEntityUpdateContext& ctx, int update) { IVehicle *pVehicle = m_vehicleId ? gEnv->pGame->GetIGameFramework()->GetIVehicleSystem()->GetVehicle(m_vehicleId) : NULL; if (!m_vehicleId && GetEntity()->GetParent()) { IEntity *entity = GetEntity(); if (entity) { IEntity *parent = entity->GetParent(); if (parent) { m_vehicleId = parent->GetId(); pVehicle = gEnv->pGame->GetIGameFramework()->GetIVehicleSystem()->GetVehicle(parent->GetId()); } } } if (pVehicle) { IVehiclePart *pPart = pVehicle->GetWeaponParentPart(GetEntityId()); if(pPart) { if(IVehiclePart *pParentPart = pPart->GetParent()) { CRY_ASSERT(pVehicle->GetEntity()); if(ICharacterInstance *characterInst = pVehicle->GetEntity()->GetCharacter(pParentPart->GetSlot())) { if(ISkeletonPose* pose = characterInst->GetISkeletonPose()) { IDefaultSkeleton& rIDefaultSkeleton = characterInst->GetIDefaultSkeleton(); int16 joint = rIDefaultSkeleton.GetJointIDByName(pPart->GetName()); const QuatT &jQuat = pose->GetAbsJointByID(joint); Matrix34 localT(jQuat); localT.SetTranslation(jQuat.t/* - Vec3(0.0f, 0.75f, 0.0f)*/); Matrix34 vehicleWorldTm = pVehicle->GetEntity()->GetWorldTM(); Matrix34 mat = vehicleWorldTm * localT; Vec3 vehicleSide2 = pPart->GetParent()->GetLocalTM(true, true).GetTranslation(); CPlayer *pl = this->GetOwnerPlayer(); Matrix33 mat2; if (!m_destination.IsEquivalent(ZERO)) { Vec3 diff = GetDestination() - mat.GetTranslation(); //pPart->GetWorldTM().GetTranslation(); diff.Normalize(); Matrix33 loc(mat); loc.Invert(); Vec3 diffLocal = loc.TransformVector(diff); Matrix33 desMat; desMat.SetRotationVDir(diffLocal, 0.0f); Vec3 test = GetEntity()->GetLocalTM().GetColumn0(); Ang3 testTM(desMat); float za = testTM.x - m_Angles.x; za = (za < 0.0f) ? -gf_PI : gf_PI; za *= 0.05f * ctx.fFrameTime; m_Angles.x += za; Limit(m_Angles.x, -gf_PI * 0.33f, gf_PI * 0.33f); if (testTM.z > m_Angles.z + 0.05f) { m_Angles.z += gf_PI * factor1 * ctx.fFrameTime; } else if (testTM.z < m_Angles.z - 0.05f) { m_Angles.z -= gf_PI * factor1 * ctx.fFrameTime; } else { m_Angles.z = testTM.z; } Limit(m_Angles.z, -gf_PI * 0.33f, gf_PI * 0.33f); mat2.SetRotationXYZ(m_Angles); } else { if (!m_FireBlocked) { m_Angles.x = m_Angles.x - ctx.fFrameTime * factor2 * m_Angles.x; m_Angles.z = m_Angles.z - ctx.fFrameTime * factor2 * m_Angles.z; } mat2.SetRotationXYZ(m_Angles); } mat = mat * mat2; GetEntity()->SetWorldTM(mat); if (pl) { Matrix34 worldGunMat = vehicleWorldTm * localT; if (!pl->IsDead()) { Vec3 trans = worldGunMat.GetTranslation() - worldGunMat.GetColumn2() * 0.7f; worldGunMat.SetTranslation(trans); pl->GetEntity()->SetWorldTM(worldGunMat); float dot = mat.GetColumn1().dot(worldGunMat.GetColumn0()); Update3PAnim(pl, 0.5f - dot * 0.5f, ctx.fFrameTime, mat); } else { ICharacterInstance* pCharacter = pl->GetEntity()->GetCharacter(0); int boneId = pCharacter ? pCharacter->GetIDefaultSkeleton().GetJointIDByName("Spine03") : 7; pl->LinkToMountedWeapon(0); if (IVehicleSeat* seat = pVehicle->GetSeatForPassenger(pl->GetEntityId())) { seat->Exit(false, true); } Matrix33 rot(worldGunMat); Vec3 offset(0.0f, 0.0f, 0.70f); Vec3 transformedOff = rot.TransformVector(offset); Vec3 trans = worldGunMat.GetTranslation(); trans -= transformedOff; worldGunMat.SetTranslation(trans); pl->GetEntity()->SetWorldTM(worldGunMat); pl->GetEntity()->SetPos(worldGunMat.GetTranslation()); //worldGunMat.GetTranslation()); pl->RagDollize(true); if (boneId > -1) { IPhysicalEntity *physEnt = pl->GetEntity()->GetPhysics(); if (physEnt) { pe_simulation_params simulationParams; physEnt->GetParams(&simulationParams); pe_params_pos pos; pos.pos = GetEntity()->GetPos(); physEnt->SetParams(&pos); pe_action_impulse impulse; impulse.ipart = boneId; impulse.angImpulse = Vec3(0.0f, 0.0f, 1.0f); impulse.impulse = worldGunMat.GetColumn1() * -1.5f * simulationParams.mass; physEnt->Action(&impulse); } } StopUse(GetOwnerId()); SetOwnerId(0); StopFire(); m_FireBlocked = true; } // IsDead } // pl } // pose } // characterInst } // pParentPart } // pPart } // pVehicle Base::Update(ctx, update); RequireUpdate(eIUS_General); }
void CParachute::ProcessMovement(const float deltatime) { #define MetersPerSecondToKilometersPerHour(fValue) (fValue*3.6f) #define SquareFeetToSquareMeters(fValue) (fValue*0.0929f) IPhysicalEntity* pPhysics = GetEntity()->GetPhysics(); if (!pPhysics) return; float fDeltaTime = min(deltatime,0.1f); pe_status_dynamics statusDynamics; if (!pPhysics->GetStatus(&statusDynamics)) return; ResetTextPos(); DumpVector("Velocity", &statusDynamics.v); DumpVector("AVelocity", &statusDynamics.w); DumpVector("Acceleration", &statusDynamics.a); DumpVector("WAcceleration", &statusDynamics.wa); DumpText("DeltaTime=%f",fDeltaTime); DumpText("Velocity=%f m/s",statusDynamics.v.len()); DumpText("Velocity=%f km/h",MetersPerSecondToKilometersPerHour(statusDynamics.v.len())); DumpText("Yaw=%f", m_movementAction.rotateYaw); DumpText("Pitch=%f",m_movementAction.rotatePitch); DumpText("Roll=%f", m_movementAction.rotateRoll); /* Vec3 p1 = GetEntity()->GetWorldTM().GetColumn(3); Vec3 p2 = p1 + statusDynamics.v * 10.0f; gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(p1,ColorF(1,1,0,1),p2,ColorF(1,1,0,1)); gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(p1,0.6f,ColorF(0,0,1,1));*/ if(m_movementAction.rotatePitch > 0.0f) { pe_action_impulse actionImpulse; actionImpulse.impulse = Vec3(0,0,5000*fDeltaTime); pPhysics->Action(&actionImpulse); } else if(statusDynamics.v.z < 0.0f) { for(int iCel=0; iCel<7; iCel++) { SWing *pCel = &m_aCels[iCel]; pCel->fCl = 1.0f; pCel->fCd = 1.0f; float fPosY = 0.25f; m_aCels[0].vPos = Vec3(-3.7f,fPosY,5.2f); m_aCels[1].vPos = Vec3(-2.7f,fPosY,5.7f); m_aCels[2].vPos = Vec3(-1.6f,fPosY,6.0f); m_aCels[3].vPos = Vec3(+0.0f,fPosY,6.1f); m_aCels[4].vPos = Vec3(+1.6f,fPosY,6.0f); m_aCels[5].vPos = Vec3(+2.7f,fPosY,5.7f); m_aCels[6].vPos = Vec3(+3.7f,fPosY,5.2f); m_aCels[0].fAngleX = 7.0f; m_aCels[1].fAngleX = 7.0f; m_aCels[2].fAngleX = 7.0f; m_aCels[3].fAngleX = 7.0f; m_aCels[4].fAngleX = 7.0f; m_aCels[5].fAngleX = 7.0f; m_aCels[6].fAngleX = 7.0f; if(m_movementAction.rotateYaw < 0.0f) { m_aCels[0].fCl = 1.3f; // m_aCels[1].fCl = 1.3f; // m_aCels[2].fCl = 1.2f; m_aCels[0].fCd = 2.9f; // m_aCels[1].fCd = 2.2f; // m_aCels[2].fCd = 2.1f; } else if(m_movementAction.rotateYaw > 0.0f) { // m_aCels[4].fCl = 1.2f; // m_aCels[5].fCl = 1.3f; m_aCels[6].fCl = 1.3f; // m_aCels[4].fCd = 2.1f; // m_aCels[5].fCd = 2.2f; m_aCels[6].fCd = 2.9f; } else if(m_movementAction.rotatePitch < 0.0f) { /* m_aCels[0].vPos = Vec3(-3.6f,fPosY,4.6f); m_aCels[1].vPos = Vec3(-2.6f,fPosY,5.3f); m_aCels[2].vPos = Vec3(-1.6f,fPosY,5.9f); m_aCels[0].fAngleX = -15.0f; m_aCels[1].fAngleX = -8.0f; m_aCels[2].fAngleX = 0.0f; m_aCels[4].vPos = Vec3(+1.6f,fPosY,5.9f); m_aCels[5].vPos = Vec3(+2.6f,fPosY,5.3f); m_aCels[6].vPos = Vec3(+3.6f,fPosY,4.6f); m_aCels[4].fAngleX = 0.0f; m_aCels[5].fAngleX = -8.0f; m_aCels[6].fAngleX = -15.0f;*/ m_aCels[0].fCl = 1.1f; m_aCels[1].fCl = 1.2f; m_aCels[2].fCl = 1.3f; m_aCels[0].fCd = 2.1f; m_aCels[1].fCd = 2.2f; m_aCels[2].fCd = 2.3f; m_aCels[4].fCl = 1.3f; m_aCels[5].fCl = 1.2f; m_aCels[6].fCl = 1.1f; m_aCels[4].fCd = 2.3f; m_aCels[5].fCd = 2.2f; m_aCels[6].fCd = 2.1f; } UpdateWing(pCel,0,fDeltaTime); } } }
////////////////////////////////////////////////////////////////////////// // NOTE: This function must be thread-safe. Before adding stuff contact MarcoC. void CVehicleMovementTank::ProcessMovement(const float deltaTime) { FUNCTION_PROFILER( gEnv->pSystem, PROFILE_GAME ); m_netActionSync.UpdateObject(this); CryAutoCriticalSection lk(m_lock); CVehicleMovementBase::ProcessMovement(deltaTime); if (!(m_actorId && m_isEnginePowered)) { IPhysicalEntity* pPhysics = GetPhysics(); if (m_latFriction != 1.3f) SetLatFriction(1.3f); if (m_axleFriction != m_axleFrictionMax) UpdateAxleFriction(0.f, false, deltaTime); m_action.bHandBrake = 1; m_action.pedal = 0; m_action.steer = 0; pPhysics->Action(&m_action, 1); return; } IPhysicalEntity* pPhysics = GetPhysics(); MARK_UNUSED m_action.clutch; Matrix34 worldTM( m_PhysPos.q ); worldTM.AddTranslation( m_PhysPos.pos ); const Matrix34 invWTM = worldTM.GetInvertedFast(); Vec3 localVel = invWTM.TransformVector(m_PhysDyn.v); Vec3 localW = invWTM.TransformVector(m_PhysDyn.w); float speed = m_PhysDyn.v.len(); float speedRatio = min(1.f, speed/m_maxSpeed); float actionPedal = abs(m_movementAction.power) > 0.001f ? m_movementAction.power : 0.f; // tank specific: // avoid steering input around 0.5 (ask Anton) float actionSteer = m_movementAction.rotateYaw; float absSteer = abs(actionSteer); float steerSpeed = (absSteer < 0.01f && abs(m_currSteer) > 0.01f) ? m_steerSpeedRelax : m_steerSpeed; if (steerSpeed == 0.f) { m_currSteer = (float)sgn(actionSteer); } else { if (m_movementAction.isAI) { m_currSteer = actionSteer; } else { m_currSteer += min(abs(actionSteer-m_currSteer), deltaTime*steerSpeed) * sgn(actionSteer-m_currSteer); } } Limit(m_currSteer, -m_steerLimit, m_steerLimit); if (abs(m_currSteer) > 0.0001f) { // if steering, apply full throttle to have enough turn power actionPedal = (float)sgn(actionPedal); if (actionPedal == 0.f) { // allow steering-on-teh-spot only above maxReverseSpeed (to avoid sudden reverse of controls) const float maxReverseSpeed = -1.5f; actionPedal = max(0.f, min(1.f, 1.f-(localVel.y/maxReverseSpeed))); // todo float steerLim = 0.8f; Limit(m_currSteer, -steerLim*m_steerLimit, steerLim*m_steerLimit); } } if (!pPhysics->GetStatus(&m_vehicleStatus)) return; int currGear = m_vehicleStatus.iCurGear - 1; // indexing for convenience: -1,0,1,2,.. UpdateAxleFriction(m_movementAction.power, true, deltaTime); UpdateSuspension(deltaTime); float absPedal = abs(actionPedal); // pedal ramping if (m_pedalSpeed == 0.f) m_currPedal = actionPedal; else { m_currPedal += deltaTime * m_pedalSpeed * sgn(actionPedal - m_currPedal); m_currPedal = clamp_tpl(m_currPedal, -absPedal, absPedal); } // only apply pedal after threshold is exceeded if (currGear == 0 && fabs_tpl(m_currPedal) < m_pedalThreshold) m_action.pedal = 0; else m_action.pedal = m_currPedal; // change pedal amount based on damages float damageMul = 0.0f; { if (m_movementAction.isAI) { damageMul = 1.0f - 0.30f * m_damage; m_action.pedal *= damageMul; } else { // request from Sten: damage shouldn't affect reversing so much. float effectiveDamage = m_damage; if(m_action.pedal < -0.1f) effectiveDamage = 0.4f * m_damage; m_action.pedal *= GetWheelCondition(); damageMul = 1.0f - 0.7f*effectiveDamage; m_action.pedal *= damageMul; } } // reverse steering value for backward driving float effSteer = m_currSteer * sgn(actionPedal); // update lateral friction float latSlipMinGoal = 0.f; float latFricMinGoal = m_latFricMin; if (abs(effSteer) > 0.01f && !m_movementAction.brake) { latSlipMinGoal = m_latSlipMin; // use steering friction, but not when countersteering if (sgn(effSteer) != sgn(localW.z)) latFricMinGoal = m_latFricMinSteer; } Interpolate(m_currentSlipMin, latSlipMinGoal, 3.f, deltaTime); if (latFricMinGoal < m_currentFricMin) m_currentFricMin = latFricMinGoal; else Interpolate(m_currentFricMin, latFricMinGoal, 3.f, deltaTime); float fractionSpeed = min(1.f, max(0.f, m_avgLateralSlip-m_currentSlipMin) / (m_latSlipMax-m_currentSlipMin)); float latFric = fractionSpeed * (m_latFricMax-m_currentFricMin) + m_currentFricMin; if ( m_movementAction.brake && m_movementAction.isAI ) { // it is natural for ai, apply differnt friction value while handbreaking latFric = m_latFricMax; } if (latFric != m_latFriction) { SetLatFriction(latFric); } const static float maxSteer = gf_PI/4.f; // fix maxsteer, shouldn't change m_action.steer = m_currSteer * maxSteer; if (m_steeringImpulseMin > 0.f && m_wheelContactsLeft != 0 && m_wheelContactsRight != 0) { const float maxW = 0.3f*gf_PI; float steer = abs(m_currSteer)>0.001f ? m_currSteer : 0.f; float desired = steer * maxW; float curr = -localW.z; float err = desired - curr; // err>0 means correction to right Limit(err, -maxW, maxW); if (abs(err) > 0.01f) { float amount = m_steeringImpulseMin + speedRatio*(m_steeringImpulseMax-m_steeringImpulseMin); // bigger correction for relaxing if (desired == 0.f || (desired*curr>0 && abs(desired)<abs(curr))) amount = m_steeringImpulseRelaxMin + speedRatio*(m_steeringImpulseRelaxMax-m_steeringImpulseRelaxMin); float corr = -err * amount * m_PhysDyn.mass * deltaTime; pe_action_impulse imp; imp.iApplyTime = 0; imp.angImpulse = worldTM.GetColumn2() * corr; pPhysics->Action(&imp, THREAD_SAFE); } } m_action.bHandBrake = (m_movementAction.brake) ? 1 : 0; if (currGear > 0 && m_vehicleStatus.iCurGear < m_currentGear) { // when shifted down, disengage clutch immediately to avoid power/speed dropdown m_action.clutch = 1.f; } pPhysics->Action(&m_action, 1); if (Boosting()) ApplyBoost(speed, 1.2f*m_maxSpeed*GetWheelCondition()*damageMul, m_boostStrength, deltaTime); if (m_wheelContacts <= 1 && speed > 5.f) { ApplyAirDamp(DEG2RAD(20.f), DEG2RAD(10.f), deltaTime, THREAD_SAFE); UpdateGravity(-9.81f * 1.4f); } if (m_netActionSync.PublishActions( CNetworkMovementStdWheeled(this) )) CHANGED_NETWORK_STATE(m_pVehicle, eEA_GameClientDynamic ); }
////////////////////////////////////////////////////////////////////////// // NOTE: This function must be thread-safe. Before adding stuff contact MarcoC. void CVehicleMovementHelicopter::ProcessMovement(const float deltaTime) { FUNCTION_PROFILER(GetISystem(), PROFILE_GAME); IPhysicalEntity *pPhysics = GetPhysics(); assert(pPhysics); m_netActionSync.UpdateObject(this); CryAutoCriticalSection lk(m_lock); Vec3 &impulse = m_control.impulse; Vec3 &angImpulse = m_control.angImpulse; impulse.zero(); angImpulse.zero(); m_actionPitch = m_actionRoll = m_actionYaw = m_hoveringPower = 0.0f; if(!m_isEnginePowered) return; // This results in either ProcessActions or ProcessAI getting called CVehicleMovementBase::ProcessMovement(deltaTime); const Matrix33 tm(m_PhysPos.q); Ang3 angles = Ang3::GetAnglesXYZ(tm); m_currentFwdDir = tm * Vec3(0.0f, 1.0f , 0.0f); m_currentLeftDir = tm * Vec3(-1.0f, 0.0f, 0.0f); m_currentUpDir = tm * Vec3(0.0f, 0.0f , 1.0f); m_mass = m_PhysDyn.mass; Vec3 &velocity = m_PhysDyn.v; Vec3 &angVelocity = m_PhysDyn.w; /* float gravity; pe_simulation_params paramsSim; if (pPhysics->GetParams(¶msSim)) gravity = abs(paramsSim.gravity.z); else gravity = 9.8f; */ UpdateDamages(deltaTime); UpdateEngine(deltaTime); PreProcessMovement(deltaTime); m_control.iSource = 3; m_control.iApplyTime = 0; if(!m_controlDamages.impulse.IsZero() || !m_controlDamages.angImpulse.IsZero()) { m_controlDamages.iSource = 3; m_controlDamages.iApplyTime = 0; pPhysics->Action(&m_controlDamages,1); } if(abs(angles.x) < 0.01f) angles.x = 0.0f; if(abs(angles.y) < 0.01f) angles.y = 0.0f; float turbulenceMult = 1.0f - min(m_turbulenceMultMax, m_turbulence); Vec3 engineImpulse; engineImpulse = m_workingUpDir * m_engineForce * m_hoveringPower; impulse += (engineImpulse - (velocity * m_velDamp * turbulenceMult)); impulse *= deltaTime * m_mass; angImpulse += -m_currentLeftDir * m_actionPitch * m_pitchResponsiveness; angImpulse += m_currentFwdDir * m_actionRoll * m_rollResponsiveness; angImpulse += m_currentUpDir * m_actionYaw * m_yawResponsiveness; angImpulse += m_currentUpDir * m_steeringDamage * m_yawResponsiveness * 0.5f; angImpulse *= m_mass * deltaTime; angImpulse -= (angVelocity - m_controlDamages.angImpulse) * m_mass * m_rotationDamping * deltaTime; float powerScale = GetEnginePower(); impulse *= powerScale; angImpulse *= powerScale; // apply the action pPhysics->Action(&m_control, 1); m_turbulence -= m_turbulence * deltaTime; if(m_turbulence < 0.01) m_turbulence = 0.0f; }
//-------------------------------------- void CThrow::DoDrop() { m_pWeapon->HideItem(true); if (m_throwableId) { IEntity *pEntity = gEnv->pEntitySystem->GetEntity(m_throwableId); if (pEntity) { IPhysicalEntity *pPE = pEntity->GetPhysics(); if (pPE && (pPE->GetType() == PE_RIGID || pPE->GetType() == PE_PARTICLE)) { Vec3 hit = GetProbableHit(WEAPON_HIT_RANGE); Vec3 pos = GetFiringPos(hit); CActor *pActor = m_pWeapon->GetOwnerActor(); IMovementController *pMC = pActor ? pActor->GetMovementController() : 0; if (pMC) { SMovementState info; pMC->GetMovementState(info); float speed = 2.5f; CPlayer *pPlayer = static_cast<CPlayer *>(m_pWeapon->GetOwnerActor()); if(info.aimDirection.z < -0.1f) { if(pPlayer) { if(SPlayerStats *pStats = static_cast<SPlayerStats *>(pPlayer->GetActorStats())) { if(pStats->grabbedHeavyEntity) { speed = 4.0f; } } } } if(CheckForIntersections(pPE, info.eyeDirection)) { Matrix34 newTM = pEntity->GetWorldTM(); newTM.SetTranslation(newTM.GetTranslation() - (info.eyeDirection * 0.4f)); pEntity->SetWorldTM(newTM, ENTITY_XFORM_POS); pe_action_set_velocity asv; asv.v = (-info.eyeDirection * speed); pPE->Action(&asv); } else { pe_action_set_velocity asv; asv.v = (info.eyeDirection * speed); pPE->Action(&asv); } SEntityEvent entityEvent; entityEvent.event = ENTITY_EVENT_PICKUP; entityEvent.nParam[0] = 0; if (pPlayer) { entityEvent.nParam[1] = pPlayer->GetEntityId(); } entityEvent.fParam[0] = speed; pEntity->SendEvent( entityEvent ); } } } if (m_throwableAction) { m_throwableAction->execute(m_pWeapon); } } }
void CVehicleMovementHelicopter::ProcessAI(const float deltaTime) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); CryAutoCriticalSection lk(m_lock); SVehiclePhysicsStatus* physStatus = &m_physStatus[k_physicsThread]; if (m_arcade.m_handling.maxSpeedForward>0.f) // Use the new handling code { //ResetActions(); m_movementAction.Clear(); m_movementAction.isAI = true; SVehiclePhysicsHelicopterProcessAIParams params; params.pPhysStatus = physStatus; params.pInputAction = &m_inputAction; params.pAiRequest = &m_aiRequest; params.dt = deltaTime; params.aiRequiredVel = m_CurrentVel; params.aiCurrentSpeed = m_CurrentSpeed; params.aiYawResponseScalar = m_yawResponseScalar; m_yawResponseScalar = 1.f; // Use helper class to process the AI input // It will return a requested velocity, and change the input m_arcade.ProcessAI(params); // Get the output velocity m_CurrentVel = params.aiRequiredVel; m_CurrentSpeed = params.aiCurrentSpeed; return; } ////////////////////// OLD DEPRECATED CODE :( ////////////////////////////////// m_movementAction.Clear(); ResetActions(); // Our current state const Vec3 worldPos = physStatus->pos; const Matrix33 worldMat( physStatus->q); const Matrix33 localMat( physStatus->q.GetInverted()); const Ang3 worldAngles = Ang3::GetAnglesXYZ(worldMat); const Ang3 localAngles = Ang3::GetAnglesXYZ(localMat); const Vec3 currentVel = physStatus->v; const Vec3 currentVel2D(currentVel.x, currentVel.y, 0.0f); m_CurrentSpeed = m_CurrentVel.len(); //currentVel.len(); float currentSpeed2d = currentVel2D.len(); // +ve direction mean rotation anti-clocwise about the z axis - 0 means along y float currentDir = worldAngles.z; // to avoid singularity const Vec3 vWorldDir = worldMat.GetRow(1); const Vec3 vSideWays = worldMat.GetRow(0); const Vec3 vWorldDir2D = Vec3( vWorldDir.x, vWorldDir.y, 0.0f ).GetNormalizedSafe(); // Our inputs float desiredSpeed = m_aiRequest.HasDesiredSpeed() ? m_aiRequest.GetDesiredSpeed() : 0.0f; Limit(desiredSpeed, -m_maxSpeed, m_maxSpeed); const Vec3 desiredMoveDir = m_aiRequest.HasMoveTarget() ? (m_aiRequest.GetMoveTarget() - worldPos).GetNormalizedSafe() : vWorldDir; Vec3 desiredMoveDir2D = Vec3(desiredMoveDir.x, desiredMoveDir.y, 0.0f); desiredMoveDir2D = desiredMoveDir2D.GetNormalizedSafe(desiredMoveDir2D); const Vec3 desiredVel = desiredMoveDir * desiredSpeed; const Vec3 desiredVel2D(desiredVel.x, desiredVel.y, 0.0f); Vec3 desiredLookDir(desiredMoveDir); if (m_aiRequest.HasDesiredBodyDirectionAtTarget()) { desiredLookDir = m_aiRequest.GetDesiredBodyDirectionAtTarget().GetNormalizedSafe(desiredMoveDir); } else if (m_aiRequest.HasLookTarget()) { desiredLookDir = (m_aiRequest.GetLookTarget() - worldPos).GetNormalizedSafe(desiredMoveDir); } //const Vec3 desiredLookDir = m_aiRequest.HasLookTarget() ? (m_aiRequest.GetLookTarget() - worldPos).GetNormalizedSafe() : desiredMoveDir; const Vec3 desiredLookDir2D = Vec3(desiredLookDir.x, desiredLookDir.y, 0.0f).GetNormalizedSafe(vWorldDir2D); Vec3 prediction = m_aiRequest.HasBodyTarget() ? m_aiRequest.GetBodyTarget() : ZERO; prediction = (prediction.IsEquivalent(ZERO)) ? desiredMoveDir2D : prediction - worldPos; prediction.z = 0.0f; float speedLimit = prediction.GetLength2D(); if(speedLimit > 0.0f) { prediction *= 1.0f / speedLimit; } Vec3 tempDir = currentVel2D.IsEquivalent(ZERO) ? localMat.GetRow(1) : currentVel2D; tempDir.z = 0.0f; tempDir.NormalizeFast(); float dotProd = tempDir.dot(prediction); Limit(dotProd, FLT_EPSILON, 1.0f); float accel = m_enginePowerMax * min(2.0f, 1.0f / dotProd); // * dotProd; if (!m_aiRequest.HasDesiredBodyDirectionAtTarget()) { dotProd *= dotProd; dotProd *= dotProd; float tempf = min(max(speedLimit * speedLimit, 2.0f), m_maxSpeed * dotProd); Limit(desiredSpeed, -tempf, tempf); } else if (dotProd < 0.0125f) { Limit(desiredSpeed, -m_maxSpeed * 0.25f, m_maxSpeed * 0.25f); } float posNeg = (float)__fsel(desiredSpeed - m_CurrentSpeed, 1.0f, -5.0f); if (desiredVel2D.GetLengthSquared() > FLT_EPSILON) { m_CurrentSpeed = m_CurrentSpeed + posNeg * accel * deltaTime; } else { m_CurrentSpeed = m_CurrentSpeed + posNeg * accel * deltaTime; } if (posNeg > 0.0f && m_CurrentSpeed > desiredSpeed) { m_CurrentSpeed = desiredSpeed; } else if (posNeg < 0.0f && m_CurrentSpeed < desiredSpeed) { m_CurrentSpeed = desiredSpeed; } // ---------------------------- Rotation ---------------------------- float desiredDir = (desiredLookDir2D.GetLengthSquared() > 0.0f) ? atan2f(-desiredLookDir2D.x, desiredLookDir2D.y) : atan2f(-vWorldDir2D.x, vWorldDir2D.y); while (currentDir < desiredDir - gf_PI) currentDir += 2.0f * gf_PI; while (currentDir > desiredDir + gf_PI) currentDir -= 2.0f * gf_PI; // ---------------------------- Yaw ---------------------------- Ang3 dirDiff(0.0f, 0.0f, desiredDir - currentDir); dirDiff.RangePI(); float absDiff = fabsf(dirDiff.z); float rotSpeed = (float)__fsel(dirDiff.z, m_yawPerRoll, -m_yawPerRoll); m_actionYaw = m_actionYaw + deltaTime * (rotSpeed - m_actionYaw); float temp = fabsf(m_actionYaw); float multiplier = ((absDiff / (temp + 0.001f)) + 1.0f) * 0.5f; m_actionYaw *= (float)__fsel(absDiff - temp, 1.0f, multiplier); // ---------------------------- Yaw ------------------------------ m_CurrentVel = desiredMoveDir * m_CurrentSpeed; // ---------------------------- Pitch ---------------------------- if (m_CurrentVel.GetLengthSquared2D() > 0.1f) { CalculatePitch(worldAngles, desiredMoveDir, currentSpeed2d, desiredSpeed, deltaTime); } else { Quat rot; rot.SetRotationVDir(desiredLookDir, 0.0f); float desiredXRot = Ang3::GetAnglesXYZ(rot).x + m_steeringDamage.x; m_actionPitch = worldAngles.x + (desiredXRot - worldAngles.x) * deltaTime/* * 10.0f*/; Limit(m_actionPitch, -m_maxPitchAngle * 2.0f, m_maxPitchAngle * 2.0f); } // ---------------------------- Roll ---------------------------- float rollSpeed = GetRollSpeed(); rollSpeed *= deltaTime; rollSpeed = (float)__fsel(absDiff - rollSpeed, rollSpeed, absDiff); float roll =(float) __fsel(dirDiff.z, -rollSpeed, rollSpeed); float speedPerUnit = 1.5f; float desiredRollSpeed = absDiff * speedPerUnit * (float)__fsel(dirDiff.z, 1.0f, -1.0f); desiredRollSpeed = -m_actionYaw * 2.5f; desiredRollSpeed += m_steeringDamage.y; m_actionRoll = m_actionRoll + deltaTime * (desiredRollSpeed - m_actionRoll); Limit(m_actionRoll, -m_maxRollAngle + m_steeringDamage.y, m_maxRollAngle - m_steeringDamage.y); m_actionRoll *= m_rollDamping; // ---------------------------- Roll ---------------------------- // ---------------------------- Convert and apply ---------------------------- Ang3 angles(m_actionPitch, m_actionRoll, worldAngles.z + deltaTime * m_actionYaw); pe_params_pos paramPos; paramPos.q.SetRotationXYZ(angles); paramPos.q.Normalize(); IPhysicalEntity * pPhysicalEntity = GetPhysics(); pPhysicalEntity->SetParams(¶mPos, 1); pe_action_set_velocity vel; vel.v = m_CurrentVel + m_netPosAdjust; pPhysicalEntity->Action(&vel, 1); // ---------------------------- Convert and apply ---------------------------- m_rpmScale = max(0.2f, cry_fabsf(m_CurrentSpeed / m_maxSpeed)); }
//------------------------------------------------------------------------ void CVehicleDamageBehaviorBlowTire::Activate(bool activate) { if (activate == m_isActive) return; if (activate && m_pVehicle->IsDestroyed()) return; if (activate) { // NOTE: stance and physics position when getting into vehicles is set wrong if (!gEnv->pSystem->IsSerializingFile()) DamagePlayers(); } IVehicleComponent* pComponent = m_pVehicle->GetComponent(m_component.c_str()); if (!pComponent) return; IVehiclePart* pPart = pComponent->GetPart(0); if (!pPart) return; // if IVehicleWheel available, execute full damage behavior. if null, only apply effects IVehicleWheel* pWheel = pPart->GetIWheel(); if (activate) { IEntity* pEntity = m_pVehicle->GetEntity(); IPhysicalEntity* pPhysics = pEntity->GetPhysics(); const Matrix34& wheelTM = pPart->GetLocalTM(false); const SVehicleStatus& status = m_pVehicle->GetStatus(); if (pWheel) { const pe_cargeomparams* pParams = pWheel->GetCarGeomParams(); // handle destroyed wheel pe_params_wheel wheelParams; wheelParams.iWheel = pWheel->GetWheelIndex(); wheelParams.minFriction = wheelParams.maxFriction = 0.5f * pParams->maxFriction; pPhysics->SetParams(&wheelParams); if (IVehicleMovement* pMovement = m_pVehicle->GetMovement()) { SVehicleMovementEventParams params; params.pComponent = pComponent; params.iValue = pWheel->GetWheelIndex(); pMovement->OnEvent(IVehicleMovement::eVME_TireBlown, params); } if (status.speed > 0.1f) { // add angular impulse pe_action_impulse angImp; float amount = m_pVehicle->GetMass() * status.speed * Random(0.25f, 0.45f) * -sgn(wheelTM.GetTranslation().x); angImp.angImpulse = pEntity->GetWorldTM().TransformVector(Vec3(0,0,amount)); pPhysics->Action(&angImp); } m_aiImmobilizedTimer = m_pVehicle->SetTimer(-1, AI_IMMOBILIZED_TIME*1000, this); } if (!gEnv->pSystem->IsSerializingFile()) { // add linear impulse pe_action_impulse imp; imp.point = pPart->GetWorldTM().GetTranslation(); float amount = m_pVehicle->GetMass() * Random(0.1f, 0.15f); if (pWheel) { amount *= max(0.5f, min(10.f, status.speed)); if (status.speed < 0.1f) amount = -0.5f*amount; } else amount *= 0.5f; imp.impulse = pEntity->GetWorldTM().TransformVector(Vec3(0,0,amount)); pPhysics->Action(&imp); // effect IParticleEffect* pEffect = gEnv->pParticleManager->FindEffect(TIRE_BLOW_EFFECT); if (pEffect) { int slot = pEntity->LoadParticleEmitter(-1, pEffect); if (slot > -1) { float rotation = pWheel ? 0.5f * gf_PI * -sgn(wheelTM.GetTranslation().x) : gf_PI; Matrix34 tm = Matrix34::CreateRotationZ(rotation); tm.SetTranslation(wheelTM.GetTranslation()); pEntity->SetSlotLocalTM(slot, tm); } } // remove affected decals { Vec3 pos = pPart->GetWorldTM().GetTranslation(); AABB aabb = pPart->GetLocalBounds(); float radius = aabb.GetRadius(); Vec3 vRadius(radius,radius,radius); AABB areaBox(pos-vRadius, pos+vRadius); IRenderNode * pRenderNode = NULL; if (IEntityRenderProxy *pRenderProxy = (IEntityRenderProxy*)pEntity->GetProxy(ENTITY_PROXY_RENDER)) pRenderNode = pRenderProxy->GetRenderNode(); gEnv->p3DEngine->DeleteDecalsInRange(&areaBox, pRenderNode); } } } else { if (pWheel) { // restore wheel properties IPhysicalEntity* pPhysics = m_pVehicle->GetEntity()->GetPhysics(); pe_params_wheel wheelParams; for (int i=0; i<m_pVehicle->GetWheelCount(); ++i) { const pe_cargeomparams* pParams = m_pVehicle->GetWheelPart(i)->GetIWheel()->GetCarGeomParams(); wheelParams.iWheel = i; wheelParams.bBlocked = 0; wheelParams.suspLenMax = pParams->lenMax; wheelParams.bDriving = pParams->bDriving; wheelParams.minFriction = pParams->minFriction; wheelParams.maxFriction = pParams->maxFriction; pPhysics->SetParams(&wheelParams); } if (IVehicleMovement* pMovement = m_pVehicle->GetMovement()) { SVehicleMovementEventParams params; params.pComponent = pComponent; params.iValue = pWheel->GetWheelIndex(); // reset the particle status pMovement->OnEvent(IVehicleMovement::eVME_TireRestored, params); } } m_aiImmobilizedTimer = -1; } m_isActive = activate; }
bool CJaw::SetAspectProfile(EEntityAspects aspect, uint8 profile) { if(aspect!=eEA_Physics) return BaseClass::SetAspectProfile(aspect, profile); bool ok = false; if(!gEnv->bMultiplayer && gEnv->pSystem->IsSerializingFile() && m_auxSlotUsedBQS) ok = true; int slot = (m_auxSlotUsed||ok)?eIGS_ThirdPersonAux:eIGS_ThirdPerson; if (aspect == eEA_Physics) { switch (profile) { case eIPhys_PhysicalizedStatic: { SEntityPhysicalizeParams params; params.type = PE_STATIC; params.nSlot = slot; GetEntity()->Physicalize(params); return true; } break; case eIPhys_PhysicalizedRigid: { SEntityPhysicalizeParams params; params.type = PE_RIGID; params.nSlot = slot; params.mass = m_sharedparams->params.mass; pe_params_buoyancy buoyancy; buoyancy.waterDamping = 1.5; buoyancy.waterResistance = 1000; buoyancy.waterDensity = 0; params.pBuoyancy = &buoyancy; GetEntity()->Physicalize(params); IPhysicalEntity *pPhysics = GetEntity()->GetPhysics(); if (pPhysics) { pe_action_awake action; action.bAwake = m_owner.GetId()!=0; pPhysics->Action(&action); } } return true; case eIPhys_NotPhysicalized: { IEntityPhysicalProxy *pPhysicsProxy = GetPhysicalProxy(); if (pPhysicsProxy) { SEntityPhysicalizeParams params; params.type = PE_NONE; params.nSlot = slot; pPhysicsProxy->Physicalize(params); } } return true; } } return false; }
//------------------------------------------------------------------------ void CVehicleMovementHelicopter::OnEvent(EVehicleMovementEvent event, const SVehicleMovementEventParams& params) { switch (event) { case eVME_Repair: { if(params.fValue < 0.25) { m_damageActual = 0.0f; m_damage = 0.0f; } } break; case eVME_Collision: { if (0) { m_isEnginePowered = false; pe_simulation_params simParams; simParams.dampingFreefall = 0.01f; simParams.gravity = Vec3(0.0f, 0.0f, -9.8f); GetPhysics()->SetParams(&simParams); } } break; case eVME_GroundCollision: { const float stopOver = 1.0f; } break; case eVME_Damage: { if (!m_pVehicle->IsIndestructable()) { const float stopOver = 1.0f; m_damage = params.fValue; if (m_damage > 0.95f) { m_isEngineDisabled = true; m_isEnginePowered = false; StopExhaust(); StopSounds(); IPhysicalEntity * pPhysicalEntity = GetPhysics(); pe_action_impulse impulse; impulse.angImpulse = Vec3(0.1f, 100.f, 0.0f); pPhysicalEntity->Action(&impulse); pe_simulation_params simParams; simParams.dampingFreefall = 0.01f; simParams.gravity = Vec3(0.0f, 0.0f, -9.8f); pPhysicalEntity->SetParams(&simParams); SVehicleEventParams eventParams; eventParams.entityId = 0; m_pVehicle->BroadcastVehicleEvent(eVE_Destroyed, eventParams); if (m_pVehicle) { if (IEntity *entity = m_pVehicle->GetEntity()) { if (IAIObject *aiobject = entity->GetAI()) { aiobject->Event(AIEVENT_DISABLE, NULL); } } } } } } break; case eVME_WarmUpEngine: m_enginePower = m_enginePowerMax; break; //case eVME_Turbulence: // m_turbulence = max(m_turbulence, params.fValue); // break; default: CVehicleMovementBase::OnEvent(event, params); break; } }
//------------------------------------------------------------------------ bool CNetworkedPhysicsEntity::SetAspectProfile( EEntityAspects aspect, uint8 profile ) { bool bRetVal = false; if (aspect == eEA_Physics) { switch (profile) { case ePhys_PhysicalizedRigid: { if (m_physicsType!=ePhys_PhysicalizedRigid) { m_physicsParams.type = PE_RIGID; GetEntity()->Physicalize(m_physicsParams); m_physicsType = ePhys_PhysicalizedRigid; GetEntity()->GetPhysics()->SetParams(m_physicsParams.pBuoyancy); } bRetVal = true; break; } case ePhys_PhysicalizedStatic: { if (m_physicsType != ePhys_PhysicalizedStatic) { m_physicsParams.type = PE_STATIC; GetEntity()->Physicalize(m_physicsParams); m_physicsType = ePhys_PhysicalizedStatic; } bRetVal = true; break; } case ePhys_NotPhysicalized: { if (m_physicsType!=ePhys_NotPhysicalized) { SEntityPhysicalizeParams params; params.type = PE_NONE; GetEntity()->Physicalize(params); m_physicsType = ePhys_NotPhysicalized; } bRetVal = true; break; } default: { CryLog("Unsupported physicalization type in CNetworkedPhysicsEntity!"); } } } IPhysicalEntity * pPhysEnt = GetEntity()->GetPhysics(); if(pPhysEnt) { // Turn off some collisions // NB: by leaving pe_params_part.ipart undefined, all the geom flags will changed pe_params_part pp; pp.flagsAND = ~(geom_colltype_ray|geom_colltype_player|geom_colltype_explosion|geom_colltype_debris|geom_colltype_foliage_proxy); pPhysEnt->SetParams(&pp); pe_simulation_params psp; psp.damping = 0.5f; pPhysEnt->SetParams(&psp); //Add a bit of angular velocity so it doesn't look bizzare. pe_action_set_velocity physicsAction; physicsAction.w.Set((rnd()-0.5f)*15.0f, (rnd()-0.5f)*15.0f, (rnd()-0.5f)*15.0f); pPhysEnt->Action(&physicsAction); } return bRetVal; }
////////////////////////////////////////////////////////////////////////// // NOTE: This function must be thread-safe. Before adding stuff contact MarcoC. void CVehicleMovementHelicopter::ProcessMovement(const float deltaTime) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); IPhysicalEntity* pPhysics = GetPhysics(); assert(pPhysics); if (m_arcade.m_handling.maxSpeedForward>0.f) // Use the new handling code { CryAutoCriticalSection lk(m_lock); if (!m_isEnginePowered) return; CVehicleMovementBase::ProcessMovement(deltaTime); SVehiclePhysicsStatus* physStatus = &m_physStatus[k_physicsThread]; if(m_bApplyNoiseAsVelocity) { physStatus->v -= m_pNoise->m_posDifference; physStatus->w -= m_pNoise->m_angDifference; m_pNoise->Update(deltaTime); } /////////////////////////////////////////////////////////////// // Pass on the movement request to the active physics handler // NB: m_physStatus is update by this call SVehiclePhysicsHelicopterProcessParams params; params.pPhysics = pPhysics; params.pPhysStatus = physStatus; params.pInputAction = &m_inputAction; params.dt = deltaTime; params.haveDriver = (m_actorId!=0)||m_remotePilot; params.isAI = m_movementAction.isAI; params.aiRequiredVel = m_CurrentVel; m_arcade.ProcessMovement(params); // Network error adjustment m_netPosAdjust *= max(0.f, 1.f-deltaTime*k_netErrorPosScale); physStatus->v += m_netPosAdjust * k_netErrorPosScale; if(m_bApplyNoiseAsVelocity) { physStatus->v += m_pNoise->m_posDifference; physStatus->w += m_pNoise->m_angDifference; } //=============================================== // Commit the velocity back to the physics engine //=============================================== // if (fabsf(m_movementAction.rotateYaw)>0.05f || vel.GetLengthSquared()>0.001f || m_chassis.vel.GetLengthSquared()>0.001f || angVel.GetLengthSquared()>0.001f || angVel.GetLengthSquared()>0.001f) { pe_action_set_velocity setVelocity; setVelocity.v = physStatus->v; setVelocity.w = physStatus->w; pPhysics->Action(&setVelocity, 1); } /////////////////////////////////////////////////////////////// } else { if (m_isEnginePowered && pPhysics) { m_movementAction.isAI = true; pe_status_pos psp; pe_status_dynamics psd; if (!pPhysics->GetStatus(&psp) || !pPhysics->GetStatus(&psd)) return; UpdatePhysicsStatus(&m_physStatus[k_physicsThread], &psp, &psd); ProcessAI(deltaTime); } } }
//------------------------------------------------------------------------ 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); } } }
virtual void ProcessEvent( EFlowEvent event, SActivationInfo *pActInfo ) { if (!pActInfo->pEntity) return; if (event == eFE_Activate && IsPortActive(pActInfo, IN_ACTIVATE)) { pe_action_impulse action; int ipart = GetPortInt( pActInfo, IN_PARTINDEX ); if (ipart>0) action.ipart = ipart-1; IEntity* pEntity = pActInfo->pEntity; ECoordSys coordSys = (ECoordSys)GetPortInt( pActInfo, IN_COORDSYS ); if (coordSys==CS_PARENT && !pEntity->GetParent()) coordSys = CS_WORLD; // When a "zero point" is set in the node, the value is left undefined and physics assume it is the CM of the object. // but when the entity has a parent (is linked), then we have to use a real world coordinate for the point, because we have to apply the impulse to the highest entity // on the hierarchy and physics will use the position of that entity instead of the position of the entity assigned to the node bool bHaveToUseTransformedZeroPoint = false; Vec3 transformedZeroPoint; Matrix34 transMat; switch (coordSys) { case CS_WORLD: default: { transMat.SetIdentity(); bHaveToUseTransformedZeroPoint = pEntity->GetParent()!=NULL; transformedZeroPoint = pEntity->GetWorldPos(); break; } case CS_PARENT: { transMat = pEntity->GetParent()->GetWorldTM(); bHaveToUseTransformedZeroPoint = pEntity->GetParent()->GetParent()!=NULL; transformedZeroPoint = pEntity->GetParent()->GetWorldPos(); break; } case CS_LOCAL: { transMat = pEntity->GetWorldTM(); bHaveToUseTransformedZeroPoint = pEntity->GetParent()!=NULL; transformedZeroPoint = pEntity->GetWorldPos(); break; } } action.impulse = GetPortVec3( pActInfo, IN_IMPULSE ); action.impulse = transMat.TransformVector( action.impulse ); Vec3 angImpulse = GetPortVec3( pActInfo, IN_ANGIMPULSE ); if (!angImpulse.IsZero()) action.angImpulse = transMat.TransformVector( angImpulse ); Vec3 pointApplication = GetPortVec3( pActInfo, IN_POINT ); if (!pointApplication.IsZero()) action.point = transMat.TransformPoint( pointApplication ); else { if (bHaveToUseTransformedZeroPoint) action.point = transformedZeroPoint; } // the impulse has to be applied to the highest entity in the hierarchy. This comes from how physics manage linked entities. IEntity* pEntityImpulse = pEntity; while (pEntityImpulse->GetParent()) { pEntityImpulse = pEntityImpulse->GetParent(); } IPhysicalEntity * pPhysEntity = pEntityImpulse->GetPhysics(); if (pPhysEntity) pPhysEntity->Action( &action ); } }
void CTornado::UpdateFlow() { IVehicleSystem* pVehicleSystem = g_pGame->GetIGameFramework()->GetIVehicleSystem(); assert(pVehicleSystem); float frameTime(gEnv->pTimer->GetFrameTime()); IPhysicalWorld *ppWorld = gEnv->pPhysicalWorld; Vec3 pos(GetEntity()->GetWorldPos()); //first, check the entities in range m_nextEntitiesCheck -= frameTime; if (m_nextEntitiesCheck<0.0f) { m_nextEntitiesCheck = 1.0f; Vec3 radiusVec(m_radius,m_radius,0); IPhysicalEntity **ppList = NULL; int numEnts = ppWorld->GetEntitiesInBox(pos-radiusVec,pos+radiusVec+Vec3(0,0,m_cloudHeight*0.5f),ppList,ent_sleeping_rigid|ent_rigid|ent_living); m_spinningEnts.clear(); for (int i=0;i<numEnts;++i) { // add check for spectating players... EntityId id = ppWorld->GetPhysicalEntityId(ppList[i]); CActor* pActor = static_cast<CActor*>(g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(id)); if(!pActor || !pActor->GetSpectatorMode()) { m_spinningEnts.push_back(id); } } //OutputDistance(); } //mess entities around for (size_t i=0;i<m_spinningEnts.size();++i) { IPhysicalEntity *ppEnt = ppWorld->GetPhysicalEntityById(m_spinningEnts[i]); if (ppEnt) { pe_status_pos spos; pe_status_dynamics sdyn; if (!ppEnt->GetStatus(&spos) || !ppEnt->GetStatus(&sdyn)) continue; //gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(spos.pos,2.0f,ColorB(255,0,255,255)); Vec3 delta(pos - spos.pos); delta.z = 0.0f; float dLen(delta.len()); float forceMult(max(0.0f,(m_radius-dLen)/m_radius)); if (dLen>0.001f) delta /= dLen; else delta.zero(); Vec3 upVector(0,0,1); float spinImpulse(m_spinImpulse); float attractionImpulse(m_attractionImpulse); float upImpulse(m_upImpulse); if (ppEnt->GetType() == PE_LIVING) { upImpulse *= 0.75f; attractionImpulse *= 0.35f; spinImpulse *= 1.5f; } if (IVehicle* pVehicle = pVehicleSystem->GetVehicle(m_spinningEnts[i])) { IVehicleMovement* pMovement = pVehicle->GetMovement(); if (pMovement && pMovement->GetMovementType() == IVehicleMovement::eVMT_Air) { SVehicleMovementEventParams params; params.fValue = forceMult; pMovement->OnEvent(IVehicleMovement::eVME_Turbulence, params); } } Vec3 spinForce( (delta % upVector) * spinImpulse ); Vec3 attractionForce(delta * attractionImpulse); Vec3 upForce(0,0,upImpulse); pe_action_impulse aimpulse; aimpulse.impulse = (spinForce + attractionForce + upForce) * (forceMult * sdyn.mass * frameTime); aimpulse.angImpulse = (upVector + (delta % upVector)) * (gf_PI * 0.33f * forceMult * sdyn.mass * frameTime); aimpulse.iApplyTime = 0; ppEnt->Action(&aimpulse); //gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(spos.pos,ColorB(255,0,255,255),spos.pos+aimpulse.impulse.GetNormalizedSafe(ZERO),ColorB(255,0,255,255)); } } }