codesamples >> quantum camera class

Quantum: Camera class

Project:

Quantum

Engine:

XNA

Code language:

C#

Class description:

The camera system in Quantum is a 3rd person camera, which can change into a cinematic camera in case an event happens.
I have also included a director camera function which allows free control of the camera which we used to record the Quantum trailer.

Camera.cs

// ...            

/// 
/// Allows the game component to update itself.
/// 
/// Provides a snapshot of timing values.
public override void Update(GameTime gameTime)
{
    // TODO: Add your update code here
    
    // Lerp Camera behind Vigor
    if (!m_IsDirectorCamActive || m_IsDirectorCamFollowing)
    {
        m_CameraTarget = m_Vigor.Position;
        m_CameraTarget.Y += m_CameraHeightOffset;
    }

    // Shake the Camera when needed
    CameraShake(gameTime);

    // Switch Camera if needed
    if (m_ShouldCameraSwitch)
    {
        switch (m_MainCameraSettings)
        {
            case ((int)Camera.MainCameraState.Suburbia):
                m_NewCameraPosition = new Vector3(0, 30, -40);
                Matrix rotationMatrixSuburbia = Matrix.CreateRotationY(m_Vigor.Rotation);
                m_NewCameraPosition = Vector3.Transform(m_NewCameraPosition, rotationMatrixSuburbia);
                m_IsCameraSwitching = true;
                m_Vigor.CanTurn = false;
                break;

            case ((int)Camera.MainCameraState.Industry):
                m_NewCameraPosition = new Vector3(0, 45, -60);
                Matrix rotationMatrixIndustry = Matrix.CreateRotationY(m_Vigor.Rotation);
                m_NewCameraPosition = Vector3.Transform(m_NewCameraPosition, rotationMatrixIndustry);
                m_IsCameraSwitching = true;
                m_Vigor.CanTurn = false;
                break;
        }
    }
   
    // Manage the camera switching between regions
    if (m_IsCameraSwitching)
    {
        Vector3 flyingDistance = m_NewCameraPosition - m_CameraPosition;
        Matrix rotationMatrix = Matrix.CreateRotationY(m_Vigor.Rotation);
        if (Math.Abs(flyingDistance.X) < m_CameraSwitchMinDistance 
            && Math.Abs(flyingDistance.Y) < m_CameraSwitchMinDistance 
            && Math.Abs(flyingDistance.Z) < m_CameraSwitchMinDistance)
        {
            m_IsCameraSwitching = false;
            m_CameraPosition = m_NewCameraPosition;
            m_Vigor.CanTurn = true;
            m_ShouldCameraSwitch = false;
        }
        else
        {
            m_CameraPosition += flyingDistance / m_CameraSwitchOffset;
        }
    }

    // Cinematic camera actions happen here
    if (m_IsCinematicCamActive)
    {
        Vector3 flyingDistance = m_CinematicCameraDestination - m_CinematicCameraPosition;

        if (Math.Abs(flyingDistance.X) < m_CinematicCameraMinDistance 
            && Math.Abs(flyingDistance.Y) < m_CinematicCameraMinDistance 
            && Math.Abs(flyingDistance.Z) < m_CinematicCameraMinDistance)
        {
            ++m_CinematicCameraTimer; 
            if (m_CinematicCameraTimer == m_CinematicCameraMaxTime)
            {
                //Trace.WriteLine("Deactivating Cinematic camera");
                m_IsCinematicCamActive = false;
                m_CinematicCameraTimer = 0;
            }
        }
        else
        {
            m_CinematicCameraPosition += flyingDistance / m_CinematicCameraOffset;
        }
    }

    // Safety reset
    if (m_CinematicCameraTimer > m_CinematicCameraMaxTime)
    {
        m_CinematicCameraTimer = 0;
    }

    base.Update(gameTime);
}

