Dynamic Cameras in Unity Puzzle Games with Cinemachine

Posted by Gemma Ellison
./
July 16, 2025

Puzzle games live or die on clarity. If the player can’t clearly see the puzzle, they’re not going to solve it – they’re just going to get frustrated. That’s why a flexible, dynamic camera system is absolutely essential. Stop wrestling with rigid, pre-defined camera angles, and start building a system that adapts to the player, not the other way around. Let’s dive into how to craft a powerful camera for your Unity puzzle game using Cinemachine.

Setting Up Cinemachine for Puzzle Bliss

Cinemachine is the backbone of our dynamic camera. Don’t even think about hand-crafting camera movements with basic Transform manipulations; Cinemachine offers a far more robust and artist-friendly solution.

  1. Installation is Key: First, install Cinemachine from the Package Manager (Window -> Package Manager -> Cinemachine).

  2. Virtual Camera Creation: Create a Virtual Camera (Cinemachine -> Create Virtual Camera). This is your primary camera controller.

  3. Prioritize Orthographic Projection: For most puzzle games, an orthographic projection is far superior to perspective. Select the Unity camera linked to the Cinemachine Virtual Camera and set its projection to “Orthographic.” Adjust the Orthographic Size to frame your initial puzzle area. The initial size is critical to providing clarity right from the start.

Smooth Zooming: A Cinemachine Deep Dive

Zooming shouldn’t be jarring. It should be smooth, intuitive, and enhance the player’s experience. Cinemachine makes this surprisingly easy, but there’s a right way and a wrong way.

Here’s the code to handle zoom input, adjusting the camera’s orthographic size:

using Cinemachine;
using UnityEngine;

public class CameraZoom : MonoBehaviour
{
    public CinemachineVirtualCamera virtualCamera;
    public float zoomSpeed = 5f;
    public float minOrthographicSize = 5f;
    public float maxOrthographicSize = 20f;

    private Camera unityCamera;

    void Start()
    {
        unityCamera = virtualCamera.GetComponent<Camera>();
        if (unityCamera == null)
        {
            Debug.LogError("Cinemachine Virtual Camera does not have a Camera component!");
            enabled = false;
        }
    }

    void Update()
    {
        float zoomInput = Input.GetAxis("Mouse ScrollWheel");
        float targetOrthographicSize = unityCamera.orthographicSize - zoomInput * zoomSpeed;
        unityCamera.orthographicSize = Mathf.Clamp(targetOrthographicSize, minOrthographicSize, maxOrthographicSize);
    }
}
  • Explanation: This script reads the mouse scroll wheel input, adjusts the orthographic size of the linked Unity camera, and clamps the size within predefined min/max values.

  • Common Pitfall: Forgetting to clamp the orthographic size! Without clamping, players can zoom way too far in or out, breaking the game.

  • Actionable Insight: Expose the zoomSpeed, minOrthographicSize, and maxOrthographicSize as public variables. This allows designers to easily tweak the zoom behavior without code changes. Create a camera settings asset to store these settings and share them between levels.

Panning with Precision: Mouse Input Mastery

Panning allows players to explore larger puzzles or focus on specific areas. The key is to make it feel natural and responsive.

Here’s the code to enable camera panning with the mouse:

using Cinemachine;
using UnityEngine;

public class CameraPan : MonoBehaviour
{
    public CinemachineVirtualCamera virtualCamera;
    public float panSpeed = 20f;
    private Vector3 dragOrigin;

    void Update()
    {
        if (Input.GetMouseButtonDown(0)) // Left mouse button
        {
            dragOrigin = Input.mousePosition;
            return;
        }

        if (!Input.GetMouseButton(0)) return;

        Vector3 pos = Camera.main.ScreenToViewportPoint(Input.mousePosition - dragOrigin);
        Vector3 move = new Vector3(pos.x * panSpeed, pos.y * panSpeed, 0);

        virtualCamera.transform.Translate(move, Space.World);

        dragOrigin = Input.mousePosition; // Update drag origin for continuous panning
    }
}
  • Explanation: This script tracks the mouse position when the left mouse button is held down and translates the Cinemachine Virtual Camera’s transform accordingly.

  • Common Pitfall: Panning speed is too fast or slow. Playtest extensively to find the sweet spot.

  • Actionable Insight: Consider adding inertia to the panning. Instead of directly translating the camera, apply an impulse to a Rigidbody attached to the Virtual Camera. This creates a smoother, more organic feel.

Object Tracking: Keeping the Focus Where It Belongs

Sometimes, you need the camera to automatically focus on a specific object – perhaps a newly revealed puzzle piece or an important interaction point.

using Cinemachine;
using UnityEngine;

public class CameraTracker : MonoBehaviour
{
    public CinemachineVirtualCamera virtualCamera;
    public Transform target;
    public float trackingSpeed = 5f;
    private CinemachineTransposer transposer;

    void Start()
    {
        CinemachineComponentBase componentBase = virtualCamera.GetCinemachineComponent(CinemachineCore.Stage.Body);
        transposer = componentBase as CinemachineTransposer;
        if (transposer == null)
        {
            Debug.LogError("Cinemachine Virtual Camera does not have a CinemachineTransposer component!");
            enabled = false;
        }
    }

    void LateUpdate()
    {
        if (target != null)
        {
            Vector3 targetPosition = target.position;
            // Option 1: Directly set the Follow target
            //virtualCamera.Follow = target; // Simple, but abrupt

            // Option 2: Smoothly interpolate towards the target position
            Vector3 currentPosition = virtualCamera.transform.position;
            Vector3 smoothedPosition = Vector3.Lerp(currentPosition, targetPosition, trackingSpeed * Time.deltaTime);
            virtualCamera.transform.position = smoothedPosition;
        }
    }
}
  • Explanation: This script allows you to set a target Transform. The camera will smoothly move to keep the target in view.

  • Common Pitfall: Abrupt camera movements can be disorienting. Use Vector3.Lerp or Cinemachine’s built-in damping settings to smooth transitions.

  • Actionable Insight: Instead of directly setting the target’s position, use Cinemachine’s “Follow” and “Look At” targets. This gives Cinemachine more control over the camera’s behavior and allows you to leverage its advanced features like damping and dead zones.

Putting It All Together: A Complete System

By combining these three elements – zooming, panning, and object tracking – you create a powerful and adaptable camera system for your puzzle game. Remember to prioritize player comfort and clarity above all else. Experiment with different settings, gather feedback, and iterate until you find the perfect balance for your specific game. Stop forcing your players to adapt to a subpar camera, and give them the tools they need to truly engage with your puzzles.