Part of these game systems:
Top-Down Camera
RTS/strategy camera with WASD panning, edge scrolling, scroll wheel zoom, and optional target follow.
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
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;
}
}