public void ResetCamera()
{
    if (m_CameraYRotation <= 180)
    {
        Matrix rotationMatrix = Matrix.CreateRotationY(MathHelper.ToRadians(-m_CameraYRotation /
         m_CameraRotOffset));
        m_CameraPosition = Vector3.Transform(m_CameraPosition, rotationMatrix);

        m_CameraYRotation -= m_CameraYRotation / m_CameraRotOffset;
        //Trace.WriteLine("Resetted camera to 0°");
    }
    if (m_CameraYRotation > 180)
    {
        Matrix rotationMatrix = Matrix.CreateRotationY(MathHelper.ToRadians((360 - m_CameraYRotation) / 
        m_CameraRotOffset));
        m_CameraPosition = Vector3.Transform(m_CameraPosition, rotationMatrix);

        m_CameraYRotation += (360 - m_CameraYRotation) / m_CameraRotOffset;
        //Trace.WriteLine("Resetted camera to 0°");
    }
}

public void ResetXZCamera()
{
    if (m_CameraXZRotation > m_CameraRotOffset)
    {
        Vector3 right = Vector3.Transform(Vector3.Right, Matrix.CreateRotationY(m_Vigor.Rotation));
        Matrix rotationMatrix = Matrix.CreateFromAxisAngle(right, MathHelper.ToRadians(m_CameraXZRotation / 
        m_CameraRotOffset));
        m_CameraPosition = Vector3.Transform(m_CameraPosition, rotationMatrix);

        m_CameraXZRotation -= m_CameraXZRotation / m_CameraRotOffset;
        //Trace.WriteLine("CameraXZrotation:" + m_CameraXZRotation);
    }
}

public float MakeAnglePositive(float angleInDegrees)
{
    if (angleInDegrees > 360)
    {
        angleInDegrees -= 360;
    }

    if (angleInDegrees < 0)
    {
        angleInDegrees += 360;
    }

    return angleInDegrees;
}

public void PlayCinematicCamera(int sequenceNumber)
{
    switch (sequenceNumber)
    {
		// City entered
        case ((int)Camera.CameraSequence.City):
            m_CinematicCameraTarget = new Vector3(244, 0, 46.5f);
            m_CinematicCameraDestination = new Vector3(161, 64, 25);
            m_CinematicCameraPosition = m_Vigor.Position + m_CameraPosition;
            m_IsCinematicCamActive = true;
            break;

        // Statue unlocked
        case ((int)Camera.CameraSequence.StatueUnlocked):
            m_CinematicCameraTarget = new Vector3(183, 5, 123);
            m_CinematicCameraDestination = new Vector3(210, 40, 88);
            m_CinematicCameraPosition = m_Vigor.Position + m_CameraPosition;
            m_IsCinematicCamActive = true;
            break;

        // Statue win
        case ((int)Camera.CameraSequence.StatueVictory):
            m_CinematicCameraTarget = new Vector3(183, 5, 123);
            m_CinematicCameraDestination = new Vector3(183, 100, -1.7f);
            m_CinematicCameraPosition = m_Vigor.Position + m_CameraPosition;
            m_IsCinematicCamActive = true;
            break;

        // Shop
        case ((int)Camera.CameraSequence.Shop):
            m_CinematicCameraTarget = new Vector3(56, 25, 124);
            m_CinematicCameraDestination = new Vector3(53, 40, 104);
            m_CinematicCameraPosition = m_Vigor.Position + m_CameraPosition;
            m_IsCinematicCamActive = true;
            break;

        // Industry entered
        case ((int)Camera.CameraSequence.Industry):
            m_CinematicCameraTarget = new Vector3(61, 5, 444);
            m_CinematicCameraDestination = new Vector3(78, 40, 414);
            m_CinematicCameraPosition = m_Vigor.Position + m_CameraPosition;
            m_IsCinematicCamActive = true;
            break;
    }
}

