Part of these game systems:
intermediate UI

Minimap System

Render texture minimap with player icon, enemy blips, objective markers, and zoom control.

Unity 2022.3+ · 3.2 KB · MinimapSystem.cs

How to Use

1

Create a secondary Camera set to Orthographic, looking down (rotation 90,0,0)

2

Set it to render to a RenderTexture (create one: 256x256)

3

Display the RenderTexture in a RawImage UI element (circular mask optional)

4

Attach MinimapSystem, assign the camera and player transform

5

Register icons: MinimapSystem.RegisterIcon(enemy.transform, Color.red)

6

Unregister on destroy: MinimapSystem.UnregisterIcon(transform)

7

Create a 'Minimap' layer and set camera culling to only show minimap objects

Source Code

MinimapSystem.cs
C#
using UnityEngine;
using System.Collections.Generic;

/// <summary>
/// Render texture minimap. Requires a secondary orthographic camera
/// rendered to a RenderTexture displayed in a RawImage UI element.
/// </summary>
public class MinimapSystem : MonoBehaviour
{
    public static MinimapSystem Instance { get; private set; }

    [Header("Camera")]
    [SerializeField] private Camera minimapCamera;
    [SerializeField] private Transform playerTransform;

    [Header("Follow")]
    [SerializeField] private float height = 40f;
    [SerializeField] private bool rotateWithPlayer = false;

    [Header("Zoom")]
    [SerializeField] private float defaultZoom = 30f;
    [SerializeField] private float minZoom = 15f;
    [SerializeField] private float maxZoom = 60f;
    [SerializeField] private float zoomSpeed = 5f;

    [Header("Icons")]
    [SerializeField] private GameObject iconPrefab;
    [SerializeField] private float iconScale = 1f;

    private float currentZoom;
    private Dictionary<Transform, MinimapIcon> trackedIcons = new Dictionary<Transform, MinimapIcon>();

    private void Awake()
    {
        if (Instance == null)
            Instance = this;
        else
        {
            Destroy(gameObject);
            return;
        }

        currentZoom = defaultZoom;

        if (minimapCamera != null)
            minimapCamera.orthographicSize = currentZoom;
    }

    private void LateUpdate()
    {
        if (minimapCamera == null || playerTransform == null) return;

        // Follow player
        Vector3 camPos = playerTransform.position;
        camPos.y = playerTransform.position.y + height;
        minimapCamera.transform.position = camPos;

        // Rotation
        if (rotateWithPlayer)
        {
            minimapCamera.transform.rotation = Quaternion.Euler(
                90f, playerTransform.eulerAngles.y, 0f
            );
        }
        else
        {
            minimapCamera.transform.rotation = Quaternion.Euler(90f, 0f, 0f);
        }

        // Update zoom
        minimapCamera.orthographicSize = Mathf.Lerp(
            minimapCamera.orthographicSize,
            currentZoom,
            Time.deltaTime * 5f
        );

        // Update tracked icons
        CleanupDestroyedIcons();
    }

    /// <summary>
    /// Register a transform to show on the minimap.
    /// </summary>
    public static void RegisterIcon(Transform target, Color color, float scale = 1f)
    {
        if (Instance == null || Instance.iconPrefab == null) return;
        if (Instance.trackedIcons.ContainsKey(target)) return;

        GameObject icon = Instantiate(Instance.iconPrefab);
        MinimapIcon minimapIcon = icon.GetComponent<MinimapIcon>();

        if (minimapIcon == null)
            minimapIcon = icon.AddComponent<MinimapIcon>();

        minimapIcon.Initialize(target, color, scale * Instance.iconScale);
        Instance.trackedIcons[target] = minimapIcon;
    }

    /// <summary>
    /// Remove a tracked icon from the minimap.
    /// </summary>
    public static void UnregisterIcon(Transform target)
    {
        if (Instance == null) return;
        if (Instance.trackedIcons.TryGetValue(target, out MinimapIcon icon))
        {
            if (icon != null)
                Destroy(icon.gameObject);
            Instance.trackedIcons.Remove(target);
        }
    }

    /// <summary>Zoom in the minimap.</summary>
    public void ZoomIn()
    {
        currentZoom = Mathf.Max(minZoom, currentZoom - zoomSpeed);
    }

    /// <summary>Zoom out the minimap.</summary>
    public void ZoomOut()
    {
        currentZoom = Mathf.Min(maxZoom, currentZoom + zoomSpeed);
    }

    private void CleanupDestroyedIcons()
    {
        List<Transform> toRemove = new List<Transform>();
        foreach (var kvp in trackedIcons)
        {
            if (kvp.Key == null || kvp.Value == null)
                toRemove.Add(kvp.Key);
        }
        foreach (var key in toRemove)
        {
            if (trackedIcons.TryGetValue(key, out MinimapIcon icon))
            {
                if (icon != null) Destroy(icon.gameObject);
            }
            trackedIcons.Remove(key);
        }
    }
}

/// <summary>
/// Minimap icon that follows a world-space target.
/// </summary>
public class MinimapIcon : MonoBehaviour
{
    private Transform target;
    private float heightOffset = 40f;

    public void Initialize(Transform trackedTarget, Color color, float scale)
    {
        target = trackedTarget;
        transform.localScale = Vector3.one * scale;

        Renderer rend = GetComponent<Renderer>();
        if (rend != null)
            rend.material.color = color;

        // Place on minimap layer
        gameObject.layer = LayerMask.NameToLayer("Minimap");
    }

    private void LateUpdate()
    {
        if (target == null)
        {
            Destroy(gameObject);
            return;
        }

        Vector3 pos = target.position;
        pos.y = target.position.y + heightOffset;
        transform.position = pos;
    }
}