void CWaterPuddle::ZapEnemiesOnPuddle(int ownTeam, EntityId shooterId, EntityId weaponId, float damage, int hitTypeId, IParticleEffect* hitEffect) { IGameVolumes::VolumeInfo volumeInfo; if (!GetVolumeInfoForEntity(GetEntityId(), &volumeInfo)) return; IEntity* pEntity = GetEntity(); Matrix34 worldTM = pEntity->GetWorldTM(); float waterLevel = worldTM.GetTranslation().z + volumeInfo.volumeHeight * 0.5f; CActorManager* pActorManager = CActorManager::GetActorManager(); const int numberOfActors = pActorManager->GetNumActors(); for(int i = 0; i < numberOfActors; i++) { SActorData actorData; pActorManager->GetNthActorData(i, actorData); bool isActorAlive = (actorData.health > 0.0f); bool isActorEnemy = (actorData.teamId != ownTeam); bool isActorInsidevolume = IsActorInsideVolume(worldTM, volumeInfo, actorData.entityId); if (isActorAlive && isActorEnemy && isActorInsidevolume) ApplyHit(actorData, shooterId, weaponId, damage, hitTypeId, waterLevel, hitEffect); } }
//----------------------------------------------------- void CThrow::ThrowObject(IEntity* pEntity, IPhysicalEntity* pPE) { bool strengthMode = false; CPlayer *pPlayer = static_cast<CPlayer*>(m_pWeapon->GetOwnerActor()); if (pPlayer) { // Report throw to AI system. if (pPlayer->GetEntity() && pPlayer->GetEntity()->GetAI()) { SAIEVENT AIevent; AIevent.targetId = pEntity->GetId(); pPlayer->GetEntity()->GetAI()->Event(AIEVENT_PLAYER_THROW, &AIevent); } } Vec3 hit = GetProbableHit(WEAPON_HIT_RANGE); Vec3 pos = GetFiringPos(hit); Vec3 dir = ApplySpread(GetFiringDir(hit, pos), GetSpread()); Vec3 vel = GetFiringVelocity(dir); float speed = 12.0f; if(strengthMode) speed *= m_pShared->throwparams.strenght_scale; speed = max(2.0f, speed); pe_params_pos ppos; ppos.pos = pEntity->GetWorldPos(); pPE->SetParams(&ppos); if(CheckForIntersections(pPE,dir)) { Matrix34 newTM = pEntity->GetWorldTM(); newTM.SetTranslation(newTM.GetTranslation()-(dir*0.4f)); pEntity->SetWorldTM(newTM,ENTITY_XFORM_POS); } else { pe_action_set_velocity asv; asv.v = (dir*speed)+vel; AABB box; pEntity->GetWorldBounds(box); Vec3 finalW = -gEnv->pSystem->GetViewCamera().GetMatrix().GetColumn0()*(8.0f/max(0.1f,box.GetRadius())); finalW.x *= Random(0.5f,1.3f); finalW.y *= Random(0.5f,1.3f); finalW.z *= Random(0.5f,1.3f); asv.w = finalW; //asv.w = Vec3(Random(-4.5f,3.5f),Random(-1.75f,2.5f),Random(-1.5f,2.2f)); 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 ); }
bool CIntersectionAssistanceUnit::TestForIntersection(const eTestMethod testMethod, const QuatT& qWOrient, const Quat& qRotOffset, const bool bCentreOnFocalEnt, int index ) { QuatT temp = qWOrient; temp.q *= qRotOffset; Matrix34 finalMatrix = Matrix34(temp); QuatT outAdjustedResult; if(!TestForIntersectionAtLocation(testMethod, finalMatrix, m_subjectEntityId, m_focalEntityId, outAdjustedResult,bCentreOnFocalEnt, false, index)) { if(testMethod == eTM_Immediate) { m_lastKnownGoodPositions[index] = outAdjustedResult; } return false; } #ifndef _RELEASE else if(g_pGameCVars->pl_pickAndThrow.intersectionAssistDebugEnabled == 1) { const QuatT& qLastKnownGood =m_lastKnownGoodPositions[index]; if(IsPositionWithinAcceptedLimits(qLastKnownGood.t, finalMatrix.GetTranslation(), 1.5f)) { QuatT dummyTest; TestForIntersectionAtLocation(eTM_Immediate, Matrix34(qLastKnownGood), m_subjectEntityId, m_focalEntityId, dummyTest, bCentreOnFocalEnt, true, index); } } #endif // #ifndef _RELEASE return true; }
// Calculates the desired position for the physics box, so that its center will be superimposed with AABB center of provided entity. // Also adjusts upwards to avoid any obvious floor clipping. Returns desired Position for entity. Vec3 CIntersectionAssistanceUnit::CalculateTargetAdjustPoint(const IEntity* pEntity, const Matrix34 &wMat, const Vec3& vStartingPos) const { // (if present + desired) adjust physbox center to that of owner Ent - to make sure centers of PhysBox + focal ent superimposed // at the desired position const IEntity* pFocalEnt = gEnv->pEntitySystem->GetEntity(m_focalEntityId); if(pFocalEnt) { OBB focalOBB; AABB focalAABB; // Compensate for actor/non actor entities that require different paths :( if(CPlayer* pPlayer = static_cast<CPlayer*>(g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(m_focalEntityId))) { EStance playerStance = pPlayer->GetStance(); focalAABB = pPlayer->GetStanceInfo(playerStance)->GetStanceBounds(); } else { pFocalEnt->GetLocalBounds(focalAABB); } focalOBB.SetOBBfromAABB(Quat(IDENTITY), focalAABB); // shift to match focus ent Center (taking into account crouch etc if player). float fVerticalAdjust = focalOBB.h.z; // Additionally.. if the new test pos *would* immediately penetrate the floor (assumption based on any part of the volume being < player AABB z min value) // shift it up. float fFloorPenetrationAdjust = 0.0f; AABB wEntABB; pEntity->GetLocalBounds(wEntABB); wEntABB.SetTransformedAABB(wMat,wEntABB); float fFloorClearance = focalOBB.h.z - (wEntABB.GetSize().z * 0.5f); fFloorPenetrationAdjust += (0.0f - min(fFloorClearance, 0.0f)); // Apply floor clearance + Vertical adjust Vec3 desiredPos = wMat.GetTranslation() + Vec3(0.0f,0.0f,(fFloorPenetrationAdjust) * kFloorAdjustConstant); desiredPos += (fVerticalAdjust * pFocalEnt->GetWorldTM().GetColumn2() * kFloorAdjustConstant); return desiredPos; } return wMat.GetTranslation(); }
void CGameVolume_Water::CreatePhysicsArea(const uint32 segmentIndex, const Matrix34& baseMatrix, const Vec3* pVertices, uint32 vertexCount, const bool isRiver, const float streamSpeed) { //Destroy previous physics if any if(segmentIndex == 0) { DestroyPhysicsAreas(); } SWaterSegment& segment = m_segments[segmentIndex]; IWaterVolumeRenderNode* pWaterRenderNode = segment.m_pWaterRenderNode; Vec3 waterFlow(ZERO); CRY_ASSERT (segment.m_pWaterArea == NULL); CRY_ASSERT (pWaterRenderNode != NULL); pWaterRenderNode->SetMatrix( Matrix34::CreateIdentity() ); segment.m_pWaterArea = pWaterRenderNode->SetAndCreatePhysicsArea( &pVertices[0], vertexCount ); IPhysicalEntity* pWaterArea = segment.m_pWaterArea; if( pWaterArea ) { const Quat entityWorldRot = Quat(baseMatrix); pe_status_pos posStatus; pWaterArea->GetStatus( &posStatus ); const Vec3 areaPosition = baseMatrix.GetTranslation() + ((entityWorldRot * posStatus.pos) - posStatus.pos); pe_params_pos position; position.pos = areaPosition; position.q = entityWorldRot; pWaterArea->SetParams( &position); pe_params_buoyancy pb; pb.waterPlane.n = entityWorldRot * Vec3( 0, 0, 1 ); pb.waterPlane.origin = areaPosition; if(isRiver) { int i = segmentIndex; int j = vertexCount - 1 - segmentIndex; pb.waterFlow = ((pVertices[1]-pVertices[0]).GetNormalized() + (pVertices[2]-pVertices[3]).GetNormalized()) / 2.f * streamSpeed; } pWaterArea->SetParams( &pb); pe_params_foreign_data pfd; pfd.pForeignData = pWaterRenderNode; pfd.iForeignData = PHYS_FOREIGN_ID_WATERVOLUME; pfd.iForeignFlags = 0; pWaterArea->SetParams(&pfd); segment.m_physicsLocalAreaCenter = posStatus.pos; } }
void CMountedGunController::UpdateGunnerLocation( CItem* pMountedGun, IEntity* pParent, const Vec3& bodyDirection ) { const SMountParams* pMountParams = pMountedGun->GetMountedParams(); if (pMountParams) { f32 bodyDist = pMountParams->body_distance; f32 groundDist = pMountParams->ground_distance; Matrix34 gunLocalTM = pMountedGun->GetEntity()->GetLocalTM(); Matrix34 gunLocalTMXY(IDENTITY); Matrix34 characterTM(IDENTITY); Matrix34 newGunnerTM; Vec3 playerOffset(0.0f, -bodyDist, -groundDist); characterTM.SetTranslation(playerOffset); IEntity* pControlledPlayerEntity = m_pControlledPlayer->GetEntity(); IVehicle *pVehicle = NULL; if (gEnv->bMultiplayer && m_pControlledPlayer->IsClient() && m_pControlledPlayer->GetLinkedVehicle()) { newGunnerTM = gunLocalTM; newGunnerTM.SetTranslation(gunLocalTM.GetTranslation() + Quat(gunLocalTM) * playerOffset); } else { float rotZ = pMountedGun->GetEntity()->GetRotation().GetRotZ(); gunLocalTMXY.SetRotationZ(rotZ); gunLocalTMXY.SetTranslation(gunLocalTM.GetTranslation()); newGunnerTM = gunLocalTMXY*characterTM; } pControlledPlayerEntity->SetLocalTM(newGunnerTM, ENTITY_XFORM_USER); // CryWatch("Mount wrot: plr: %f vehicle: %f wpn: %f", pControlledPlayerEntity->GetWorldRotation().GetRotZ(), pParent ? pParent->GetWorldRotation().GetRotZ() : -99.0f, pMountedGun->GetEntity()->GetWorldRotation().GetRotZ()); // CryWatch("Mount lrot: plr: %f vehicle: %f wpn: %f", pControlledPlayerEntity->GetRotation().GetRotZ(), pParent ? pParent->GetRotation().GetRotZ() : -99.0f, pMountedGun->GetEntity()->GetRotation().GetRotZ()); } }
//--------------------------------------------------------------------- //This function is only executed on the server void CC4Projectile::StickToStaticObject(EventPhysCollision *pCollision, IPhysicalEntity *pTarget) { //Calculate new position and orientation Matrix34 mat; Vec3 pos = pCollision->pt+(pCollision->n*0.05f); mat.SetRotation33(Matrix33::CreateOrientation(-pCollision->n,GetEntity()->GetWorldTM().TransformVector(Vec3(0,0,1)),gf_PI)); Vec3 newUpDir = mat.TransformVector(Vec3(0,0,1)); pos += (newUpDir*-0.1f); mat.SetTranslation(pos+(newUpDir*-0.1f)); GetEntity()->SetWorldTM(mat); GetGameObject()->SetAspectProfile(eEA_Physics, ePT_Static); pos = mat.GetTranslation(); Quat rot = GetEntity()->GetWorldRotation(); if(gEnv->bMultiplayer) GetGameObject()->InvokeRMI(CC4Projectile::ClSetPosition(),ProjectileStaticParams(pos,rot),eRMI_ToAllClients); }
//------------------------------------------------------------------------ void CVehicleViewFirstPerson::Update(float frameTimeIn) { // Use the physics frame time, but only if non zero! const float physFrameTime = static_cast<CVehicle*>(m_pVehicle)->GetPhysicsFrameTime(); const float frameTime = (physFrameTime>0.f) ? min(physFrameTime,frameTimeIn) : frameTimeIn; CVehicleViewBase::Update(frameTime); if (m_frameSlot != -1 && m_pHelper) { Matrix34 tm; m_pHelper->GetVehicleTM(tm); tm = tm * m_invFrame; tm.SetTranslation(tm.GetTranslation() + tm.TransformVector(m_frameObjectOffset)); m_pVehicle->GetEntity()->SetSlotLocalTM(m_frameSlot, tm); } m_viewPosition = GetWorldPosGoal(); }
//----------------------------------------------------- void CThrow::ThrowLivingEntity(IEntity* pEntity, IPhysicalEntity* pPE) { Vec3 hit = GetProbableHit(WEAPON_HIT_RANGE); Vec3 pos = GetFiringPos(hit); Vec3 dir = ApplySpread(GetFiringDir(hit, pos), GetSpread()); Vec3 vel = GetFiringVelocity(dir); CPlayer *pPlayer = static_cast<CPlayer*>(m_pWeapon->GetOwnerActor()); if(pPlayer) { float speed = 8.0f; dir.Normalize(); if(CheckForIntersections(pPE,dir)) { Matrix34 newTM = pEntity->GetWorldTM(); newTM.SetTranslation(newTM.GetTranslation()-(dir*0.6f)); pEntity->SetWorldTM(newTM,ENTITY_XFORM_POS); } { pe_action_set_velocity asv; asv.v = (dir*speed)+vel; pPE->Action(&asv); // [anton] use thread safe=1 (immediate) if the character is still a living entity at this stage, // but will be ragdollized during the same frame pe_params_articulated_body pab; pab.bCheckCollisions = 1; // was set to 0 while carrying pPE->SetParams(&pab); } // Report throw to AI system. if (pPlayer->GetEntity() && pPlayer->GetEntity()->GetAI()) { SAIEVENT AIevent; AIevent.targetId = pEntity->GetId(); pPlayer->GetEntity()->GetAI()->Event(AIEVENT_PLAYER_STUNT_THROW_NPC, &AIevent); } } }
//------------------------------------------------------------------------ void CVehicleSeatActionRotateTurret::Serialize(TSerialize ser, EEntityAspects aspects) { // MR: for network, only turret parts are serialized // for savegame, all parts are serialized (by CVehicle) if (ser.GetSerializationTarget() == eST_Network) { for (int i = 0; i < eVTRT_NumRotationTypes; ++i) { if (m_rotations[i].m_pPart) { m_rotations[i].m_pPart->Serialize(ser, aspects); } } } else { // save rotation details CryFixedStringT<16> tag; for (int i = 0; i < eVTRT_NumRotationTypes; ++i) { if (m_rotations[i].m_pPart) { Quat q; Matrix34 currentTM = m_rotations[i].m_pPart->GetLocalBaseTM(); if (ser.IsWriting()) q = Quat(currentTM); tag = (i == eVTRT_Pitch) ? "rotation_pitch" : "rotation_yaw"; ser.Value(tag.c_str(), q, 'ori1'); if (ser.IsReading()) { Matrix34 newTM(q); newTM.SetTranslation(currentTM.GetTranslation()); m_rotations[i].m_pPart->SetLocalBaseTM(newTM); m_rotations[i].m_orientation.Set(q); } } } } }
//----------------------------------------------------------------------- void CVehiclePartLight::UpdateLight(const float frameTime) { if (m_slot == -1) return; // move to vehicle event change view? if (m_diffuseMult[0] != m_diffuseMult[1]) { SEntitySlotInfo info; if (m_pVehicle->GetEntity()->GetSlotInfo(m_slot, info) && info.pLight) { CDLight& light = info.pLight->GetLightProperties(); IActor* pActor = CCryAction::GetCryAction()->GetClientActor(); bool localPlayer = (pActor != NULL) && (pActor->GetLinkedVehicle() == m_pVehicle); IVehicleSeat* pSeat = pActor ? m_pVehicle->GetSeatForPassenger(pActor->GetEntityId()) : NULL; IVehicleView* pView = pSeat? pSeat->GetView(pSeat->GetCurrentView()) : NULL; bool isThirdPersonView = pView? pView->IsThirdPerson() : true; if (localPlayer && !isThirdPersonView) light.SetLightColor(ColorF(m_diffuseCol * m_diffuseMult[0], 1.f)); else light.SetLightColor(ColorF(m_diffuseCol * m_diffuseMult[1], 1.f)); } } if (m_pHelper) { const static Matrix33 rot(Matrix33::CreateRotationXYZ(Ang3(0.f, 0.f, DEG2RAD(90.f)))); Matrix34 helperTM; m_pHelper->GetVehicleTM(helperTM); Matrix34 localTM = Matrix33(helperTM) * rot; localTM.SetTranslation(helperTM.GetTranslation()); GetEntity()->SetSlotLocalTM(m_slot, localTM); } }
//-------------------------------------------- void CLaser::GetLaserPositionAndDirection(CWeapon* pParentWeapon, Vec3& pos, Vec3& dir) { const char* entityLocationHelper = m_laserHelperFP.c_str(); const char* laserTermHelper = "laser_term"; const bool relative = false; const bool absolute = true; const int slot = pParentWeapon->IsOwnerFP() ? eIGS_FirstPerson : eIGS_ThirdPerson; Matrix34 entityLocation = Matrix34::CreateTranslationMat(pParentWeapon->GetSlotHelperPos(slot, entityLocationHelper, absolute)) * pParentWeapon->GetSlotHelperRotation(slot, entityLocationHelper, absolute); Matrix34 helperLocation = Matrix34::CreateTranslationMat(GetSlotHelperPos(slot, laserTermHelper, relative)) * GetSlotHelperRotation(slot, laserTermHelper, relative); Matrix34 finalLocation = entityLocation * helperLocation; pos = finalLocation.GetTranslation(); dir = finalLocation.GetColumn1(); }
//------------------------------------------------------------------------ void CItem::SpawnEffect(int slot, const char *effectName, const char *helper, const Vec3 &offset, const Vec3 &dir, float scale) { if (m_stats.mounted) slot=eIGS_FirstPerson; Vec3 position(0,0,0); Vec3 finalOffset = offset; SEntitySlotInfo slotInfo; if (GetEntity()->GetSlotInfo(slot, slotInfo)) { if (slotInfo.pStatObj) // entity slot { // get helper position IStatObj *pStatsObj = slotInfo.pStatObj; position = pStatsObj->GetHelperPos(helper); position = GetEntity()->GetSlotWorldTM(slot).TransformPoint(position); } else if (slotInfo.pCharacter) // bone attachment { ICharacterInstance *pCharacter = slotInfo.pCharacter; IAttachmentManager *pAttachmentManager = pCharacter->GetIAttachmentManager(); IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(helper); if (pAttachment) { const Matrix34 m = Matrix34(pAttachment->GetAttWorldAbsolute()); position = m.GetTranslation(); } else { int16 id = pCharacter->GetISkeletonPose()->GetJointIDByName(helper); if (id>=0) position = pCharacter->GetISkeletonPose()->GetAbsJointByID(id).t; position = GetEntity()->GetSlotWorldTM(slot).TransformPoint(position); } } } else if(m_stats.mounted && !m_stats.fp) { if(GetIWeapon()) { // if no helper specified, try getting pos from firing locator IWeaponFiringLocator *pLocator = GetIWeapon()->GetFiringLocator(); if (pLocator) { if(!pLocator->GetFiringPos(GetEntityId(), NULL, position)) position.Set(0.0f,0.0f,0.0f); else finalOffset = GetEntity()->GetWorldTM().TransformVector(finalOffset); } } } position += finalOffset; IParticleEffect *pParticleEffect = gEnv->pParticleManager->FindEffect(effectName); if (pParticleEffect) pParticleEffect->Spawn(true, IParticleEffect::ParticleLoc(position, dir, scale)); }
//-------------------------------------- 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 CVehicleViewSteer::Update(float dt) { IEntity* pEntity = m_pVehicle->GetEntity(); assert(pEntity); IVehicleMovement* pVehicleMovement = m_pVehicle->GetMovement(); if (pVehicleMovement == NULL) return; IPhysicalEntity* pPhysEntity = pEntity->GetPhysics(); if (!pPhysEntity) return; pe_status_dynamics dynStatus; pPhysEntity->GetStatus(&dynStatus); SMovementState movementState; pVehicleMovement->GetMovementState(movementState); const float pedal = pVehicleMovement->GetEnginePedal(); const float maxSpeed = movementState.maxSpeed; const Matrix34 &pose = m_pAimPart ? m_pAimPart->GetWorldTM() : pEntity->GetWorldTM(); const Vec3 entityPos = pose.GetColumn3(); const Vec3 xAxis = pose.GetColumn0(); const Vec3 yAxis = pose.GetColumn1(); const Vec3 zAxis = pose.GetColumn2(); const float forwardSpeed = dynStatus.v.dot(yAxis); const float speedNorm = clamp_tpl(forwardSpeed / maxSpeed, 0.0f, 1.0f); const Vec3 maxRotation = m_maxRotation + speedNorm * (m_maxRotation2 - m_maxRotation); CalcLookAt(pose); if (m_lookAt.IsValid()) { if (!m_lastOffset.IsValid()) { m_position = pose * m_localSpaceCameraOffset; m_lastOffset = m_position - m_lookAt; m_lastOffsetBeforeElev = m_lastOffset; } Vec3 offset = m_lastOffsetBeforeElev; if (pedal < 0.1f && forwardSpeed < 1.0f) { // Going Backwards m_flags &= ~(eVCam_goingForwards | m_forwardFlags); m_flags |= m_backwardsFlags; } if (offset.dot(yAxis) < 0.8f && forwardSpeed > 1.f) { // Going Forwards m_flags &= ~m_backwardsFlags; m_flags |= eVCam_goingForwards | m_forwardFlags; } float sensitivity = (1.f - speedNorm) * m_stickSensitivity.z + speedNorm * m_stickSensitivity2.z; float rotate = -m_rotatingAction.z * sensitivity; rotate = rotate * dt; if (zAxis.z > 0.1f) { // Safe to update curYaw Vec3 projectedX = xAxis; projectedX.z = 0.f; Vec3 projectedY = yAxis; projectedY.z = 0.f; const float newYaw = atan2_tpl(offset.dot(projectedX), -(offset.dot(projectedY))); const float maxChange = DEG2RAD(270.f) * dt; const float delta = clamp_tpl(newYaw - m_curYaw, -maxChange, +maxChange); m_curYaw += delta; } // Rotation Action { if (m_flags & eVCam_rotationClamp) { float newYaw = clamp_tpl(m_curYaw + rotate, -maxRotation.z, +maxRotation.z); rotate = newYaw - m_curYaw; rotate = clamp_tpl(newYaw - m_curYaw, -fabsf(rotate), +fabsf(rotate)); m_rotation.z += rotate; } else { m_rotation.z = 0.f; } if (speedNorm > 0.1f) { float reduce = dt * 1.f; m_rotation.z = m_rotation.z - reduce * m_rotation.z / (fabsf(m_rotation.z) + reduce); } } // Ang Spring { float angSpeedCorrection = dt * dt * m_angSpeedCorrection / (dt * m_angSpeedCorrection + 1.f) * dynStatus.w.z; if ((m_flags & eVCam_rotationSpring) == 0) { m_angReturnSpeed = 0.f; angSpeedCorrection = 0.f; } float difference = m_rotation.z - m_curYaw; float relax = difference * (m_angReturnSpeed * dt) / ((m_angReturnSpeed * dt) + 1.f); const float delta = +relax + angSpeedCorrection + rotate; m_curYaw += delta; Matrix33 rot = Matrix33::CreateRotationZ(delta); offset = rot * offset; // Lerp the spring speed float angSpeedTarget = m_angReturnSpeed1 + speedNorm * (m_angReturnSpeed2 - m_angReturnSpeed1); m_angReturnSpeed += (angSpeedTarget - m_angReturnSpeed) * (dt / (dt + 0.3f)); m_angSpeedCorrection += (m_angSpeedCorrection0 - m_angSpeedCorrection) * (dt / (dt + 0.3f)); } if (!offset.IsValid()) offset = m_lastOffset; // Velocity influence Vec3 displacement = -((2.f - speedNorm) * dt) * dynStatus.v;// - yAxis*(0.0f*speedNorm*(yAxis.dot(dynStatus.v)))); float dot = offset.dot(displacement); if (dot < 0.f) { displacement = displacement + offset * -0.1f * (offset.dot(displacement) / offset.GetLengthSquared()); } offset = offset + displacement; const float radius0 = fabsf(m_localSpaceCameraOffset.y); const float minRadius = radius0 * m_radiusMin; const float maxRadius = radius0 * m_radiusMax; float radiusXY = sqrtf(sqr(offset.x) + sqr(offset.y)); Vec3 offsetXY = offset; offsetXY.z = 0.f; Vec3 accelerationV = (dynStatus.v - m_lastVehVel); float acceleration = offsetXY.dot(accelerationV) / radiusXY; m_lastVehVel = dynStatus.v; m_radiusVel -= acceleration; m_radius += m_radiusVel * dt - dt * m_radiusVelInfluence * offsetXY.dot(dynStatus.v) / radiusXY; m_radiusVel *= expf(-dt * m_radiusDampRate); m_radius += (radius0 - m_radius) * (dt * m_radiusRelaxRate) / (dt * m_radiusRelaxRate + 1.f); m_radius = clamp_tpl(m_radius, minRadius, maxRadius); offset = offset * (m_radius / radiusXY); // Vertical motion float targetOffsetHeight = m_localSpaceCameraOffset.z * (m_radius / radius0); float oldOffsetHeight = offset.z; offset.z += (targetOffsetHeight - offset.z) * (dt / (dt + 0.3f)); Limit(offset.z, targetOffsetHeight - 2.f, targetOffsetHeight + 2.f); float verticalChange = offset.z - oldOffsetHeight; m_lastOffsetBeforeElev = offset; // Add up and down camera tilt { offset.z -= verticalChange; m_rotation.x += dt * m_stickSensitivity.x * m_rotatingAction.x; m_rotation.x = clamp_tpl(m_rotation.x, -maxRotation.x, +maxRotation.x); float elevAngleVehicle = m_inheritedElev * yAxis.z; // yAxis.z == approx elevation angle float elevationAngle = m_rotation.x - elevAngleVehicle; float sinElev, cosElev; sincos_tpl(elevationAngle, &sinElev, &cosElev); float horizLen = sqrtf(offset.GetLengthSquared2D()); float horizLenNew = horizLen * cosElev - sinElev * offset.z; if (horizLen > 1e-4f) { horizLenNew /= horizLen; offset.x *= horizLenNew; offset.y *= horizLenNew; offset.z = offset.z * cosElev + sinElev * horizLen; } offset.z += verticalChange; } if (!offset.IsValid()) offset = m_lastOffset; m_position = m_lookAt + offset; // Perform world intersection test. { // Initialise sphere and direction. primitives::sphere sphere; sphere.center = m_lookAt; sphere.r = g_SteerCameraRadius; Vec3 direction = m_position - m_lookAt; // Calculate camera bounds. AABB localBounds; m_pVehicle->GetEntity()->GetLocalBounds(localBounds); const float cameraBoundsScale = 0.75f; localBounds.min *= cameraBoundsScale; localBounds.max *= cameraBoundsScale; OBB cameraBounds; Matrix34 worldTM = m_pVehicle->GetEntity()->GetWorldTM(); cameraBounds.SetOBBfromAABB(Matrix33(worldTM), localBounds); // Try to find point on edge of camera bounds to begin swept sphere intersection test. Vec3 rayBoxIntersect; if (Intersect::Ray_OBB(Ray(m_position, -direction), worldTM.GetTranslation(), cameraBounds, rayBoxIntersect) > 0) { Vec3 temp = m_position - rayBoxIntersect; if (direction.Dot(temp) > 0.0f) { sphere.center = rayBoxIntersect; direction = temp; } } // Perform swept sphere intersection test against world. geom_contact* pContact = NULL; IPhysicalEntity* pSkipEntities[10]; float distance = gEnv->pPhysicalWorld->PrimitiveWorldIntersection(sphere.type, &sphere, direction, 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, m_pVehicle->GetSkipEntities(pSkipEntities, 10)); if (distance > 0.0f) { // Sweep intersects world so calculate new offset. offset = (sphere.center + (direction.GetNormalizedSafe() * distance)) - m_lookAt; } } Interpolate(m_lastOffset, offset, 10.f, dt); m_position = m_lookAt + m_lastOffset; } else { CRY_ASSERT_MESSAGE(0, "camera will fail because lookat position is invalid"); } m_rotatingAction.zero(); }
//------------------------------------------------------------------------ void CVehicleMovementVTOL::ProcessActions(const float deltaTime) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); UpdateDamages(deltaTime); UpdateEngine(deltaTime); m_velDamp = 0.25f; m_playerControls.ProcessActions(deltaTime); Limit(m_forwardAction, -1.0f, 1.0f); Limit(m_strafeAction, -1.0f, 1.0f); m_actionYaw = 0.0f; Vec3 worldPos = m_pEntity->GetWorldPos(); IPhysicalEntity* pPhysics = GetPhysics(); // get the current state // roll pitch + yaw Matrix34 worldTM = m_pRotorPart ? m_pRotorPart->GetWorldTM() : m_pEntity->GetWorldTM(); // if (m_pRotorPart) // worldTM = m_pRotorPart->GetWorldTM(); // else // worldTM = m_pEntity->GetWorldTM(); Vec3 specialPos = worldTM.GetTranslation(); Ang3 angles = Ang3::GetAnglesXYZ(Matrix33(worldTM)); Matrix33 tm; tm.SetRotationXYZ((angles)); // +ve pitch means nose up const float& currentPitch = angles.x; // +ve roll means to the left const float& currentRoll = angles.y; // +ve direction mean rotation anti-clockwise about the z axis - 0 means along y float currentDir = angles.z; const float maxPitchAngle = 60.0f; float pitchDeg = RAD2DEG(currentPitch); if (pitchDeg >= (maxPitchAngle * 0.75f)) { float mult = pitchDeg / (maxPitchAngle); if (mult > 1.0f && m_desiredPitch < 0.0f) { m_desiredPitch *= 0.0f; m_actionPitch *= 0.0f; m_desiredPitch += 0.2f * mult; } else if (m_desiredPitch < 0.0f) { m_desiredPitch *= (1.0f - mult); m_desiredPitch += 0.05f; } } else if (pitchDeg <= (-maxPitchAngle * 0.75f)) { float mult = abs(pitchDeg) / (maxPitchAngle); if (mult > 1.0f && m_desiredPitch > 0.0f) { m_desiredPitch *= 0.0f; m_actionPitch *= 0.0f; m_desiredPitch += 0.2f * mult; } else if (m_desiredPitch > 0.0f) { m_desiredPitch *= (1.0f - mult); m_desiredPitch -= 0.05f; } } if (currentRoll >= DEG2RAD(m_maxRollAngle * 0.7f) && m_desiredRoll > 0.001f) { float r = currentRoll / DEG2RAD(m_maxRollAngle); r = min(1.0f, r * 1.0f); r = 1.0f - r; m_desiredRoll *= r; m_desiredRoll = min(1.0f, m_desiredRoll); } else if (currentRoll <= DEG2RAD(-m_maxRollAngle * 0.7f) && m_desiredRoll < 0.001f) { float r = abs(currentRoll) / DEG2RAD(m_maxRollAngle); r = min(1.0f, r * 1.0f); r = 1.0f - r; m_desiredRoll *= r; m_desiredRoll = max(-1.0f, m_desiredRoll); } Vec3 currentFwdDir2D = m_currentFwdDir; currentFwdDir2D.z = 0.0f; currentFwdDir2D.NormalizeSafe(); Vec3 currentLeftDir2D(-currentFwdDir2D.y, currentFwdDir2D.x, 0.0f); Vec3 currentVel = m_PhysDyn.v; Vec3 currentVel2D = currentVel; currentVel2D.z = 0.0f; float currentHeight = worldPos.z; float currentFwdSpeed = currentVel.Dot(currentFwdDir2D); ProcessActions_AdjustActions(deltaTime); float inputMult = m_basicSpeedFraction; // desired things float turnDecreaseScale = m_yawDecreaseWithSpeed / (m_yawDecreaseWithSpeed + fabs(currentFwdSpeed)); Vec3 desired_vel2D = currentFwdDir2D * m_forwardAction * m_maxFwdSpeed * inputMult + currentLeftDir2D * m_strafeAction * m_maxLeftSpeed * inputMult; // calculate the angle changes Vec3 desiredVelChange2D = desired_vel2D - currentVel2D; float desiredTiltAngle = m_tiltPerVelDifference * desiredVelChange2D.GetLength(); Limit(desiredTiltAngle, -m_maxTiltAngle, m_maxTiltAngle); float goal = abs(m_desiredPitch) + abs(m_desiredRoll); goal *= 1.5f; Interpolate(m_playerAcceleration, goal, 0.25f, deltaTime); Limit(m_playerAcceleration, 0.0f, 5.0f); //static float g_angleLift = 4.0f; if (abs(m_liftAction) > 0.001f && abs(m_forwardAction) < 0.001) { // float pitch = RAD2DEG(currentPitch); if (m_liftPitchAngle < 0.0f && m_liftAction > 0.0f) m_liftPitchAngle = 0.0f; else if (m_liftPitchAngle > 0.0f && m_liftAction < 0.0f) m_liftPitchAngle = 0.0f; Interpolate(m_liftPitchAngle, 1.25f * m_liftAction, 0.75f, deltaTime); if (m_liftPitchAngle < 1.0f && m_liftPitchAngle > -1.0f) m_desiredPitch += 0.05f * m_liftAction; } else if (m_liftAction < 0.001f && abs(m_liftPitchAngle) > 0.001) { Interpolate(m_liftPitchAngle, 0.0f, 1.0f, deltaTime); m_desiredPitch += 0.05f * -m_liftPitchAngle; } /* todo else if (m_liftAction < -0.001f) { m_desiredPitch += min(0.0f, (DEG2RAD(-5.0f) - currentPitch)) * 0.5f * m_liftAction; }*/ if (!iszero(m_desiredPitch)) { m_actionPitch -= m_desiredPitch * m_pitchInputConst; Limit(m_actionPitch, -m_maxYawRate, m_maxYawRate); } float rollAccel = 1.0f; if (abs(currentRoll + m_desiredRoll) < abs(currentRoll)) rollAccel *= 1.25f; m_actionRoll += m_pitchActionPerTilt * m_desiredRoll * rollAccel * (m_playerAcceleration + 1.0f); Limit(m_actionRoll, -10.0f, 10.0f); Limit(m_actionPitch, -10.0f, 10.0f); // roll as we turn if (!m_strafeAction) { m_actionYaw += m_yawPerRoll * currentRoll; } if (abs(m_strafeAction) > 0.001f) { float side = 0.0f; side = min(1.0f, max(-1.0f, m_strafeAction)); float roll = DEG2RAD(m_extraRollForTurn * 0.25f * side) - (currentRoll); m_actionRoll += max(0.0f, abs(roll)) * side * 1.0f; } float relaxRollTolerance = 0.0f; if (abs(m_turnAction) > 0.01f || abs(m_PhysDyn.w.z) > DEG2RAD(3.0f)) { m_actionYaw += -m_turnAction * m_yawInputConst * GetDamageMult(); float side = 0.0f; if (abs(m_turnAction) > 0.01f) side = min(1.0f, max(-1.0f, m_turnAction)); float roll = DEG2RAD(m_extraRollForTurn * side) - (currentRoll); m_actionRoll += max(0.0f, abs(roll)) * side * m_rollForTurnForce; roll *= max(1.0f, abs(m_PhysDyn.w.z)); m_actionRoll += roll; Limit(m_actionYaw, -m_maxYawRate, m_maxYawRate); } m_desiredDir = currentDir; m_lastDir = currentDir; float boost = Boosting() ? m_boostMult : 1.0f; float liftActionMax = 1.0f; if (m_pAltitudeLimitVar) { float altitudeLimit = m_pAltitudeLimitVar->GetFVal(); if (!iszero(altitudeLimit)) { float altitudeLowerOffset; if (m_pAltitudeLimitLowerOffsetVar) { float r = 1.0f - min(1.0f, max(0.0f, m_pAltitudeLimitLowerOffsetVar->GetFVal())); altitudeLowerOffset = r * altitudeLimit; } else altitudeLowerOffset = altitudeLimit; float mult = 1.0f; if (currentHeight >= altitudeLimit) { if (m_liftAction > 0.f) { mult = 0.0f; } } else if (currentHeight >= altitudeLowerOffset) { float zone = altitudeLimit - altitudeLowerOffset; mult = (altitudeLimit - currentHeight) / (zone); } m_liftAction *= mult; if (currentPitch > DEG2RAD(0.0f)) { if (m_forwardAction > 0.0f) m_forwardAction *= mult; if (m_actionPitch > 0.0f) { m_actionPitch *= mult; m_actionPitch += -currentPitch; } } m_desiredHeight = min(altitudeLowerOffset, currentHeight); } } else { m_desiredHeight = currentHeight; } if (abs(m_liftAction) > 0.001f) { m_liftAction = min(liftActionMax, max(-0.2f, m_liftAction)); m_hoveringPower = (m_powerInputConst * m_liftAction) * boost; m_noHoveringTimer = 0.0f; } else if (!m_isTouchingGround) { if (m_noHoveringTimer <= 0.0f) { float gravity; pe_simulation_params paramsSim; if (pPhysics->GetParams(¶msSim)) gravity = abs(paramsSim.gravity.z); else gravity = 9.2f; float upDirZ = m_workingUpDir.z; if (abs(m_forwardAction) > 0.01 && upDirZ > 0.0f) upDirZ = 1.0f; else if (upDirZ > 0.8f) upDirZ = 1.0f; float upPower = upDirZ; upPower -= min(1.0f, abs(m_forwardAction) * abs(angles.x)); float turbulenceMult = 1.0f - min(m_turbulenceMultMax, m_turbulence); Vec3& impulse = m_control.impulse; impulse += Vec3(0.0f, 0.0f, upPower) * gravity * turbulenceMult * GetDamageMult(); impulse.z -= m_PhysDyn.v.z * turbulenceMult; } else { m_noHoveringTimer -= deltaTime; } } if (m_pStabilizeVTOL) { float stabilizeTime = m_pStabilizeVTOL->GetFVal(); if (stabilizeTime > 0.0f) { if (m_relaxTimer < 6.0f) m_relaxTimer += deltaTime; else { float r = currentRoll - relaxRollTolerance; r = min(1.0f, max(-1.0f, r)); m_actionRoll += -r * m_relaxForce * (m_relaxTimer / 6.0f); } } } if (m_netActionSync.PublishActions( CNetworkMovementHelicopter(this) )) m_pVehicle->GetGameObject()->ChangedNetworkState(eEA_GameClientDynamic); }
//------------------------------------------------------------------------ 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 CVehicleMovementStdBoat::UpdateSurfaceEffects(const float deltaTime) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); if (0 == g_pGameCVars->v_pa_surface) { ResetParticles(); return; } IEntity* pEntity = m_pVehicle->GetEntity(); const Matrix34& worldTM = pEntity->GetWorldTM(); float distSq = worldTM.GetTranslation().GetSquaredDistance(gEnv->pRenderer->GetCamera().GetPosition()); if (distSq > sqr(300.f) || (distSq > sqr(50.f) && !m_pVehicle->GetGameObject()->IsProbablyVisible())) return; Matrix34 worldTMInv = worldTM.GetInverted(); const SVehicleStatus& status = m_pVehicle->GetStatus(); float velDot = status.vel * worldTM.GetColumn1(); float powerNorm = min(abs(m_movementAction.power), 1.f); SEnvironmentParticles* envParams = m_pPaParams->GetEnvironmentParticles(); SEnvParticleStatus::TEnvEmitters::iterator end = m_paStats.envStats.emitters.end(); for (SEnvParticleStatus::TEnvEmitters::iterator emitterIt = m_paStats.envStats.emitters.begin(); emitterIt!=end; ++emitterIt) { if (emitterIt->layer < 0) { assert(0); continue; } const SEnvironmentLayer& layer = envParams->GetLayer(emitterIt->layer); SEntitySlotInfo info; info.pParticleEmitter = 0; pEntity->GetSlotInfo(emitterIt->slot, info); float countScale = 1.f; float sizeScale = 1.f; float speedScale = 1.f; float speed = 0.f; // check if helper position is beneath water level Vec3 emitterWorldPos = worldTM * emitterIt->quatT.t; float waterLevel = gEnv->p3DEngine->GetWaterLevel(&emitterWorldPos); int matId = 0; if (emitterWorldPos.z <= waterLevel+0.1f && m_physStatus[k_mainThread].submergedFraction<0.999f) { matId = gEnv->pPhysicalWorld->GetWaterMat(); speed = status.speed; bool spray = !strcmp(layer.GetName(), "spray"); if (spray) { // slip based speed -= abs(velDot); } GetParticleScale(layer, speed, powerNorm, countScale, sizeScale, speedScale); } else { countScale = 0.f; } if (matId && matId != emitterIt->matId) { // change effect IParticleEffect* pEff = 0; const char* effect = GetEffectByIndex( matId, layer.GetName() ); if (effect && (pEff = gEnv->pParticleManager->FindEffect(effect))) { #if ENABLE_VEHICLE_DEBUG if (DebugParticles()) CryLog("%s changes water sfx to %s (slot %i)", pEntity->GetName(), effect, emitterIt->slot); #endif if (info.pParticleEmitter) { info.pParticleEmitter->Activate(false); pEntity->FreeSlot(emitterIt->slot); } emitterIt->slot = pEntity->LoadParticleEmitter(emitterIt->slot, pEff); if (emitterIt->slot != -1) pEntity->SetSlotLocalTM(emitterIt->slot, Matrix34(emitterIt->quatT)); info.pParticleEmitter = 0; pEntity->GetSlotInfo(emitterIt->slot, info); } else countScale = 0.f; } if (matId) emitterIt->matId = matId; if (info.pParticleEmitter) { SpawnParams sp; sp.fSizeScale = sizeScale; sp.fCountScale = countScale; sp.fSpeedScale = speedScale; info.pParticleEmitter->SetSpawnParams(sp); if (layer.alignToWater && countScale > 0.f) { Vec3 worldPos(emitterWorldPos.x, emitterWorldPos.y, waterLevel+0.05f); Matrix34 localTM(emitterIt->quatT); localTM.SetTranslation(worldTMInv * worldPos); pEntity->SetSlotLocalTM(emitterIt->slot, localTM); } } #if ENABLE_VEHICLE_DEBUG if (DebugParticles() && m_pVehicle->IsPlayerDriving()) { float color[] = {1,1,1,1}; ColorB red(255,0,0,255); IRenderAuxGeom* pAuxGeom = gEnv->pRenderer->GetIRenderAuxGeom(); const char* effect = info.pParticleEmitter ? info.pParticleEmitter->GetName() : ""; const Matrix34& slotTM = m_pEntity->GetSlotWorldTM(emitterIt->slot); Vec3 ppos = slotTM.GetTranslation(); pAuxGeom->DrawSphere(ppos, 0.2f, red); pAuxGeom->DrawCone(ppos, slotTM.GetColumn1(), 0.1f, 0.5f, red); gEnv->pRenderer->Draw2dLabel(50.f, (float)(400+10*emitterIt->slot), 1.2f, color, false, "<%s> water fx: slot %i [%s], speed %.1f, sizeScale %.2f, countScale %.2f (pos %.0f,%0.f,%0.f)", pEntity->GetName(), emitterIt->slot, effect, speed, sizeScale, countScale, ppos.x, ppos.y, ppos.z); } #endif } // generate water splashes Vec3 wakePos; if(m_pSplashPos) { wakePos = m_pSplashPos->GetWorldSpaceTranslation(); } else { wakePos = worldTM.GetTranslation(); } float wakeWaterLevel = gEnv->p3DEngine->GetWaterLevel(&wakePos); const Vec3& localW = m_localSpeed; if (localW.x >= 0.f) m_diving = false; if (!m_diving && localW.x < -0.03f && status.speed > 10.f && wakePos.z < m_lastWakePos.z && wakeWaterLevel+0.1f >= wakePos.z) { float speedRatio = min(1.f, status.speed/(m_maxSpeed*m_factorMaxSpeed)); m_diving = true; if (m_pWaveEffect) { if (IParticleEmitter* pEmitter = pEntity->GetParticleEmitter(m_wakeSlot)) { pEmitter->Activate(false); pEntity->FreeSlot(m_wakeSlot); m_wakeSlot = -1; } SpawnParams spawnParams; spawnParams.fSizeScale = spawnParams.fCountScale = 0.5f + 0.25f*speedRatio; spawnParams.fSizeScale += 0.4f*m_waveRandomMult; spawnParams.fCountScale += cry_random(0.0f, 0.4f); m_wakeSlot = pEntity->LoadParticleEmitter(m_wakeSlot, m_pWaveEffect, &spawnParams); } // handle splash sound ExecuteTrigger(eSID_Splash); SetSoundParam(eSID_Splash, "intensity", 0.2f*speedRatio + 0.5f*m_waveRandomMult); if (m_rpmPitchDir == 0) { m_rpmPitchDir = -1; m_waveSoundPitch = 0.f; m_waveSoundAmount = 0.02f + m_waveRandomMult*0.08f; } } if (m_wakeSlot != -1) { // update emitter local pos to short above waterlevel Matrix34 tm; if(m_pSplashPos) m_pSplashPos->GetVehicleTM(tm); else tm.SetIdentity(); Vec3 pos = tm.GetTranslation(); pos.z = worldTMInv.TransformPoint(Vec3(wakePos.x,wakePos.y,wakeWaterLevel)).z + 0.2f; tm.SetTranslation(pos); pEntity->SetSlotLocalTM(m_wakeSlot, tm); #if ENABLE_VEHICLE_DEBUG if (IsProfilingMovement()) { Vec3 wPos = worldTM * tm.GetTranslation(); ColorB col(128, 128, 0, 200); gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(wPos, 0.4f, col); gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(wPos, col, wPos+Vec3(0,0,1.5f), col); } #endif } m_lastWakePos = wakePos; }
bool CIntersectionAssistanceUnit::TestForIntersectionAtLocation(const eTestMethod testMethod, const Matrix34& wMat, EntityId testEntityId, EntityId ignoreEnt, QuatT& outAdjustedResult, const bool bCentreOnFocalEnt /* = false */, bool bRenderOnFail /* = true */, const int index /* = -1*/) { // Build an OOBB that surrounds this entity, test for intersection between that and world IEntity* pEntity = gEnv->pEntitySystem->GetEntity(testEntityId); if(pEntity) { IPhysicalEntity* pPhysical = pEntity->GetPhysics(); if(pPhysical) { OBB entOBB; AABB entAABB; pEntity->GetLocalBounds(entAABB); entOBB.SetOBBfromAABB(Quat(IDENTITY), entAABB); // Do Primitive world intersection primitives::box physBox; physBox.bOriented = 1; // LSpace physBox.center = entOBB.c; physBox.Basis = entOBB.m33; physBox.size.x = entOBB.h.x; physBox.size.y = entOBB.h.y; physBox.size.z = entOBB.h.z; // WSpace physBox.center = wMat.TransformPoint(physBox.center); physBox.Basis *= Matrix33(wMat).GetInverted(); // Optional tweak - We can get away with a little bit of scaling down (if edges are slightly embedded the physics pushes them out easily) physBox.size = physBox.size.scale(kPhysBoxScaleFactor); // adjust Vec3 vAdjustments(0.0f,0.0f,0.0f); if(bCentreOnFocalEnt && m_focalEntityId) { Vec3 vDesiredPos = CalculateTargetAdjustPoint(pEntity, wMat, physBox.center); vAdjustments = (vDesiredPos - physBox.center); physBox.center += vAdjustments; } IEntity* pIgnoreEnt = gEnv->pEntitySystem->GetEntity(ignoreEnt); IPhysicalEntity* pIgnorePhys = pIgnoreEnt ? pIgnoreEnt->GetPhysics() : NULL; // Test if(testMethod == eTM_Immediate #ifndef _RELEASE || g_pGameCVars->pl_pickAndThrow.intersectionAssistDebugEnabled >= 1 #endif // #ifndef _RELEASE ) { geom_contact *contacts; intersection_params params; float numHits = gEnv->pPhysicalWorld->PrimitiveWorldIntersection(primitives::box::type, &physBox, Vec3(ZERO), ent_static|ent_terrain, &contacts, 0, 3, ¶ms, 0, 0, &pIgnorePhys, pIgnorePhys ? 1 : 0); // Debug #ifndef _RELEASE if(g_pGameCVars->pl_pickAndThrow.intersectionAssistDebugEnabled) { const bool bIntersect = numHits <= 0.0f ? false : true; if(bRenderOnFail || !bIntersect) { const ColorB colorPositive = ColorB(16, 96, 16); const ColorB colorNegative = ColorB(128, 0, 0); const ColorB colorSelected = ColorB(0,255,0); if(numHits > 0.0f) { gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(contacts->pt, 0.1f, colorPositive); } OBB finalOBB; finalOBB.SetOBB(Matrix33(IDENTITY), physBox.size, Vec3(0.0f,0.0f,0.0f)); Matrix34 drawMat = wMat; drawMat.AddTranslation(physBox.center - wMat.GetTranslation()); if(index != -1 && index == m_currentBestIndex) { gEnv->pRenderer->GetIRenderAuxGeom()->DrawOBB(finalOBB, drawMat, false, colorSelected, eBBD_Faceted); } else { gEnv->pRenderer->GetIRenderAuxGeom()->DrawOBB(finalOBB, drawMat, false, bIntersect ? colorNegative : colorPositive, eBBD_Faceted); } } } #endif //#ifndef RELEASE // If we performed an adjust, make sure we pass out the QuatT representing the FINAL ENTITY POSITION that passed/failed (not the phys box etc) outAdjustedResult.t = wMat.GetTranslation() + vAdjustments; outAdjustedResult.q = Quat(wMat); #ifndef _RELEASE // allow optional debug drawing of last known good positions by retaining non adjusted position if(g_pGameCVars->pl_pickAndThrow.intersectionAssistDebugEnabled == 1) { outAdjustedResult.t = wMat.GetTranslation(); } #endif // #ifndef _RELEASE return (numHits > 0.0f); } else { // QUEUE primitive intersection check outAdjustedResult.t = wMat.GetTranslation() + vAdjustments; outAdjustedResult.q = Quat(wMat); CRY_ASSERT(index >= 0); m_intersectionTester.DoCheck(index,physBox,outAdjustedResult,pIgnorePhys); return false; } } } return false; }
//------------------------------------------------------------------------ void CVehicleMovementWarrior::Update(const float deltaTime) { FUNCTION_PROFILER(GetISystem(), PROFILE_GAME); if(!IsCollapsing()) CVehicleMovementHovercraft::Update(deltaTime); else CVehicleMovementBase::Update(deltaTime); if(IsCollapsing()) { m_collapseTimer += deltaTime; // check platform Vec3 platformPos; if(m_pPlatformPos) platformPos = m_pPlatformPos->GetWorldSpaceTranslation(); else platformPos.zero(); float dist = platformPos.z - gEnv->p3DEngine->GetTerrainElevation(platformPos.x, platformPos.y); if(dist < 1.f) { m_platformDown = true; } // center turret RotatePart(m_pTurret, DEG2RAD(0.f), AXIS_Z, DEG2RAD(2.5f), deltaTime); // take down wing and cannon RotatePart(m_pWing, DEG2RAD(-12.5f), AXIS_X, DEG2RAD(3.f), deltaTime); RotatePart(m_pCannon, DEG2RAD(-20.f), AXIS_X, DEG2RAD(2.5f), deltaTime); if(!m_platformDown) { // handle legs to bring down platform TThrusters::iterator iter; for(iter=m_vecThrusters.begin(); iter!=m_vecThrusters.end(); ++iter) { SThruster *pThruster = *iter; if(pThruster->heightAdaption <= 0.f) { pThruster->hoverHeight = max(0.1f, pThruster->hoverHeight - 0.6f*deltaTime); continue; } else { //if (!pThruster->groundContact) //pThruster->hoverHeight = max(0.1f, pThruster->hoverHeight - 0.2f*deltaTime); } /* // special legs control float collapseSpeed = DEG2RAD(5.f); float maxDistMovable = 1.f/0.8f; float dist = (isneg(pThruster->prevDist)) ? 0.f : pThruster->hoverHeight - pThruster->prevDist; if (isneg(dist)) { collapseSpeed *= max(0.f, 1.f + maxDistMovable*dist); } if (collapseSpeed > 0.f) { float angle = RotatePart(pThruster->pParentPart, DEG2RAD(m_collapsedLegAngle), collapseSpeed, deltaTime); RotatePart(pThruster->pPart, DEG2RAD(m_collapsedFeetAngle), collapseSpeed, deltaTime); } */ } } else { if(!m_collapsed) { Collapsed(true); } } } if(IsPowered() && !IsCollapsed()) { // "normal" legs control here bool bStartComplete = (m_startComplete > 1.5f); float adaptionSpeed = IsCollapsing() ? 0.8f : 1.5f; int t = 0; for(TThrusters::iterator iter=m_vecThrusters.begin(); iter!=m_vecThrusters.end(); ++iter) { SThruster *pThruster = *iter; ++t; if(pThruster->heightAdaption > 0.f && bStartComplete && pThruster->pPart && pThruster->pParentPart) { const char *footName = pThruster->pPart->GetName(); EWarriorMovement mode = eWM_Hovering; float correction = 0.f, maxCorrection = 0.f; // adjust legs float error = 0.f; if(!pThruster->hit) error = pThruster->hoverHeight; // when not hit, correct downwards else if(pThruster->prevDist > 0.f) error = pThruster->prevDist - pThruster->hoverHeight; if(mode != eWM_None && abs(error) > 0.05f) { float speed = max(0.1f, min(1.f, abs(error))) * adaptionSpeed; correction = -sgn(error) * min(speed*deltaTime, abs(error)); // correct up to error // don't correct more than heightAdaption allows maxCorrection = abs((pThruster->heightInitial + sgn(correction)*pThruster->heightAdaption) - pThruster->pos.z); float minCorrection = (pThruster->groundContact) ? 0.f : -maxCorrection; correction = CLAMP(correction, minCorrection, maxCorrection); if(abs(correction) > 0.0001f) { // positive correction for leg, negative for foot Matrix34 legLocal = pThruster->pParentPart->GetLocalBaseTM(); Matrix34 footLocal = pThruster->pPart->GetLocalBaseTM(); float radius = footLocal.GetTranslation().len(); float deltaAngle = correction / radius; // this assumes correction on circle (accurate enough for large radius) Matrix34 legTM = Matrix33(legLocal) * Matrix33::CreateRotationX(deltaAngle); Matrix34 footTM = Matrix33(footLocal) * Matrix33::CreateRotationX(-deltaAngle); legTM.SetTranslation(legLocal.GetTranslation()); footTM.SetTranslation(footLocal.GetTranslation()); pThruster->pParentPart->SetLocalBaseTM(legTM); pThruster->pPart->SetLocalBaseTM(footTM); } } if(IsProfilingMovement()) { static ICVar *pDebugLeg = gEnv->pConsole->GetCVar("warrior_debug_leg"); if(pDebugLeg && pDebugLeg->GetIVal() == t) { //CryLog("hoverErr %.2f, levelErr %.2f, neutralErr %.2f -> %s corr %.3f (max %.2f)", hoverError, levelError, neutralError, sMode, correction, maxCorrection); } } } } } // regain control if(m_collapseTimer > m_recoverTime) { Collapsed(false); } for(TThrusters::iterator it=m_vecThrusters.begin(); it!=m_vecThrusters.end(); ++it) { (*it)->groundContact = false; } }
//------------------------------------------------------------------------ void CGunTurret::UpdateOrientation(float deltaTime) { FUNCTION_PROFILER(GetISystem(), PROFILE_GAME); bool changed = false; bool searching = (m_targetId==0 && m_turretparams.searching); float speed = searching ? m_turretparams.search_speed : m_turretparams.turn_speed; assert(m_goalYaw >= 0.f && m_goalYaw <= gf_PI2); // update turret Matrix34 turretTM = GetEntity()->GetSlotLocalTM(eIGS_Aux0, false); Ang3 turretAngles(turretTM); if(turretAngles.z < 0.0f) turretAngles.z+=gf_PI2; if(cry_fabsf(m_goalYaw-turretAngles.z) > gf_PI) { if(m_goalYaw >= gf_PI) turretAngles.z += gf_PI2; else turretAngles.z -= gf_PI2; } if(m_turretparams.yaw_range < 360.f) { // reverse, to avoid forbidden range if(m_goalYaw > gf_PI && turretAngles.z < gf_PI) turretAngles.z += gf_PI2; else if(m_goalYaw < gf_PI && turretAngles.z > gf_PI) turretAngles.z -= gf_PI2; } if(cry_fabsf(turretAngles.z-m_goalYaw) > 0.001f) { Interp(turretAngles.z, m_goalYaw, speed, deltaTime, 0.25f*speed); if(m_turretSound == INVALID_SOUNDID && gEnv->IsClient()) m_turretSound = PlayAction(g_pItemStrings->turret); changed = true; } else if(m_turretSound != INVALID_SOUNDID) { StopSound(m_turretSound); m_turretSound = INVALID_SOUNDID; } if(changed) { turretTM.SetRotationXYZ(turretAngles,turretTM.GetTranslation()); GetEntity()->SetSlotLocalTM(eIGS_Aux0, turretTM); } // update weapon Matrix34 weaponTM = GetEntity()->GetSlotLocalTM(eIGS_ThirdPerson, false); Ang3 weaponAngles(weaponTM); weaponAngles.z = turretAngles.z; if(cry_fabsf(weaponAngles.x-m_goalPitch) > 0.001f) { Interp(weaponAngles.x, m_goalPitch, speed, deltaTime, 0.25f*speed); if(m_cannonSound == INVALID_SOUNDID && gEnv->IsClient()) m_cannonSound = PlayAction(g_pItemStrings->cannon); changed = true; } else if(m_cannonSound != INVALID_SOUNDID) { StopSound(m_cannonSound); m_cannonSound = INVALID_SOUNDID; } if(changed) { weaponTM.SetRotationXYZ(weaponAngles); Vec3 w_trans = turretTM.TransformPoint(m_radarHelperPos); //Vec3 w_trans = GetSlotHelperPos(eIGS_Aux0,m_radarHelper.c_str(),false); weaponTM.SetTranslation(w_trans); GetEntity()->SetSlotLocalTM(eIGS_ThirdPerson, weaponTM); if(GetEntity()->IsSlotValid(eIGS_Aux1)) { Vec3 b_trans = weaponTM.TransformPoint(m_barrelHelperPos); //Vec3 b_trans = GetSlotHelperPos(eIGS_ThirdPerson,m_barrelHelper.c_str(),false); weaponTM.SetTranslation(b_trans); GetEntity()->SetSlotLocalTM(eIGS_Aux1, weaponTM*m_barrelRotation); } if(gEnv->IsClient()) { for(TEffectInfoMap::const_iterator it=m_effects.begin(); it!=m_effects.end(); ++it) { Matrix34 tm(GetSlotHelperRotation(eIGS_ThirdPerson,it->second.helper.c_str(),true), GetSlotHelperPos(eIGS_ThirdPerson,it->second.helper.c_str(),true)); SetEffectWorldTM(it->first, tm); } } } UpdatePhysics(); if(g_pGameCVars->i_debug_turrets == eGTD_Basic) { DrawDebug(); //gEnv->pRenderer->DrawLabel(GetEntity()->GetWorldPos(), 1.4f, "%s yaw: %.2f, goalYaw: %.2f (%.2f), goalPitch: %.2f (%.2f/%.2f)", searching?"[search]":"", RAD2DEG(turretAngles.z), RAD2DEG(m_goalYaw), 0.5f*(m_turretparams.yaw_range), RAD2DEG(m_goalPitch), m_turretparams.min_pitch, m_turretparams.max_pitch); } }
//------------------------------------------------------------------------ EntityEffects::TAttachedEffectId CItem::AttachEffect(int slot, bool attachToAccessory, const char *effectName, const char *helper, const Vec3 &offset, const Vec3 &dir, float scale, bool prime) { if(!g_pGameCVars->i_particleeffects) { return 0; } Vec3 finalOffset(offset); string helperName(helper); if(attachToAccessory) { SEntitySlotInfo slotInfo; QuatT accessoryOffset; accessoryOffset.SetIdentity(); const char* accessoryHelper = ""; const char* accessoryName = NULL; const int numAccessories = m_accessories.size(); for (int curIndex = 0; curIndex < numAccessories; curIndex++) { IEntity* pAccessory = gEnv->pEntitySystem->GetEntity(m_accessories[curIndex].accessoryId); if(pAccessory && pAccessory->GetSlotInfo(slot, slotInfo)) { if(slotInfo.pStatObj) { accessoryOffset.t = slotInfo.pStatObj->GetHelperPos(helper); if(!accessoryOffset.t.IsZero()) { accessoryOffset.q = pAccessory->GetRotation(); accessoryOffset.t += pAccessory->GetPos(); accessoryName = m_accessories[curIndex].pClass->GetName(); break; } } if(slotInfo.pCharacter) { IAttachmentManager *pAttachmentManager = slotInfo.pCharacter->GetIAttachmentManager(); IAttachment *pAttachment = pAttachmentManager->GetInterfaceByName(helper); if(pAttachment) { accessoryHelper = GetAccessoryParams(m_accessories[curIndex].pClass)->attach_helper.c_str(); accessoryName = m_accessories[curIndex].pClass->GetName(); accessoryOffset = pAttachment->GetAttAbsoluteDefault(); break; } } } } if(accessoryName) { bool validSlot = GetEntity()->GetSlotInfo(slot, slotInfo) && (slotInfo.pCharacter || slotInfo.pStatObj); if (!validSlot || slotInfo.pStatObj) { if (validSlot) { Matrix34 mtx = GetEntity()->GetSlotLocalTM(slot, false) * Matrix34(accessoryOffset); finalOffset += mtx.GetTranslation(); } EntityEffects::SEffectAttachParams attachParams(finalOffset, dir, scale, prime, eIGS_Last); return m_effectsController.AttachParticleEffect(effectName, attachParams); } else if (slotInfo.pCharacter) // bone attachment { ICharacterInstance *pCharacter = slotInfo.pCharacter; IAttachmentManager *pAttachmentManager = pCharacter->GetIAttachmentManager(); IAttachment *pAttachment = NULL; helperName = string().Format("%s_%s", helper, accessoryName); pAttachment = pAttachmentManager->GetInterfaceByName(helperName.c_str()); if(!pAttachment) { IAttachment* pAccessoryAttachment = pAttachmentManager->GetInterfaceByName(accessoryHelper); if(pAccessoryAttachment) { const char* bone = pCharacter->GetIDefaultSkeleton().GetJointNameByID(pAccessoryAttachment->GetJointID()); pAttachment = pAttachmentManager->CreateAttachment(helperName.c_str(), CA_BONE, bone); if (pAttachment) { QuatT relative = pAccessoryAttachment->GetAttRelativeDefault(); relative = relative * accessoryOffset; relative.t = relative * finalOffset; finalOffset.zero(); pAttachment->SetAttRelativeDefault(relative); } } } } } } EntityEffects::SEffectAttachParams attachParams(finalOffset, dir, scale, prime, eIGS_Last); return m_effectsController.AttachParticleEffect(effectName, slot, helperName, attachParams); }
void CPlayerView::ViewSpectatorTarget(SViewParams &viewParams) { CActor* pTarget = (CActor*)g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(m_in.stats_spectatorTarget); if(!pTarget) return; IVehicle* pVehicle = pTarget->GetLinkedVehicle(); static float defaultOffset = 0.3f; static float viewHeight = 1.8f; Matrix34 worldTM = pTarget->GetEntity()->GetWorldTM(); Vec3 worldPos = worldTM.GetTranslation(); if(!pVehicle) { const SStanceInfo* stanceInfo = pTarget->GetStanceInfo(pTarget->GetStance()); if(stanceInfo) { Interpolate(viewHeight, stanceInfo->viewOffset.z, 5.0f, viewParams.frameTime); worldPos.z += viewHeight + defaultOffset; } else { worldPos.z += 1.8f; } } else { // use vehicle pos/ori worldTM = pVehicle->GetEntity()->GetWorldTM(); worldPos = pVehicle->GetEntity()->GetWorldPos(); worldPos.z += 1.5f; } Ang3 worldAngles = Ang3::GetAnglesXYZ(Matrix33(worldTM)); float distance = 3; // if freelook allowed, get orientation and distance from player entity if(g_pGameCVars->g_spectate_FixedOrientation == 0) { CPlayer* pThisPlayer = static_cast<CPlayer*>(g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(m_in.entityId)); if(!pThisPlayer) return; Matrix34 ownOrientation = pThisPlayer->GetEntity()->GetWorldTM(); worldAngles += Ang3::GetAnglesXYZ(Matrix33(ownOrientation)); distance = pThisPlayer->GetSpectatorZoom(); } if(pVehicle) { distance *= 4.0f; // air vehicles need bigger distance if(pVehicle->GetMovement() && pVehicle->GetMovement()->GetMovementType() == IVehicleMovement::eVMT_Air) distance *= 2.0f; } Vec3 goal; goal.x = distance * cos(worldAngles.z + gf_PI*1.5f) + worldPos.x; goal.y = distance * sin(worldAngles.z - gf_PI/2.0f) + worldPos.y; AABB targetBounds; pTarget->GetEntity()->GetLocalBounds(targetBounds); goal.z = targetBounds.max.z; float offset = defaultOffset; if(pVehicle) { if(pVehicle->GetMovement() && pVehicle->GetMovement()->GetMovementType() == IVehicleMovement::eVMT_Air) offset = 3.0f; else offset = 1.0f; } goal.z += pTarget->GetEntity()->GetWorldPos().z + offset; // store / interpolate the offset, not the world pos (reduces percieved jitter in vehicles) static Vec3 viewOffset(goal-worldPos); static Vec3 camPos(goal); static Vec3 entPos(worldPos); static EntityId lastSpectatorTarget(m_in.stats_spectatorTarget); // do a ray cast to check for camera intersection static ray_hit hit; IPhysicalEntity* pSkipEntities[10]; int nSkip = 0; if(pVehicle) { // vehicle drivers don't seem to have current items, so need to add the vehicle itself here nSkip = pVehicle->GetSkipEntities(pSkipEntities, 10); } else { IItem* pItem = pTarget->GetCurrentItem(); if (pItem) { CWeapon* pWeapon = (CWeapon*)pItem->GetIWeapon(); if (pWeapon) nSkip = CSingle::GetSkipEntities(pWeapon, pSkipEntities, 10); } } static float minDist = 0.4f; // how close we're allowed to get to the target static float wallSafeDistance = 0.3f; // how far to keep camera from walls Vec3 dir = goal - worldPos; primitives::sphere sphere; sphere.center = worldPos; sphere.r = wallSafeDistance; geom_contact *pContact = 0; float hitDist = 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, nSkip); // even when we have contact, keep the camera the same height above the target float minHeightDiff = dir.z; if(hitDist > 0 && pContact) { goal = worldPos + (hitDist * dir.GetNormalizedSafe()); if(goal.z - worldPos.z < minHeightDiff) { // can't move the camera far enough away from the player in this direction. Try moving it directly up a bit int numHits = 0; sphere.center = goal; // (move back just slightly to avoid colliding with the wall we've already found...) sphere.center -= dir.GetNormalizedSafe() * 0.05f; float newHitDist = gEnv->pPhysicalWorld->PrimitiveWorldIntersection(sphere.type, &sphere, Vec3(0,0,minHeightDiff), 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, nSkip); float raiseDist = minHeightDiff - (goal.z - worldPos.z) - wallSafeDistance; if(newHitDist != 0) { raiseDist = MIN(minHeightDiff, newHitDist); } raiseDist = MAX(0.0f, raiseDist); goal.z += raiseDist; worldPos.z += raiseDist*0.8f; } } int thisFrameId = gEnv->pRenderer->GetFrameID(); static int frameNo(thisFrameId); if(thisFrameId - frameNo > 5) { // reset positions viewOffset = goal - worldPos; entPos = worldPos; camPos = goal; } if(lastSpectatorTarget != m_in.stats_spectatorTarget) { viewOffset = goal - worldPos; entPos = worldPos; camPos = goal; lastSpectatorTarget = m_in.stats_spectatorTarget; } frameNo = thisFrameId; static float interpSpeed = 5.0f; static float interpSpeed2 = 5.0f; static float interpSpeed3 = 8.0f; if(pVehicle) { Interpolate(viewOffset, goal-worldPos, interpSpeed, viewParams.frameTime); entPos = worldPos; viewParams.position = worldPos + viewOffset; camPos = viewParams.position; } else { Vec3 camPosChange = goal - camPos; Vec3 entPosChange = worldPos - entPos; if(camPosChange.GetLengthSquared() > 100.0f) camPos = goal; if(entPosChange.GetLengthSquared() > 100.0f) entPos = worldPos; Interpolate(camPos, goal, interpSpeed2, viewParams.frameTime); Interpolate(entPos, worldPos, interpSpeed3, viewParams.frameTime); viewParams.position = camPos; } Matrix33 rotation = Matrix33::CreateRotationVDir((entPos - viewParams.position).GetNormalizedSafe()); viewParams.rotation = GetQuatFromMat33(rotation); m_io.bUsePivot = true; m_io.stats_bobCycle = 0.0; }
void CPlayerView::ViewDeathCamTarget(SViewParams &viewParams) { CActor* pTarget = (CActor*)g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(m_in.stats_spectatorTarget); if(!pTarget) return; Matrix34 targetWorldTM = pTarget->GetEntity()->GetWorldTM(); Vec3 camPos = viewParams.position; static float offset = 1.5f; camPos.z += offset; float heightOffset = 1.5f; const SStanceInfo* pSI = pTarget->GetStanceInfo(pTarget->GetStance()); if(pSI) { heightOffset = pSI->viewOffset.z; } Vec3 targetPos = targetWorldTM.GetTranslation(); targetPos.z += heightOffset; int thisFrameId = gEnv->pRenderer->GetFrameID(); static int frameNo(thisFrameId); static Vec3 oldCamPos(camPos); static Vec3 oldTargetPos(targetPos); static EntityId lastSpectatorTarget(m_in.stats_spectatorTarget); static float oldFOVScale(1.0f); // if more than a few frames have passed since our last update, invalidate the positions if(thisFrameId - frameNo > 5) { oldCamPos = viewParams.position; // interpolate from current camera pos oldTargetPos = targetPos; oldFOVScale = 1.0f; } // if target changed, reset positions if(lastSpectatorTarget != m_in.stats_spectatorTarget) { oldCamPos = camPos; oldTargetPos = targetPos; lastSpectatorTarget = m_in.stats_spectatorTarget; oldFOVScale = 1.0f; } frameNo = thisFrameId; // slight zoom after 2s float timeNow = gEnv->pTimer->GetCurrTime(); float distSq = (targetPos - camPos).GetLengthSquared(); float scale = 1.0f; if(timeNow - m_in.deathTime > 1.0f && distSq > 2500.0f) { // 1.0f at 50m, 0.3f at 100m+ scale = 1.0f - (distSq - 2500.0f)/25000.0f; scale = CLAMP(scale, 0.3f, 1.0f); } Interpolate(oldCamPos, camPos, 5.0f, viewParams.frameTime); Interpolate(oldTargetPos, targetPos, 5.0f, viewParams.frameTime); Interpolate(oldFOVScale, scale, 0.5f, viewParams.frameTime); viewParams.position = oldCamPos; Vec3 dir = (oldTargetPos - oldCamPos).GetNormalizedSafe(); Matrix33 rotation = Matrix33::CreateRotationVDir(dir); dir.z = 0.0f; // quick ray check to make sure there's not a wall in the way... IActor* pActor = g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(m_in.entityId); if (pActor) { static ray_hit hit; IPhysicalEntity* pSkipEntities[10]; int nSkip = 0; IItem* pItem = pActor->GetCurrentItem(); if (pItem) { CWeapon* pWeapon = (CWeapon*)pItem->GetIWeapon(); if (pWeapon) nSkip = CSingle::GetSkipEntities(pWeapon, pSkipEntities, 10); } if (gEnv->pPhysicalWorld->RayWorldIntersection(viewParams.position, -dir, ent_static|ent_terrain|ent_rigid, rwi_ignore_noncolliding | rwi_stop_at_pierceable, &hit, 1, pSkipEntities, nSkip)) { dir.zero(); } } viewParams.position -= dir; viewParams.fov = m_in.defaultFov*oldFOVScale*(gf_PI/180.0f);; viewParams.rotation = GetQuatFromMat33(rotation); m_io.bUsePivot = true; m_io.stats_bobCycle = 0.0; }
//------------------------------------------------------------------------ bool CVehicleViewFirstPerson::Init(IVehicleSeat* pISeat, const CVehicleParams& table) { CVehicleSeat* pSeat = static_cast<CVehicleSeat*>(pISeat); if (!CVehicleViewBase::Init(pSeat, table)) return false; if (CVehicleParams paramsTable = table.findChild(m_name)) { paramsTable.getAttr("offset", m_offset); paramsTable.getAttr("hidePlayer", m_hidePlayer); paramsTable.getAttr("hideVehicle", m_hideVehicle); paramsTable.getAttr("relativeToHorizon", m_relToHorizon); paramsTable.getAttr("followSpeed", m_speedRot); float viewFov; if(paramsTable.getAttr("fov", viewFov)) { m_fov = DEG2RAD(viewFov); } m_sCharacterBoneName = paramsTable.getAttr("characterBone"); string helperName = paramsTable.getAttr("helper"); if (!helperName.empty()) { if (helperName != "auto") { m_pHelper = m_pVehicle->GetHelper(helperName); } else { // create a helper with default viewpos above sithelper const string& seatName = pSeat->GetName(); helperName = seatName + string("_ghostview_pos"); if (IVehicleHelper* pSitHelper = pSeat->GetSitHelper()) { Matrix34 tm; pSitHelper->GetVehicleTM(tm); Vec3 pos = tm.GetTranslation() + Vec3(0,0,0.625); // player eye height m_pVehicle->AddHelper(helperName.c_str(), pos, tm.GetColumn1(), pSitHelper->GetParentPart()); m_pHelper = m_pVehicle->GetHelper(helperName.c_str()); } } if (!m_pHelper) GameWarning("[%s, seat %s]: view helper %s not found, using character head", m_pVehicle->GetEntity()->GetName(), m_pSeat->GetName().c_str(), helperName.c_str()); } string frame = paramsTable.getAttr("frameObject"); if (!frame.empty()) { // todo: aspect ratio? if (strstr(frame, ".cgf")) m_frameSlot = m_pVehicle->GetEntity()->LoadGeometry(-1, frame); else m_frameSlot = m_pVehicle->GetEntity()->LoadCharacter(-1, frame); if (m_frameSlot != -1) { m_pVehicle->GetEntity()->SetSlotFlags(m_frameSlot, m_pVehicle->GetEntity()->GetSlotFlags(m_frameSlot) &~ (ENTITY_SLOT_RENDER|ENTITY_SLOT_RENDER_NEAREST)); if (m_pHelper) { Matrix34 tm; m_pHelper->GetVehicleTM(tm); m_invFrame = tm.GetInverted(); m_pVehicle->GetEntity()->SetSlotLocalTM(m_frameSlot, tm); } } } paramsTable.getAttr("frameObjectOffset", m_frameObjectOffset); } if (m_hideVehicle) m_hidePlayer = true; if (m_speedRot==0.f) { m_speedRot = 4.0f; if (IVehicleMovement* pMovement = m_pVehicle->GetMovement()) { if (pMovement->GetMovementType() == IVehicleMovement::eVMT_Air) { m_speedRot *= 2.0f; } } } Reset(); return true; }
//------------------------------------------------------------------------ void CView::Update(float frameTime,bool isActive) { //FIXME:some cameras may need to be updated always if (!isActive) return; CGameObject * pLinkedTo = GetLinkedGameObject(); if (pLinkedTo && !pLinkedTo->CanUpdateView()) pLinkedTo = NULL; IEntity* pEntity = pLinkedTo ? 0 : GetLinkedEntity(); if (pLinkedTo || pEntity) { m_viewParams.SaveLast(); CCamera *pSysCam = &m_pSystem->GetViewCamera(); //process screen shaking ProcessShaking(frameTime); //FIXME:to let the updateView implementation use the correct shakeVector m_viewParams.currentShakeShift = m_viewParams.rotation * m_viewParams.currentShakeShift; m_viewParams.frameTime=frameTime; //update view position/rotation if (pLinkedTo) { pLinkedTo->UpdateView(m_viewParams); if (!m_viewParams.position.IsValid()) { m_viewParams.position = m_viewParams.GetPositionLast(); CRY_ASSERT_MESSAGE(0, "Camera position is invalid, reverting to old position"); } if (!m_viewParams.rotation.IsValid()) { m_viewParams.rotation = m_viewParams.GetRotationLast(); CRY_ASSERT_MESSAGE(0, "Camera rotation is invalid, reverting to old rotation"); } } else { Matrix34 mat = pEntity->GetWorldTM(); mat.OrthonormalizeFast(); m_viewParams.position = mat.GetTranslation(); m_viewParams.rotation = Quat(mat); } ApplyFrameAdditiveAngles(m_viewParams.rotation); if (pLinkedTo) { pLinkedTo->PostUpdateView(m_viewParams); } float fNearZ = gEnv->pGame->GetIGameFramework()->GetIViewSystem()->GetDefaultZNear(); //see if the view have to use a custom near clipping plane float nearPlane = (m_viewParams.nearplane > 0.01f)?(m_viewParams.nearplane):(fNearZ/*pSysCam->GetNearPlane()*/); float farPlane = gEnv->p3DEngine->GetMaxViewDistance(); float fov = m_viewParams.fov < 0.001 ? DEFAULT_FOV : m_viewParams.fov; m_camera.SetFrustum(pSysCam->GetViewSurfaceX(),pSysCam->GetViewSurfaceZ(),fov,nearPlane,farPlane, pSysCam->GetPixelAspectRatio()); //TODO: (14, 06, 2010, "the player view should always get updated, this due to the hud being visable, without shocking, in cutscenes - todo is to see if we can optimise this code"); IActor * pActor = gEnv->pGame->GetIGameFramework()->GetClientActor(); if (pActor) { CGameObject * linkToObj = (CGameObject*)pActor->GetEntity()->GetProxy( ENTITY_PROXY_USER ); if (linkToObj && linkToObj != pLinkedTo) { linkToObj->PostUpdateView(m_viewParams); } } //apply shake & set the view matrix m_viewParams.rotation *= m_viewParams.currentShakeQuat; m_viewParams.rotation.NormalizeSafe(); m_viewParams.position += m_viewParams.currentShakeShift; // Camera space Rendering calculations on Entity if(pLinkedTo) { IEntity* pLinkedToEntity = pLinkedTo->GetEntity(); if(pLinkedToEntity) { const int slotIndex = 0; uint32 entityFlags = pLinkedToEntity->GetSlotFlags(slotIndex); if(entityFlags & ENTITY_SLOT_RENDER_NEAREST) { // Get camera pos relative to entity const Vec3 cameraLocalPos = m_viewParams.position; // Set entity's camera space position const Vec3 cameraSpacePos(-cameraLocalPos * m_viewParams.rotation); pLinkedToEntity->SetSlotCameraSpacePos(slotIndex,cameraSpacePos); // Add world pos onto camera local pos m_viewParams.position = pLinkedToEntity->GetWorldPos() + cameraLocalPos; } } } // Blending between cameras needs to happen after Camera space rendering calculations have been applied // so that the m_viewParams.position is in World Space again m_viewParams.UpdateBlending(frameTime); Matrix34 viewMtx(m_viewParams.rotation); viewMtx.SetTranslation(m_viewParams.position); m_camera.SetMatrix(viewMtx); } else { m_linkedTo = 0; CCryAction *pCryAction = CCryAction::GetCryAction(); if (!pCryAction->IsGameSessionMigrating()) // If we're host migrating, leave the camera where it was { // Check if we're leaving a game mid way through - if we are then stop the camera from being reset for a frame or 2 before the unload happens if (!pCryAction->GetIGameSessionHandler()->IsMidGameLeaving()) { m_camera.SetPosition(Vec3(1,1,1)); } } } }
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 CPlayerView::ViewSpectatorTarget(SViewParams &viewParams) { CActor *pTarget = (CActor *)g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(m_in.stats_spectatorTarget); if(!pTarget) { return; } Matrix34 worldTM = pTarget->GetEntity()->GetWorldTM(); Vec3 worldPos = worldTM.GetTranslation(); worldPos.z += 1.5f; Ang3 worldAngles = Ang3::GetAnglesXYZ(Matrix33(worldTM)); float rot = worldAngles.z;// + m_rot; float distance = 3;//(m_defaultDistance != 0) ? m_defaultDistance : m_distance; if(IVehicle *pVehicle = pTarget->GetLinkedVehicle()) { AABB vehicleBox; pVehicle->GetEntity()->GetLocalBounds(vehicleBox); distance = 2.0f * vehicleBox.GetRadius(); } Vec3 goal; float zoom = 1.0f; goal.x = distance * zoom * cosf(rot + gf_PI * 1.5f) + worldPos.x; goal.y = distance * zoom * sinf(rot - gf_PI / 2.0f) + worldPos.y; AABB targetBounds; pTarget->GetEntity()->GetLocalBounds(targetBounds); goal.z = targetBounds.max.z; static float defaultOffset = 0.75f; float offset = defaultOffset; if(pTarget->GetLinkedVehicle()) { offset = 2.0f; } goal.z += pTarget->GetEntity()->GetWorldPos().z + offset; // store / interpolate the offset, not the world pos (reduces percieved jitter in vehicles) static Vec3 viewOffset(goal - worldPos); static Vec3 position(goal); static Vec3 entPos(worldPos); static EntityId lastSpectatorTarget(m_in.stats_spectatorTarget); // do a ray cast to check for camera intersection static ray_hit hit; IPhysicalEntity *pSkipEntities[10]; int nSkip = 0; IItem *pItem = pTarget->GetCurrentItem(); if (pItem) { CWeapon *pWeapon = (CWeapon *)pItem->GetIWeapon(); if (pWeapon) { nSkip = CSingle::GetSkipEntities(pWeapon, pSkipEntities, 10); } } else if(IVehicle *pVehicle = pTarget->GetLinkedVehicle()) { // vehicle drivers don't seem to have current items, so need to add the vehicle itself here nSkip = pVehicle->GetSkipEntities(pSkipEntities, 10); } const float wallSafeDistance = 0.2f; // how far to keep camera from walls Vec3 dir = goal - worldPos; primitives::sphere sphere; sphere.center = worldPos; sphere.r = wallSafeDistance; geom_contact *pContact = 0; float hitDist = gEnv->pPhysicalWorld->PrimitiveWorldIntersection(sphere.type, &sphere, dir, ent_static | ent_terrain | ent_rigid | ent_sleeping_rigid, &pContact, 0, geom_colltype_player, 0, 0, 0, pSkipEntities, nSkip); // even when we have contact, keep the camera the same height above the target float minHeightDiff = dir.z; if(hitDist > 0 && pContact) { goal = worldPos + (hitDist * dir.GetNormalizedSafe()); if(goal.z - worldPos.z < minHeightDiff) { // can't move the camera far enough away from the player in this direction. Try moving it directly up a bit sphere.center = goal; // (move back just slightly to avoid colliding with the wall we've already found...) sphere.center -= dir.GetNormalizedSafe() * 0.05f; float newHitDist = gEnv->pPhysicalWorld->PrimitiveWorldIntersection(sphere.type, &sphere, Vec3(0, 0, minHeightDiff), ent_static | ent_terrain | ent_rigid | ent_sleeping_rigid, &pContact, 0, geom_colltype_player, 0, 0, 0, pSkipEntities, nSkip); float raiseDist = minHeightDiff - (goal.z - worldPos.z) - wallSafeDistance; if(newHitDist != 0) { raiseDist = MIN(minHeightDiff, newHitDist); } raiseDist = MAX(0.0f, raiseDist); goal.z += raiseDist; worldPos.z += raiseDist * 0.8f; } } int thisFrameId = gEnv->pRenderer->GetFrameID(); static int frameNo(thisFrameId); if(thisFrameId - frameNo > 5) { // reset positions viewOffset = goal - worldPos; entPos = worldPos; position = goal; } if(lastSpectatorTarget != m_in.stats_spectatorTarget) { viewOffset = goal - worldPos; entPos = worldPos; position = goal; lastSpectatorTarget = m_in.stats_spectatorTarget; } frameNo = thisFrameId; if(pTarget->GetLinkedVehicle()) { Interpolate(viewOffset, goal - worldPos, 5.0f, viewParams.frameTime); entPos = worldPos; viewParams.position = worldPos + viewOffset; position = viewParams.position; } else { Vec3 camPosChange = goal - position; Vec3 entPosChange = worldPos - entPos; if(camPosChange.GetLengthSquared() > 100.0f) { position = goal; } if(entPosChange.GetLengthSquared() > 100.0f) { entPos = worldPos; } Interpolate(position, goal, 5.0f, viewParams.frameTime); Interpolate(entPos, worldPos, 5.0f, viewParams.frameTime); viewParams.position = position; } Matrix33 rotation = Matrix33::CreateRotationVDir((entPos - viewParams.position).GetNormalizedSafe()); viewParams.rotation = Quat(rotation); m_io.bUsePivot = true; m_io.stats_bobCycle = 0.0; }
//------------------------------------------------------------------------ Vec3 CVehicleHelper::GetWorldSpaceTranslation() const { Matrix34 temp; GetWorldTM(temp); return temp.GetTranslation(); }
//------------------------------------------------------------------------ void CView::Update(float frameTime,bool isActive) { //FIXME:some cameras may need to be updated always if (!isActive) return; CGameObject* pLinkedTo = GetLinkedGameObject(); if (pLinkedTo && !pLinkedTo->CanUpdateView()) pLinkedTo = nullptr; IEntity* pEntity = pLinkedTo ? 0 : GetLinkedEntity(); if (pLinkedTo || pEntity) { m_viewParams.SaveLast(); CCamera* pSysCam = &m_pSystem->GetViewCamera(); //process screen shaking ProcessShaking(frameTime); //FIXME:to let the updateView implementation use the correct shakeVector m_viewParams.currentShakeShift = m_viewParams.rotation * m_viewParams.currentShakeShift; m_viewParams.frameTime = frameTime; //update view position/rotation if (pLinkedTo) { pLinkedTo->UpdateView(m_viewParams); if (!m_viewParams.position.IsValid()) { m_viewParams.position = m_viewParams.GetPositionLast(); CRY_ASSERT_MESSAGE(0, "Camera position is invalid, reverting to old position"); } if (!m_viewParams.rotation.IsValid()) { m_viewParams.rotation = m_viewParams.GetRotationLast(); CRY_ASSERT_MESSAGE(0, "Camera rotation is invalid, reverting to old rotation"); } } else { Matrix34 mat = pEntity->GetWorldTM(); mat.OrthonormalizeFast(); m_viewParams.position = mat.GetTranslation(); m_viewParams.rotation = Quat(mat); } ApplyFrameAdditiveAngles(m_viewParams.rotation); if (pLinkedTo) { pLinkedTo->PostUpdateView(m_viewParams); } const float fNearZ = gEnv->pGame->GetIGameFramework()->GetIViewSystem()->GetDefaultZNear(); //see if the view have to use a custom near clipping plane const float nearPlane = (m_viewParams.nearplane >= 0.01f) ? (m_viewParams.nearplane) : fNearZ; const float farPlane = gEnv->p3DEngine->GetMaxViewDistance(); float fov = (m_viewParams.fov < 0.001f) ? DEFAULT_FOV : m_viewParams.fov; // [VR] specific // Modify FOV based on the HDM device configuration IHmdManager* pHmdManager = gEnv->pSystem->GetHmdManager(); IHmdDevice* pHmdDevice = nullptr; bool bHmdTrackingEnabled = false; if (pHmdManager) { pHmdDevice = pHmdManager->GetHmdDevice(); if (pHmdDevice) { const HmdTrackingState &sensorState = pHmdDevice->GetLocalTrackingState(); if (sensorState.CheckStatusFlags(eHmdStatus_IsUsable)) { bHmdTrackingEnabled = true; } } } if (pHmdManager->IsStereoSetupOk()) { const IHmdDevice* pDev = pHmdManager->GetHmdDevice(); const HmdTrackingState &sensorState = pDev->GetLocalTrackingState(); if (sensorState.CheckStatusFlags(eHmdStatus_IsUsable)) { float arf_notUsed; pDev->GetCameraSetupInfo(fov, arf_notUsed); } } m_camera.SetFrustum(pSysCam->GetViewSurfaceX(), pSysCam->GetViewSurfaceZ(), fov, nearPlane, farPlane, pSysCam->GetPixelAspectRatio()); //TODO: (14, 06, 2010, "the player view should always get updated, this due to the hud being visable, without shocking, in cutscenes - todo is to see if we can optimise this code"); IActor* pActor = gEnv->pGame->GetIGameFramework()->GetClientActor(); if (pActor) { CGameObject* const linkToObj = static_cast<CGameObject*>(pActor->GetEntity()->GetProxy(ENTITY_PROXY_USER)); if (linkToObj && linkToObj != pLinkedTo) { linkToObj->PostUpdateView(m_viewParams); } } //apply shake & set the view matrix m_viewParams.rotation *= m_viewParams.currentShakeQuat; m_viewParams.rotation.NormalizeSafe(); m_viewParams.position += m_viewParams.currentShakeShift; // Camera space Rendering calculations on Entity if (pLinkedTo) { IEntity* pLinkedToEntity = pLinkedTo->GetEntity(); if (pLinkedToEntity) { const int slotIndex = 0; uint32 entityFlags = pLinkedToEntity->GetSlotFlags(slotIndex); if (entityFlags & ENTITY_SLOT_RENDER_NEAREST) { // Get camera pos relative to entity const Vec3 cameraLocalPos = m_viewParams.position; // Set entity's camera space position const Vec3 cameraSpacePos(-cameraLocalPos * m_viewParams.rotation); pLinkedToEntity->SetSlotCameraSpacePos(slotIndex,cameraSpacePos); // Add world pos onto camera local pos m_viewParams.position = pLinkedToEntity->GetWorldPos() + cameraLocalPos; } } } // Blending between cameras needs to happen after Camera space rendering calculations have been applied // so that the m_viewParams.position is in World Space again m_viewParams.UpdateBlending(frameTime); // [VR] specific // Add HMD's pose tracking on top of current camera pose // Each game-title can decide whether to keep this functionality here or (most likely) // move it somewhere else. Quat q = m_viewParams.rotation; Vec3 pos = m_viewParams.position; Vec3 p = Vec3(ZERO); // Uses the recorded tracking if time demo is on playback // Otherwise uses real tracking from device ITimeDemoRecorder* pTimeDemoRecorder = gEnv->pGame->GetIGameFramework()->GetITimeDemoRecorder(); if (pTimeDemoRecorder && pTimeDemoRecorder->IsPlaying()) { STimeDemoFrameRecord record; pTimeDemoRecorder->GetCurrentFrameRecord(record); p = q * record.hmdPositionOffset; q = q * record.hmdViewRotation; } else if (bHmdTrackingEnabled) { pHmdDevice->SetAsynCameraCallback(this); if (pHmdReferencePoint && pHmdReferencePoint->GetIVal() == 1) // actor-centered HMD offset { const IEntity* pEnt = GetLinkedEntity(); if (const IActor* pActor = gEnv->pGame->GetIGameFramework()->GetClientActor()) { if (pEnt && pActor->GetEntity() == pEnt) { q = pEnt->GetWorldRotation(); pos = pEnt->GetWorldPos(); } } } const HmdTrackingState &sensorState = pHmdDevice->GetLocalTrackingState(); p = q * sensorState.pose.position; q = q * sensorState.pose.orientation; } Matrix34 viewMtx(q); viewMtx.SetTranslation(pos + p); m_camera.SetMatrix(viewMtx); } else { m_linkedTo = 0; CCryAction* pCryAction = CCryAction::GetCryAction(); if (!pCryAction->IsGameSessionMigrating()) // If we're host migrating, leave the camera where it was { // Check if we're leaving a game mid way through - if we are then stop the camera from being reset for a frame or 2 before the unload happens if (!pCryAction->GetIGameSessionHandler()->IsMidGameLeaving()) { m_camera.SetPosition(Vec3(1,1,1)); } } } }