public void Shake(float magnitude, float duration)
{
    // We're now shaking
    m_IsCameraShaking = true;

    // Store our magnitude and duration
    m_CameraShakeMagnitude = magnitude;
    m_CameraShakeDuration = duration;

    // Reset our timer
    m_CameraShakeTimer = 0.0f;
}

void CameraShake(GameTime gameTime)
{
    if (m_IsCameraShaking == true)
    {
        // Move our timer ahead based on the elapsed time
        m_CameraShakeTimer += (float)gameTime.ElapsedGameTime.TotalSeconds;

        // If we're at the max duration, we're not going to be shaking anymore
        if (m_CameraShakeTimer >= m_CameraShakeDuration)
        {
            m_IsCameraShaking = false;
            m_CameraShakeTimer = m_CameraShakeDuration;
        }

        // Compute our progress in a [0, 1] range
        float progress = m_CameraShakeTimer / m_CameraShakeDuration;

        // Compute our magnitude based on our maximum value and our progress
        float magnitude = m_CameraShakeMagnitude * (1.0f - (progress * progress));

        // Generate a new offset vector with three random values and our magnitude
        m_CameraOffset = new Vector3(NextFloat(), NextFloat(), NextFloat()) * magnitude;
    }
}

/// 
/// Helper to generate a random float in the range of [-1, 1].
/// 
private float NextFloat()
{
    Random randomNumber = new System.Random();
    return (float)randomNumber.NextDouble() * 2.0f - 1.0f;
}

// ...  
            

Controls.cs

// ... 
public void TurnLeft(bool isRunning, bool isTouch=false)
{
    if (!isRunning) { m_Vigor.Pose = (int)Vigor.PoseState.Idle; }

    // Windows 8 Port Specific Touch Code
    // Turn Vigor while he isn't sprinting
    if (m_Vigor.CanTurn && m_Vigor.Pose != (int)Vigor.PoseState.SprintForwards)
    {
        Matrix rotationMatrix;
        // If Touchscreen isn't active
        if (!isTouch)
        {
            // Assign rotation matrix
            rotationMatrix = Matrix.CreateTranslation(-m_Vigor.Position) 
            * Matrix.CreateRotationY(MathHelper.ToRadians(m_TurningSpeed)) 
            * Matrix.CreateTranslation(m_Vigor.Position);
            
            // Apply rotationmatrix to Vigor's position and rotation
            m_Vigor.Position = Vector3.Transform(m_Vigor.Position, rotationMatrix);
            m_Vigor.Rotation += MathHelper.ToRadians(m_TurningSpeed);

            // Rotate the camera in the opposite direction
            m_Camera.CameraYRotation -= m_TurningSpeed;
        }
        // If Touchscreen is active
        else
        {
            // Assign rotation matrix
            rotationMatrix = Matrix.CreateTranslation(-m_Vigor.Position) 
            * Matrix.CreateRotationY(MathHelper.ToRadians(m_TurningSpeed * -m_QGame.m_ScreenControls.
        GetPivotOffset().X)) 
            * Matrix.CreateTranslation(m_Vigor.Position);
            
            // Apply rotationmatrix to Vigor's position and rotation
            m_Vigor.Position = Vector3.Transform(m_Vigor.Position, rotationMatrix);
            m_Vigor.Rotation += MathHelper.ToRadians(m_TurningSpeed * -m_QGame.m_ScreenControls.
        GetPivotOffset().X);

            // Rotate the camera in the opposite direction
            m_Camera.CameraYRotation -= m_TurningSpeed * -m_QGame.m_ScreenControls.GetPivotOffset().X;
        }    
    }
    
    // Turn Vigor while he is sprinting
    if(m_Vigor.CanTurn && m_Vigor.Pose == (int)Vigor.PoseState.SprintForwards)
    {
        // Create rotation matrix
        Matrix rotationMatrix = Matrix.CreateTranslation(-m_Vigor.Position) 
        * Matrix.CreateRotationY(MathHelper.ToRadians(m_RunningTurningSpeed * m_RunningSpeedEnergyBoost)) 
        * Matrix.CreateTranslation(m_Vigor.Position);
        
        // Apply rotationmatrix to Vigor's position and rotation
        m_Vigor.Position = Vector3.Transform(m_Vigor.Position, rotationMatrix);
        m_Vigor.Rotation += MathHelper.ToRadians(m_RunningTurningSpeed * m_RunningSpeedEnergyBoost);

        // Rotate the camera in the opposite direction
        m_Camera.CameraYRotation -= m_RunningTurningSpeed * m_RunningSpeedEnergyBoost;
    }

    //Trace.WriteLine("Modelrotation:" + MathHelper.ToDegrees(m_Vigor.Rotation));
    //Trace.WriteLine("CameraPosition:" + m_Camera.CameraPosition);
}

