Creating a FNAF Interactive Map
In this video, we bring the FNAF camera map system to life — creating a fully animated in-game map and working camera buttons, just like the ones in Five Nights at Freddy’s. We’ll walk through every step — from importing and cleaning up a hand-drawn map to building a functional camera UI that changes scenes and blinks when selected.
This is the second episode in a series where we build a complete 2D FNAF-style game from scratch using real programming and logic — no shortcuts, just solid Unity skills.
Want to see the full system in action, including all the Unity scripts and UI setup?
You can copy and paste the complete code directly from the tutorial or…
Just want the Unity Package with everything pre-built?
Become a Patreon member at the Creator Level to download now:
MapAnimator.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class MapAnimator : MonoBehaviour
{
public RectTransform mapPanel;
public Image arrow;
public float speed = 5.0f;
public Vector2 hiddenPosition;
public Vector2 visiblePosition;
public AudioSource mapOpenSound;
private bool mapVisible = false;
private bool isHoveringArrow = false;
void Start()
{
visiblePosition = mapPanel.anchoredPosition;
mapPanel.anchoredPosition = hiddenPosition;
arrow.enabled = true;
}
public void OnArrowEnter()
{
isHoveringArrow = true;
arrow.enabled = false;
if (!mapVisible)
ShowMap();
else
HideMap();
}
public void OnArrowExit()
{
isHoveringArrow = false;
arrow.enabled = true;
}
public void ShowMap()
{
mapVisible = true;
StopAllCoroutines();
StartCoroutine(SlideTo(visiblePosition));
if(mapOpenSound != null)
{
mapOpenSound.Play();
}
}
public void HideMap()
{
mapVisible = false;
StopAllCoroutines();
StartCoroutine(SlideTo(hiddenPosition));
if (mapOpenSound != null)
mapOpenSound.Play();
}
public IEnumerator SlideTo(Vector2 target)
{
while(Vector2.Distance(mapPanel.anchoredPosition, target) > 0.1f)
{
mapPanel.anchoredPosition = Vector2.Lerp(mapPanel.anchoredPosition, target, Time.deltaTime * speed);
yield return null;
}
mapPanel.anchoredPosition = target;
}
}
CameraAreaController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CameraAreaController : MonoBehaviour
{
public Texture roomBackgroundSprite;
public Image cameraUIBackground;
public Color normalColor = Color.black;
public Color blinkColor = Color.white;
public float blinkInterval = 0.5f;
private Coroutine blinkCoroutine;
public void StartBlinking()
{
StopBlinking();
blinkCoroutine = StartCoroutine(BlinkLoop());
}
public void StopBlinking()
{
if (blinkCoroutine != null)
{
StopCoroutine(blinkCoroutine);
blinkCoroutine = null;
}
if (cameraUIBackground != null)
cameraUIBackground.color = normalColor;
}
private IEnumerator BlinkLoop()
{
bool toggle = false;
while (true)
{
cameraUIBackground.color = toggle ? blinkColor : normalColor;
toggle = !toggle;
yield return new WaitForSeconds(blinkInterval);
}
}
}
CameraManager.cs
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
public class CameraManager : MonoBehaviour
{
public RawImage background;
private Material backgroundMaterial;
private CameraAreaController lastSelected;
public void Start()
{
backgroundMaterial = background.material;
}
public void SelectCamera(CameraAreaController selected)
{
backgroundMaterial.SetTexture("_background", selected.roomBackgroundSprite);
if (lastSelected != null && lastSelected != selected)
lastSelected.StopBlinking();
selected.StartBlinking();
lastSelected = selected;
}
}