Part of these game systems:
beginner Movement

Top-Down Camera

RTS/strategy camera with WASD panning, edge scrolling, scroll wheel zoom, and optional target follow.

Unity 2022.3+ · 2.6 KB · TopDownCamera.cs

How to Use

1

Create a camera rig at a top-down angle (e.g., rotation 60,0,0)

2

Attach TopDownCamera to the rig

3

Use WASD or arrow keys to pan

4

Scroll wheel to zoom in/out

5

Enable edge scrolling for mouse-at-screen-edge panning

6

Set boundaries to limit camera movement area

7

Optionally assign a follow target for unit tracking

Source Code

TopDownCamera.cs
C#
using UnityEngine;

/// <summary>
/// Top-down / RTS camera with WASD panning, edge scrolling, and zoom.
/// Perfect for strategy, management, and top-down games.
/// </summary>
public class TopDownCamera : MonoBehaviour
{
    [Header("Movement")]
    [SerializeField] private float panSpeed = 20f;
    [SerializeField] private float panSmoothing = 8f;

    [Header("Edge Scrolling")]
    [SerializeField] private bool enableEdgeScroll = true;
    [SerializeField] private float edgeScrollZone = 20f;
    [SerializeField] private float edgeScrollSpeed = 15f;

    [Header("Zoom")]
    [SerializeField] private float zoomSpeed = 5f;
    [SerializeField] private float minZoom = 5f;
    [SerializeField] private float maxZoom = 30f;
    [SerializeField] private float zoomSmoothing = 8f;

    [Header("Boundaries")]
    [SerializeField] private bool useBoundaries = false;
    [SerializeField] private Vector2 minBounds = new Vector2(-50f, -50f);
    [SerializeField] private Vector2 maxBounds = new Vector2(50f, 50f);

    [Header("Follow Target")]
    [SerializeField] private Transform followTarget;
    [SerializeField] private float followSmoothing = 5f;

    private Vector3 targetPosition;
    private float targetZoom;
    private Camera cam;

    private void Awake()
    {
        cam = GetComponentInChildren<Camera>();
        if (cam == null) cam = Camera.main;

        targetPosition = transform.position;
        targetZoom = cam.orthographic ? cam.orthographicSize : transform.position.y;
    }

    private void Update()
    {
        if (followTarget != null)
        {
            Vector3 followPos = followTarget.position;
            followPos.y = transform.position.y;
            targetPosition = Vector3.Lerp(targetPosition, followPos, followSmoothing * Time.deltaTime);
        }
        else
        {
            HandlePanInput();
            HandleEdgeScroll();
        }

        HandleZoom();
        ApplyMovement();
    }

    private void HandlePanInput()
    {
        float h = Input.GetAxisRaw("Horizontal");
        float v = Input.GetAxisRaw("Vertical");

        Vector3 panDir = new Vector3(h, 0f, v).normalized;
        targetPosition += panDir * panSpeed * Time.deltaTime;
    }

    private void HandleEdgeScroll()
    {
        if (!enableEdgeScroll) return;

        Vector3 mousePos = Input.mousePosition;
        Vector3 edgeDir = Vector3.zero;

        if (mousePos.x < edgeScrollZone) edgeDir.x = -1f;
        else if (mousePos.x > Screen.width - edgeScrollZone) edgeDir.x = 1f;

        if (mousePos.y < edgeScrollZone) edgeDir.z = -1f;
        else if (mousePos.y > Screen.height - edgeScrollZone) edgeDir.z = 1f;

        targetPosition += edgeDir.normalized * edgeScrollSpeed * Time.deltaTime;
    }

    private void HandleZoom()
    {
        float scroll = Input.GetAxis("Mouse ScrollWheel");
        if (Mathf.Abs(scroll) > 0.01f)
        {
            targetZoom -= scroll * zoomSpeed;
            targetZoom = Mathf.Clamp(targetZoom, minZoom, maxZoom);
        }

        if (cam.orthographic)
            cam.orthographicSize = Mathf.Lerp(cam.orthographicSize, targetZoom, Time.deltaTime * zoomSmoothing);
        else
        {
            Vector3 pos = transform.position;
            pos.y = Mathf.Lerp(pos.y, targetZoom, Time.deltaTime * zoomSmoothing);
            transform.position = pos;
        }
    }

    private void ApplyMovement()
    {
        if (useBoundaries)
        {
            targetPosition.x = Mathf.Clamp(targetPosition.x, minBounds.x, maxBounds.x);
            targetPosition.z = Mathf.Clamp(targetPosition.z, minBounds.y, maxBounds.y);
        }

        Vector3 smoothed = Vector3.Lerp(transform.position, targetPosition, Time.deltaTime * panSmoothing);
        smoothed.y = transform.position.y;
        transform.position = smoothed;
    }

    /// <summary>Snap camera to a world position.</summary>
    public void FocusOn(Vector3 position)
    {
        targetPosition = new Vector3(position.x, transform.position.y, position.z);
    }

    /// <summary>Set a target to follow. Pass null to stop following.</summary>
    public void SetFollowTarget(Transform target)
    {
        followTarget = target;
    }
}