public void TurnRight(bool isRunning, bool isTouch=false)
{
    if (!isRunning) { m_Vigor.Pose = (int)Vigor.PoseState.Idle; }

    // Windows 8 Port Specific Touch Code
    // Turn Vigor while he isn't sprinting
    if (m_Vigor.CanTurn && m_Vigor.Pose != (int)Vigor.PoseState.SprintForwards)
    {
        Matrix rotationMatrix;
        if (!isTouch)
        {
            // Assign rotation matrix
            rotationMatrix = Matrix.CreateTranslation(-m_Vigor.Position) 
            * Matrix.CreateRotationY(MathHelper.ToRadians(-m_TurningSpeed)) 
            * Matrix.CreateTranslation(m_Vigor.Position);
            
            // Apply rotationmatrix to Vigor's position and rotation
            m_Vigor.Position = Vector3.Transform(m_Vigor.Position, rotationMatrix);
            m_Vigor.Rotation -= MathHelper.ToRadians(m_TurningSpeed);

            // Rotate the camera in the opposite direction
            m_Camera.CameraYRotation += m_TurningSpeed;
        }
        else
        {
            // Assign rotation matrix
            rotationMatrix = Matrix.CreateTranslation(-m_Vigor.Position) 
            * Matrix.CreateRotationY(MathHelper.ToRadians(-m_TurningSpeed * m_QGame.m_ScreenControls.
        GetPivotOffset().X)) 
            * Matrix.CreateTranslation(m_Vigor.Position);
            
            // Apply rotationmatrix to Vigor's position and rotation
            m_Vigor.Position = Vector3.Transform(m_Vigor.Position, rotationMatrix);
            m_Vigor.Rotation -= MathHelper.ToRadians(m_TurningSpeed * m_QGame.m_ScreenControls.
        GetPivotOffset().X);

            // Rotate the camera in the opposite direction
            m_Camera.CameraYRotation += m_TurningSpeed * m_QGame.m_ScreenControls.GetPivotOffset().X;
        }
    }
    
    // Turn Vigor while he is sprinting
    if (m_Vigor.CanTurn && m_Vigor.Pose == (int)Vigor.PoseState.SprintForwards)
    {
        // Create rotation matrix
        Matrix rotationMatrix = Matrix.CreateTranslation(-m_Vigor.Position) 
        * Matrix.CreateRotationY(MathHelper.ToRadians(-m_RunningTurningSpeed * m_RunningSpeedEnergyBoost)) 
        * Matrix.CreateTranslation(m_Vigor.Position);
        
        // Apply rotationmatrix to Vigor's position and rotation
        m_Vigor.Position = Vector3.Transform(m_Vigor.Position, rotationMatrix);
        m_Vigor.Rotation -= MathHelper.ToRadians(m_RunningTurningSpeed * m_RunningSpeedEnergyBoost);

        // Rotate the camera in the opposite direction
        m_Camera.CameraYRotation += m_RunningTurningSpeed * m_RunningSpeedEnergyBoost;
    }
    //Trace.WriteLine("Modelrotation:" + MathHelper.ToDegrees(m_Vigor.Rotation));
    //Trace.WriteLine("CameraPosition:" + m_Camera.CameraPosition);
}

