Part of these game systems:
Minimap System
Render texture minimap with player icon, enemy blips, objective markers, and zoom control.
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
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;
}
}