void CCameraTracking::UpdateAutoFollow(const SViewParams &viewParams, const CPlayer &hero) { if(g_pGameCVars->cl_cam_auto_follow_rate > 0.0f) //auto-tracking { //if there is an obstacle nearby, don't try to rotate into it float lastObstacleDist = (m_vLastObstaclePos - viewParams.position).len(); if(lastObstacleDist < g_fAutoTrackObstacleDistance) return; if(hero.GetActorStats()->speedFlat < g_pGameCVars->cl_cam_auto_follow_movement_speed) { //only rotate when player moves m_fAutoRotateSpeed = 0.0f; return; } //get camera direction Vec3 camDir = -m_pCamRayScan->GetRayDir(eRAY_CENTER); camDir.z = 0.0f; camDir.Normalize(); //get Player direction Vec3 heroDirection = (hero.GetAnimatedCharacter()->GetAnimLocation().q * FORWARD_DIRECTION); //compute angle between directions float dt = camDir.Dot(heroDirection); dt = clamp(dt, -1.0f, 1.0f); float angle = cry_acosf(dt); //check angle being bigger than threshold if(angle > g_pGameCVars->cl_cam_auto_follow_threshold) { float moveSpeed = max(0.002f, gf_PI*m_fFrameTime*g_pGameCVars->cl_cam_auto_follow_rate); m_fAutoRotateSpeed = InterpolateTo(max(0.002f, m_fAutoRotateSpeed), moveSpeed, 0.2f); //compute rotation direction by taking height part of cross-prod float dirVal = camDir.x * heroDirection.y - camDir.y * heroDirection.x; CCameraInputHelper *const pCamHelper = hero.GetCameraInputHelper(); CRY_ASSERT(pCamHelper); if(dirVal > 0) //rotate right pCamHelper->SetTrackingDelta(-m_fAutoRotateSpeed, 0.0f); else //rotate left pCamHelper->SetTrackingDelta(m_fAutoRotateSpeed, 0.0f); } else m_fAutoRotateSpeed = 0.0f; } }
void CCameraView::Reset() { //initialize the camera view IViewSystem *pViewSystem = g_pGame->GetIGameFramework()->GetIViewSystem(); IView *pView = pViewSystem->GetActiveView(); CRY_ASSERT(pView); m_lastViewParams = *(pView->GetCurrentParams()); //the player can still change camera angles etc. CPlayer *pHero = CPlayer::GetHero(); CRY_ASSERT(pHero); m_pCamHelper = pHero->GetCameraInputHelper(); CRY_ASSERT(m_pCamHelper); m_bModeTransition = false; m_fTransitionTimeout = 0.0f; m_curPolar.SetPitch(1.f); }
bool CCameraTracking::Update(SViewParams &viewParams, float &fHOffObstacleStrength, const SCamModeSettings &camMode, const CPlayer &hero, bool bObstacleFound /* = false */) { if(!g_pGameCVars->cl_cam_tracking || !m_pCamRayScan) return false; m_fFrameTime = max(g_fCamError, gEnv->pTimer->GetFrameTime()); //in combat mode this function doesn't really avoid obstacles, it avoids clipping float fCombatModeWeight = 5.0f; //default angle and minimum const float fNow = gEnv->pTimer->GetFrameStartTime().GetSeconds(); CCameraInputHelper *pCamHelper = hero.GetCameraInputHelper(); CRY_ASSERT(pCamHelper); float fLastUserInput = pCamHelper->GetLastUserInputTime(); //user input overrides auto-follow if(fNow - fLastUserInput < 0.5f) return false; bool bTrackingActive = camMode.camType == ECT_CamFollow && (camMode.collisionType == ECCT_CollisionTrack || camMode.collisionType == ECCT_CollisionTrackOrCut); //get current values Vec3 curCamDir = viewParams.position-viewParams.targetPos; m_curCamOrientation.Set(0.0f, 0.0f, 0.0f); CartesianToSpherical(curCamDir, m_curCamOrientation); curCamDir.Normalize(); if(m_curCamOrientation.m_fDist < g_pGameCVars->cl_cam_min_distance) m_curCamOrientation.m_fDist = g_pGameCVars->cl_cam_min_distance; //work in 0 .. 2PI m_curCamOrientation.m_fYaw += gf_PI; //if there is something in the way if(bObstacleFound) { //re-start fadeout m_fTimeCovered = 0.5f; //set last obstacle pos m_vLastObstaclePos = viewParams.position; //scan obstacle if(!IdentifyObstacle(curCamDir, hero)) return false; } else if(fabsf(m_fYawDelta) > g_fCamError || fabsf(m_fPitchDelta) > g_fCamError) { //if there is nothing in the way, fade out the movement //time based fade if(m_fTimeCovered > 0) { m_fTimeCovered = max(m_fTimeCovered - m_fFrameTime, 0.0f); //these interpolators should be time and not frame based m_fYawDelta = (g_fInterpolationRate * m_fYawDelta) * g_fInterpolationWeight; m_fPitchDelta = (g_fInterpolationRate * m_fPitchDelta) * g_fInterpolationWeight; m_fSpeed = (g_fInterpolationRate * m_fSpeed) * g_fInterpolationWeight; } else { m_fYawDelta = 0.0f; m_fPitchDelta = 0.0f; m_fSpeed = 0.0f; } } //apply delta rotation for obstacle avoidance if(fabsf(m_fYawDelta) > g_fCamError || fabsf(m_fPitchDelta) > g_fCamError) { if(bTrackingActive) { //set new yaw float newYaw = m_curCamOrientation.m_fYaw + m_fYawDelta; //re-align yaw //the camera direction is 90 degrees off and flipped compared to entity space newYaw = (newYaw - gf_PI * 0.5f) * -1.0f; //set new pitch float newPitch = m_curCamOrientation.m_fPitch + m_fPitchDelta; if(g_pGameCVars->cl_cam_orbit != 0) { //pCamHelper->SetTrackingDelta(-m_fYawDelta, m_fPitchDelta); pCamHelper->SetYawDelta(-m_fYawDelta); pCamHelper->SetPitchDelta(m_fPitchDelta); } else { //apply yaw/pitch on camera //pCamHelper->SetInterpolationTarget(newYaw, newPitch, gf_PI, 0.1f, 0.0f); //this will always reset follow cam interpolation pCamHelper->SetYawDelta(m_fYawDelta); pCamHelper->SetPitchDelta(m_fPitchDelta); } } else { //in orbit mode we basically simulate user input //pCamHelper->SetTrackingDelta(-fCombatModeWeight*g_fYawDelta, fCombatModeWeight*g_fPitchDelta); //in cutting mode we offset the camera to avoid clipping float offsetStrength = 0.0f; float offsetSpeed = 2.0f; if(bObstacleFound) { offsetStrength = (m_fYawDelta < 0.0f)?-g_fOffsetTrackingDistance:g_fOffsetTrackingDistance; offsetSpeed = 0.5f; } fHOffObstacleStrength = InterpolateTo(fHOffObstacleStrength, offsetStrength, offsetSpeed); } //CryLogAlways("new yaw %f, yawDelta %f", newYaw, g_yawDelta); return true; } else UpdateAutoFollow(viewParams, hero); return false; }