public void RotateCameraLeft()
{
    m_Camera.IsFreeCamActive = true;

    Matrix rotationMatrix = Matrix.CreateRotationY(MathHelper.ToRadians(-m_RotationOffset));
    m_Camera.CameraYRotation -= m_RotationOffset;
    m_Camera.CameraPosition = Vector3.Transform(m_Camera.CameraPosition, rotationMatrix);

    m_Camera.CameraYRotation = m_Camera.MakeAnglePositive(m_Camera.CameraYRotation);
    //Trace.WriteLine("Camerarotation:" + m_Camera.CameraYRotation);
}

public void RotateCameraRight()
{
    m_Camera.IsFreeCamActive = true;

    Matrix rotationMatrix = Matrix.CreateRotationY(MathHelper.ToRadians(m_RotationOffset));
    m_Camera.CameraYRotation += m_RotationOffset;
    m_Camera.CameraPosition = Vector3.Transform(m_Camera.CameraPosition, rotationMatrix);

    m_Camera.CameraYRotation = m_Camera.MakeAnglePositive(m_Camera.CameraYRotation);
    //Trace.WriteLine("Camerarotation:" + m_Camera.CameraYRotation);
}

public void ZoomInOnVigor()
{
    Vector3 cameraPosition = m_Camera.CameraPosition;

    if (cameraPosition.Y > m_Camera.MinCameraYPos)
    {
        cameraPosition.X -= (float)Math.Sin(m_Vigor.Rotation) / m_RotationOffset;
        cameraPosition.Z -= (float)Math.Cos(m_Vigor.Rotation) / m_RotationOffset;
        cameraPosition.Y -= m_YCameraOffset;
    }

    m_Camera.CameraPosition = cameraPosition;
}

public void ZoomOutFromVigor()
{
    Vector3 cameraPosition = m_Camera.CameraPosition;

    if (cameraPosition.Y < m_Camera.MaxCameraYPos)
    {
        cameraPosition.X += (float)Math.Sin(m_Vigor.Rotation) / m_RotationOffset;
        cameraPosition.Z += (float)Math.Cos(m_Vigor.Rotation) / m_RotationOffset;
        cameraPosition.Y += m_YCameraOffset;
    }

    m_Camera.CameraPosition = cameraPosition;
}
// ... 
            

QuantumGame.cs - Draw method

// ... 
// Set ProjectionMatrix & ViewMatrix
Matrix projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4,
 GraphicsDevice.Viewport.AspectRatio, 
1.0f, 350.0f);
Matrix viewMatrix;

// Normal View
if (m_Camera.IsDirectorCamActive == false && m_Camera.IsCinematicCamActive == false)
{
    if (m_Camera.IsCameraShaking == true)
    {
        viewMatrix = Matrix.CreateLookAt(m_Vigor.Position + m_Camera.CameraPosition + m_Camera.CameraOffset, 
        m_Camera.CameraTarget + m_Camera.CameraOffset, Vector3.Up);
    }
    else
    {
        viewMatrix = Matrix.CreateLookAt(m_Vigor.Position + m_Camera.CameraPosition, m_Camera.CameraTarget, 
    Vector3.Up);
    }
}
// Director Camera
else if (m_Camera.IsDirectorCamActive == true)
{
    viewMatrix = Matrix.CreateLookAt(m_Camera.DirectorCameraPosition, m_Camera.DirectorCameraTarget, 
    Vector3.Up);
}
// Cinematic Camera
else
{
    viewMatrix = Matrix.CreateLookAt(m_Camera.CinematicCameraPosition, m_Camera.CinematicCameraTarget, 
    Vector3.Up);
}
// ...