void CVTOLVehicleManager::SetupMovement(EntityId entityId) { IVehicle* pVehicle = m_pVehicleSystem->GetVehicle(entityId); if(pVehicle) { if (CVehicleMovementBase* pMovement = StaticCast_CVehicleMovementBase(pVehicle->GetMovement())) { pMovement->Reset(); pMovement->SetRemotePilot(true); pMovement->StartDriving(0); } IGameObject* pGameObject = pVehicle->GetGameObject(); pGameObject->SetUpdateSlotEnableCondition(pVehicle, IVehicle::eVUS_Always, eUEC_WithoutAI); pGameObject->SetUpdateSlotEnableCondition(pVehicle, IVehicle::eVUS_EnginePowered, eUEC_WithoutAI); pGameObject->EnableUpdateSlot(pVehicle, IVehicle::eVUS_EnginePowered); pGameObject->EnableUpdateSlot(pVehicle, IVehicle::eVUS_Always); } }
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 CVTOLVehicleManager::Update(float frameTime) { // Update logic goes here if(CGameRules* pGameRules = g_pGame->GetGameRules()) { CGameRules::TPlayers players; pGameRules->GetPlayers(players); for (TVTOLList::iterator iter=m_vtolList.begin(), end=m_vtolList.end(); iter!=end; ++iter) { SVTOLInfo& info = iter->second; IVehicle* pVehicle = m_pVehicleSystem->GetVehicle( info.entityId ); if(pVehicle) { info.stateTime += frameTime; // Find difference in rotation Quat newRotation = pVehicle->GetEntity()->GetWorldRotation(); newRotation.Normalize(); Quat rotationDifference = newRotation*info.location.q.GetInverted(); rotationDifference.Normalize(); // Store new rotation + position info.location.q = newRotation; info.location.t = pVehicle->GetEntity()->GetWorldPos(); if(info.state==EVS_Normal) { pVehicle->NeedsUpdate(IVehicle::eVUF_AwakePhysics); if(CVehicleMovementMPVTOL* pMovement = static_cast<CVehicleMovementMPVTOL*>(pVehicle->GetMovement())) { const uint8 pathComplete = pMovement->GetPathComplete(); if(pathComplete==1) { if(CMPPathFollowingManager* pMPPathFollowingManager = g_pGame->GetGameRules()->GetMPPathFollowingManager()) { pMPPathFollowingManager->NotifyListenersOfPathCompletion(info.entityId); } pMovement->SetPathCompleteNotified(); } } } // Check status if(info.state==EVS_Normal && pVehicle->GetDamageRatio() >= 1.f) { if(gEnv->bServer) { DestructionDamageRatioReached(pVehicle, info, frameTime); } } else if(info.state == EVS_Invisible) { if(info.stateTime > g_pGameCVars->g_VTOLRespawnTime) { RespawnVTOL(pVehicle, info); } } //Process players TPlayerList& currentPlayerList = info.playersInside; TPlayerList oldPlayerList = currentPlayerList; currentPlayerList.clear(); CGameRules::TPlayers::iterator iterPlayer = players.begin(); const CGameRules::TPlayers::const_iterator endPlayer = players.end(); while(iterPlayer != endPlayer) { // Adding safeguard to protect against cases where user alt-f4 quits program. UpdateEntityInVTOL(info, *iterPlayer); ++iterPlayer; } //Find out who has been inside since the last update, who has just entered, and who has left TPlayerStatusList playerStatusList; int currentId; for(unsigned int prev = 0; prev < currentPlayerList.size(); ++prev) { currentId = currentPlayerList[prev]; bool found = false; TPlayerList::iterator oldIter = oldPlayerList.begin(); TPlayerList::iterator oldEnd = oldPlayerList.end(); while(oldIter != oldEnd) { if(currentId == *oldIter) //In both lists so still inside { found = true; playerStatusList.push_back( TPlayerStatus(currentId, E_PEVS_StillInside) ); oldPlayerList.erase(oldIter); break; } ++oldIter; } if(!found) //Only in current list so entered { playerStatusList.push_back( TPlayerStatus(currentId, E_PEVS_Entered) ); } } //Those remaining in old list have exited for(unsigned int old = 0; old < oldPlayerList.size(); ++old) { playerStatusList.push_back( TPlayerStatus(oldPlayerList[old], E_PEVS_Exited) ); } //Act based on current state TPlayerStatusList::iterator statusIter = playerStatusList.begin(); TPlayerStatusList::iterator statusEnd = playerStatusList.end(); while(statusIter != statusEnd) { switch(statusIter->second) { case E_PEVS_Entered: { OnPlayerEntered(statusIter->first); } break; case E_PEVS_Exited: { OnPlayerExited(statusIter->first); } break; } ++statusIter; } UpdateRotationOfInternalPlayers(info, playerStatusList, rotationDifference); } } } }
virtual void ProcessEvent(EFlowEvent flowEvent, SActivationInfo* pActivationInfo) { if (flowEvent == eFE_Activate && IsPortActive(pActivationInfo, EIP_StartDriving)) { IEntity* pEntity = pActivationInfo->pEntity; if(!pEntity) return; IVehicle* pVehicle; pVehicle = gEnv->pGame->GetIGameFramework()->GetIVehicleSystem()->GetVehicle( pEntity->GetId() ); if(!pVehicle || pVehicle->IsDestroyed()) { return; } IVehicleMovement* pMovement = pVehicle->GetMovement(); if (!pMovement) return; CVehicleMovementBase* pMovementBase = StaticCast_CVehicleMovementBase(pMovement); if (!pMovementBase) return; IActor* pPlayer = g_pGame->GetIGameFramework()->GetClientActor(); if (!pPlayer) return; const EntityId localPlayer = pPlayer->GetEntityId(); if (pVehicle->GetSeatCount() == 0) // Don't need to remotely enter { pMovement->StartDriving(localPlayer); } else { pVehicle->EvictAllPassengers(); IVehicleSeat* pSeat = pVehicle->GetSeatById(1); if (pSeat) { // Can't use remote entering to control otherwise if vehicle blows up, player dies //pSeat->EnterRemotely(localPlayer); pMovement->StartDriving(localPlayer); m_prevSeatLockStatus = pSeat->GetLockedStatus(); pSeat->SetLocked(eVSLS_Locked); } } m_fDuration = GetPortFloat(pActivationInfo, EIP_Time); m_fSpeed = GetPortFloat(pActivationInfo, EIP_Speed); m_actInfo = *pActivationInfo; m_entityId = pEntity->GetId(); SetActive(true); } else if (flowEvent == eFE_Update) { if (!m_bActive) { if (m_bNeedsCleanup) { Cleanup(); } return; } IEntity* pEntity = pActivationInfo->pEntity; if(!pEntity) { SetActive(false); return; } IVehicle* pVehicle; pVehicle = gEnv->pGame->GetIGameFramework()->GetIVehicleSystem()->GetVehicle( pEntity->GetId() ); if(!pVehicle || pVehicle->IsDestroyed()) { SetActive(false); return; } const float curTime = gEnv->pTimer->GetFrameStartTime().GetSeconds(); if ((curTime - m_fStartedTime) >= m_fDuration) { SetActive(false); ActivateOutput(pActivationInfo, EOP_TimeComplete, true); } else // Update every frame { IVehicleMovement* pMovement = pVehicle->GetMovement(); if (pMovement) { // prevent full pedal being kept pressed, but give it a bit pMovement->OnAction(eVAI_MoveForward, eAAM_OnPress, 1.0f); } } } }