Build a Horror Exploration Scene in Unity

Build a first-person horror game scene with interaction and atmosphere.

Introduction

30 Second Summary

You know that feeling when you open a door in a horror game and every instinct tells you not to go in? Someone designed that feeling. Every shadow, every creaking sound, every story clue you discover was placed deliberately to build tension.

In this project, you will build a playable first-person horror exploration scene in Unity. You will create a dark house interior, add a working interaction system for discovering story objects, and design atmospheric lighting and audio that makes the player feel genuinely uneasy.

What You'll Build

A first-person horror exploration demo where the player moves through connected rooms, examines interactive story objects that reveal narrative about a missing father, and experiences tension through moody lighting and ambient sound.

By the end of this project, you'll have:

  • A playable first-person scene with WASD movement and mouse look inside a multi-room indoor environment built with ProBuilder.
  • A raycast-based interaction system that detects story objects and displays narrative text on screen when the player presses E.
  • An atmospheric horror environment using point lights with shadows and looping ambient audio to create tension.
  • Secret Mission: a scripted horror event where a door slams shut behind the player when they pick up a key item.

Are there any prerequisites?

No prior Unity or C# experience is required. You just need basic computer literacy and familiarity with installing software. The project walks you through every step from creating the project to writing your first scripts.

Set Up Your Unity Project

Every game starts with a properly configured project. Before you build rooms, write scripts, or add atmosphere, you need the right Unity editor version, rendering pipeline, and tools in place.

In this step, you will install Unity 6.3 LTS, create a new project with the Universal Render Pipeline (URP), and import the packages that give you in-editor level building and first-person movement.

In this step, get ready to:
  • Install or verify Unity 6.3 LTS and create the HorrorExploration project with URP.
  • Install the ProBuilder package for in-editor geometry building.
  • Import the Starter Assets for first-person movement and camera control.
Create your Unity project

Unity Hub is your launcher for managing editor versions and projects. You will use it to verify your editor version and create the project.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Unity Hub and press Enter to open it.
  • Click Installs in the left sidebar.
  • Check the list of installed editors for Unity 6.3 LTS.

✔️ I see Unity 6.3 LTS in my installs

You are ready to create your project. Skip ahead to the project creation instructions below.

ⓧ I see an older Unity version

You can install Unity 6.3 LTS alongside your existing version. Unity Hub supports multiple editors side-by-side.

  • Click Install Editor at the top right of the Installs window.
  • Select the Official releases tab.
  • Find Unity 6.3 LTS in the list and click Install.
  • Wait for the download and installation to complete. You can monitor progress in the Downloads panel in the Hub toolbar.

How long does this take?

The Unity editor download is several gigabytes. Depending on your internet speed, this may take 10-20 minutes.

ⓧ I don't have any editor installed

You need to install the Unity editor before you can create projects.

  • Click Install Editor at the top right of the Installs window.
  • Select the Official releases tab.
  • Find Unity 6.3 LTS in the list and click Install.
  • Wait for the download and installation to complete. You can monitor progress in the Downloads panel in the Hub toolbar.

How long does this take?

The Unity editor download is several gigabytes. Depending on your internet speed, this may take 10-20 minutes.

Now create your project with the URP template.

  • In Unity Hub, click Projects in the left sidebar.
  • Click New project in the top right.
  • Make sure the editor version dropdown at the top shows Unity 6.3 LTS. If not, click the dropdown and select it.
  • Select the Universal 3D template from the template list. This configures URP automatically.
  • In the Project name field, type HorrorExploration.
  • Click Create project.

Unity will create and open your new project. This takes a minute or two while it imports the default URP assets.

What is URP?

The Universal Render Pipeline is Unity's optimized rendering system for cross-platform games. It provides great lighting and shadow features at good performance, making it ideal for a low-poly horror game.

By choosing the "Universal 3D" template, your project is already configured with URP shaders, settings, and a default rendering pipeline asset. No manual pipeline setup is needed.

Project creation taking a very long time?

The first project creation in a new Unity version imports all default packages. If it seems stuck, check the bottom-left progress bar in the Unity Editor. If the editor is unresponsive for more than 5 minutes, close it and try creating the project again.

help me troubleshoot my Unity project creation

Install ProBuilder

ProBuilder lets you build 3D geometry directly inside the Unity Editor. You will use it to create your rooms, walls, and doorways without needing an external modeling tool like Blender.

  • In the Unity Editor, click Window in the top menu bar.
  • Click Package Manager.
  • In the Package Manager window, click the Packages dropdown in the top-left corner.
  • Select Unity Registry from the dropdown.
  • In the search bar, type ProBuilder.
  • Click the ProBuilder entry in the results list (com.unity.probuilder).
  • Click Install in the package details pane on the right.

After installation completes, you need to import the URP shaders so ProBuilder objects display correctly in your project.

  • With the ProBuilder package still selected in the Package Manager, scroll down to the Samples section in the package details. You may need to expand it.
  • Click the Import button next to the Universal Render Pipeline support entry.

Why import the URP shaders?

ProBuilder needs render-pipeline-specific shaders to display vertex colors and textures correctly. Without importing these, your ProBuilder objects may appear pink or invisible in a URP project.

  • Verify the installation by clicking Tools in the top menu bar. You should see a ProBuilder option in the dropdown menu.

Don't see ProBuilder in the Tools menu?

Make sure the Packages dropdown in Package Manager is set to Unity Registry, not "In Project" or "My Assets". If ProBuilder shows as installed but doesn't appear in the Tools menu, try closing and reopening the Unity Editor.

help me find ProBuilder in my Unity Editor

Import the Starter Assets

Writing a first-person controller from scratch is complex and error-prone. Unity's free Starter Assets give you production-quality first-person movement with WASD controls and mouse look out of the box.

  • Open your web browser and go to assetstore.unity.com.
  • Search for Starter Assets - FirstPerson | URP.
  • Click the asset in the results. It is free.
  • Click Add to My Assets. You may need to sign in with your Unity account.

Now import the package into your Unity project.

  • Back in the Unity Editor, click Window in the top menu bar.
  • Click Package Manager.
  • In the Package Manager, click the Packages dropdown in the top-left.
  • Select My Assets.
  • Find Starter Assets - FirstPerson | URP in the list.
  • Click Download, then click Import when the download finishes.

Unity will ask to enable the new Input System

During import, a dialog will ask if you want to enable the new Input System backend and restart the editor. Click Yes. The editor will close and reopen automatically.

After the restart, if a dialog asks you to reimport the Starter Assets package, click Import again to finish.

What are the Starter Assets?

The Starter Assets provide a fully functional first-person character controller built on Unity's CharacterController component. It handles gravity, ground detection, smooth camera movement, and input using the new Input System.

This saves you from writing 200+ lines of movement code and lets you focus on the gameplay systems unique to your horror game.

Now verify everything works by testing the included sample scene.

  • In the Project window at the bottom of the editor, navigate to Assets/StarterAssets/FirstPersonController/Scenes.
  • Double-click the Playground scene to open it.
  • Click the Play button at the top center of the editor (the triangle icon).
  • Move around with WASD and look around with your mouse.

You should be able to walk freely through the playground environment and look around smoothly with the mouse.

Can't move or the camera doesn't respond?

Make sure you clicked the Game view window to give it focus. If the mouse cursor is visible (not locked to the center), click inside the Game view. If movement still doesn't work, confirm the Input System restart completed successfully by checking that no error messages appear in the Console window.

help me fix my first-person controller in the Playground scene

  • Click the Play button again to exit Play mode.

Your project is set up with the right editor, rendering pipeline, and movement system. Next up, you will build the indoor environment where your horror game takes place.

Build the Indoor Environment with ProBuilder

Your Unity project is ready with all the right tools installed. Now it is time to build the physical space your player will explore.

Horror games live and die by their environments. Tight hallways, dark rooms, and closed-off spaces create tension before a single scare happens. In this step, you will use ProBuilder to model a small house interior directly inside the Unity Editor.

In this step, get ready to:
  • Create a new scene and build the first room (hallway) with ProBuilder.
  • Add two more connected rooms with doorways between them.
  • Apply materials and add simple furniture to bring the space to life.
Create a new scene and build the hallway

The default SampleScene has objects you do not need. You will start fresh with an empty scene and build your first room from scratch.

  • In the Hierarchy window, select Main Camera and Directional Light (hold Ctrl/Cmd to multi-select).
  • Press Delete to remove them.
  • Go to File in the top menu bar, then click New Scene.
  • In the New Scene dialog, select Empty and click Create.
  • Save the scene immediately by pressing Ctrl+S (Windows) or Cmd+S (macOS).
  • In the Save dialog, create a new folder called Scenes inside your Assets folder.
  • Name the scene HouseScene and click Save.

You should see an empty Scene view with just a grid. The title bar should show HouseScene.

  • Open the ProBuilder toolbar by going to Tools in the top menu, then ProBuilder, then ProBuilder Window.
  • Dock the ProBuilder Window by dragging its tab next to the Inspector or Hierarchy panel.

What is ProBuilder?

ProBuilder is a Unity package that lets you model 3D geometry directly inside the editor. You can create, edit, and texture meshes without ever leaving Unity.

For a low-poly horror game, simple boxes and planes are all you need. This avoids the complexity of learning a separate 3D modeling tool like Blender.

  • In the ProBuilder toolbar, click New Shape. The Create Shape panel appears at the bottom of your Scene view.
  • Select the Cube shape from the shape icons at the top of the panel.
  • In the Shape Settings, set the bounding box dimensions to X: 8, Y: 3, Z: 10.
  • Click in the Scene view to place the shape.
  • Press Esc to exit the New Shape tool.
  • Rename this object to Hallway in the Hierarchy (double-click the name to edit it).

You now have a solid cube in the scene. To make it feel like an interior room, you need to flip the normals inward so the inside faces render instead of the outside.

  • Select the Hallway object in the Hierarchy.
  • Go to Tools in the top menu, then ProBuilder, then Object, then Flip Object Normals.

What are normals?

Every face on a 3D mesh has a "normal" that points outward. Unity only renders the side a normal points toward. By default, a cube's normals face outward so you see the exterior.

Flipping normals inward means the player sees the interior walls, floor, and ceiling when standing inside the box. The outside becomes invisible.

Double-click the Hallway object to zoom into it. You should see the inside faces of the cube rendered as a room-like interior.

Room looks invisible or inside-out?

If you cannot see any surfaces when you zoom inside the cube, the normals may still face outward. Select the object and run Tools > ProBuilder > Object > Flip Object Normals again.

If surfaces appear pink or magenta, ProBuilder needs its URP shaders. Go to Window > Package Manager, find ProBuilder, expand the Samples section, and import the URP Shaders sample.

help me fix my ProBuilder room surfaces

Add the main room and study with connecting doorways

One room is not enough for a horror exploration scene. You need connected spaces the player can move between, with doorways creating that sense of transition and discovery.

  • Using the same process as before, click New Shape in the ProBuilder toolbar.
  • Select Cube and set dimensions to X: 10, Y: 3, Z: 10.
  • Click in the Scene view to place it, then press Esc to exit the tool.
  • Rename this object to MainRoom in the Hierarchy.
  • Select MainRoom and flip its normals: Tools > ProBuilder > Object > Flip Object Normals.
  • Use the Move tool (W key) to position MainRoom adjacent to the hallway so one wall of each room overlaps where the doorway will be.

Now you need to cut a doorway between the two rooms. You will delete a face from each room where they connect.

  • Select the Hallway object.
  • In the ProBuilder toolbar, switch to Face selection mode (the square icon in the edit mode toolbar).
  • Click on the face where the hallway meets the main room.
  • Press Delete or Backspace to remove that face. This creates the doorway opening.
  • Repeat for MainRoom: select it, switch to Face mode, select the corresponding face, and delete it.
  • Create the third room by clicking New Shape again with dimensions X: 6, Y: 3, Z: 6.
  • Rename it to Study.
  • Flip its normals: Tools > ProBuilder > Object > Flip Object Normals.
  • Position the Study adjacent to the main room on a different wall.
  • Delete a face from both MainRoom and Study where they connect to create the second doorway.

Save your scene with Ctrl+S (Windows) or Cmd+S (macOS). You should now see three connected box shapes in the Scene view forming your level layout.

Aligning rooms precisely

Hold Ctrl (Windows) or Cmd (macOS) while dragging to snap objects to the grid. This makes it easier to line up walls perfectly so doorways connect cleanly.

Doorway faces not lining up?

Make sure both rooms share the same Y position (floor height). Check the Transform Y value in the Inspector for both objects and set them to the same number.

If deleting a face does not create a visible opening, confirm you are in Face selection mode (not Vertex or Edge) before pressing Delete.

help me align my ProBuilder rooms and doorways

Apply materials and add placeholder furniture

Plain white geometry does not feel like a horror game. A couple of dark materials and simple furniture shapes will give the space depth and make it feel inhabited.

  • In the Project window, right-click inside your Assets folder.
  • Select Create, then Material.
  • Name the new material WallMaterial.
  • In the Inspector, click the Base Map color swatch and set it to a dark grey or muted brown (something like hex #3D3530).
  • Create a second material and name it FloorMaterial.
  • Set its color to a darker shade (something like hex #1A1614).
  • Drag WallMaterial from the Project window onto the wall surfaces of each room in the Scene view.
  • To apply a material to specific faces only (like floors), select the room object, switch to Face selection mode, select the bottom face, then drag FloorMaterial onto the selected face.

Why not use textures?

For a low-poly horror game, flat colored materials create the right aesthetic. Textures add visual noise that can distract from the atmosphere you are building with lighting (which comes in a later step).

Your rooms should now show dark walls and darker floors instead of the default white. Next, add some simple furniture to give the player reference points.

  • Click New Shape in the ProBuilder toolbar and create a Cube with dimensions X: 1.2, Y: 0.8, Z: 0.6.
  • Rename it to Desk and position it inside the Study room against a wall.
  • Create another Cube with dimensions X: 0.4, Y: 2.5, Z: 1.5.
  • Rename it to Bookshelf and position it in the MainRoom against a wall.
  • Create a flat Cube with dimensions X: 1.5, Y: 0.5, Z: 0.8.
  • Rename it to Table and position it in the Hallway.
  • Apply WallMaterial to the furniture objects so they blend with the environment.

Save your scene. You should have three connected rooms with dark materials applied and simple furniture shapes placed inside them.

Furniture floating or clipping through the floor?

Check the Y position of each furniture object in the Inspector. The bottom of the object should sit at the same Y level as the room floor. Adjust the Y transform until the furniture looks grounded.

help me position my furniture objects on the floor

Your environment is built. Next up, you will drop in the first-person player controller and walk through your rooms for the first time.

Add the Player and Set Up the Scene

Your house is built. Three connected rooms with dark walls, colored floors, and placeholder furniture are ready in HouseScene.

Now you need a pair of eyes to walk through it. In this step, you'll place a first-person player controller from the Starter Assets into your scene and tune the camera for a tight, claustrophobic horror perspective.

In this step, get ready to:
  • Place the first-person player controller in the hallway.
  • Verify floor colliders and test movement through all rooms.
  • Adjust the camera field of view for horror atmosphere.
Place the player controller in the scene

The Starter Assets package you imported earlier includes a ready-made first-person controller prefab. It handles WASD movement, mouse look, and gravity out of the box.

  • In the Project window at the bottom of the Unity Editor, navigate to Assets/StarterAssets/FirstPersonController/Prefabs.
  • Find the PlayerCapsule prefab in that folder.
  • Drag PlayerCapsule from the Project window into your Hierarchy panel (the list of objects in your scene on the left).
  • With PlayerCapsule selected in the Hierarchy, look at the Inspector panel on the right. Find the Transform section at the top.
  • Set Position to X: 0, Y: 1, Z: 0. This places the player at the start of the hallway.
  • Check if a standalone Main Camera object exists in your Hierarchy (separate from the PlayerCapsule). If it does, right-click it and select Delete. The player prefab includes its own camera, so a second one causes conflicts.

Why delete the extra camera?

Unity renders what the active camera sees. If two cameras exist in the scene, you can get overlapping views or unexpected behavior. The PlayerCapsule prefab already has a camera attached to it that follows your mouse movement, so any standalone Main Camera must go.

You should now see the PlayerCapsule listed in your Hierarchy with no standalone Main Camera alongside it.

Don't see the PlayerCapsule prefab?

Make sure you imported the Starter Assets in Step 1. If the Assets/StarterAssets folder does not exist, return to Window > Package Manager, switch to My Assets, and import the Starter Assets - FirstPerson | URP package again.

Help me find the PlayerCapsule prefab in my project

Verify colliders and test movement

ProBuilder objects automatically receive a MeshCollider component when created. This means your floors already have collision surfaces that prevent the player from falling through.

  • Click on one of your floor ProBuilder objects in the Hierarchy.
  • In the Inspector, confirm you see a Mesh Collider component listed. If it is missing, click Add Component at the bottom of the Inspector and search for Mesh Collider.
  • Press the Play button at the top center of the Unity Editor (the triangle icon) to enter Play mode.
  • Use W/A/S/D to move and your mouse to look around. Walk through all three rooms.
  • Press Play again to exit Play mode when done testing.

You should be able to walk through all three rooms without falling through the floor. Doorways should be passable and furniture should be at realistic heights relative to your viewpoint.

What if the scale feels wrong?

If the player feels too big (bumping into ceilings) or too small (furniture towers over you), select the PlayerCapsule in the Hierarchy and find the CharacterController component in the Inspector. The Height property controls the capsule's vertical size. Unity recommends around 2 meters for a human-like character.

You can also scale your ProBuilder room objects slightly to make doorways taller or rooms wider. Adjust until walking through the space feels natural.

Falling through the floor?

Your floor ProBuilder object may be missing its collider. Select the floor in the Hierarchy and confirm a Mesh Collider component appears in the Inspector. If not, click Add Component and add one.

Also check that the PlayerCapsule's Y position is above the floor surface (not inside it). A starting Y of 1 should keep the player above a floor at Y 0.

Help me fix my player falling through the floor

Adjust the camera for horror atmosphere

The default camera field of view is wide and open. Horror games use a narrower FOV to create a claustrophobic, tunnel-vision feeling that limits what the player can see at the edges of their screen.

  • In the Hierarchy, expand the PlayerCapsule object by clicking the arrow next to it. Find the child object that has a Camera component (look for the camera icon).
  • Select that camera child object.
  • In the Inspector, find the Camera component section.
  • Locate the Field of View property (visible when Projection is set to Perspective).
  • Change the value to 60. This gives a tighter, more claustrophobic perspective than the default.
  • Press Ctrl+S (Windows) or Cmd+S (macOS) to save your scene.
  • Press Play to test the full experience. Walk through all rooms and notice how the narrower FOV makes the hallway feel tighter.

What does Field of View do?

Field of View (FOV) controls how wide the camera's viewing angle is, measured in degrees. A higher FOV (like 90) shows more of the world at once, making spaces feel open. A lower FOV (like 60) narrows the view, making corridors feel tighter and limiting peripheral vision.

Horror games deliberately use lower FOV values so the player cannot see threats approaching from the side. This builds tension because you have to physically turn to check your surroundings.

Press Play again to exit Play mode. Your scene should now have a working first-person controller with a tight, atmospheric camera perspective.

Camera feels the same as before?

Make sure you changed the FOV on the correct camera. The camera must be the child object inside the PlayerCapsule hierarchy, not a separate camera in the scene. Also confirm you are editing the Field of View field in the Camera component, not another numeric field.

Changes made during Play mode are lost when you exit Play mode. If you adjusted the FOV while the game was running, exit Play mode first and make the change again.

Help me adjust my camera's field of view

Your player is in the scene and the camera feels appropriately claustrophobic. Next up, you'll build the interaction system that lets the player examine story objects and uncover clues about the missing father.

Build the Interaction System

Your rooms are built, your furniture is placed, and you can walk through the entire house. But right now you are just passing through an empty space with no way to engage with anything.

Horror games are driven by discovery. The player needs to find objects, read notes, and piece together a story. In this step, you will build the interaction system that makes all of that possible.

In this step, get ready to:
  • Write a C# interface and raycast script that detects interactive objects.
  • Create a UI canvas that shows interaction prompts on screen.
  • Place three story objects (letter, photo frame, locked door) that the player can examine.
Create the interaction interface and base scripts

Every interactive object in your game needs to share a common contract. The player looks at an object, sees a prompt, and presses a key to interact. An interface defines that contract so any object can be interactive without inheriting from the same base class.

  • In the Project window, right-click inside the Assets folder.
  • Select Create, then Folder.
  • Name the folder Scripts.
  • Inside the Scripts folder, right-click and select Create, then C# Script.
  • Name the script IInteractable.
  • Double-click IInteractable.cs to open it in VS Code, then replace all of the default content with this code:
using UnityEngine;

public interface IInteractable
{
    string PromptMessage { get; }
    void Interact();
}

What does this code do?

This is a C# interface. It defines two things every interactable object must have.

  • PromptMessage is a read-only string property that provides the text shown to the player (like "Press E to read").
  • Interact() is the method that runs when the player actually presses the interaction key.
  • Save IInteractable.cs.

✔️ Awesome, I've got everything!

Great. Make sure the file is saved before moving on.

ⓧ I'd like to double check the full code

using UnityEngine;

public interface IInteractable
{
    string PromptMessage { get; }
    void Interact();
}

Now you need the script that fires a ray from the player camera to detect these interactable objects. This technique is called raycasting. It sends an invisible line forward from the camera and reports what it hits.

  • Before creating the raycast script, set up a dedicated layer so the raycast only checks objects you mark as interactable.
  • In the Unity menu bar, click Edit, then Project Settings.
  • Select Tags and Layers in the left sidebar.
  • Expand the Layers section and find an empty User Layer slot (for example, User Layer 6).
  • Type Interactable into the empty slot and press Enter.
  • Close Project Settings.

What is a layer?

Layers let you group GameObjects so that Unity APIs like Physics.Raycast can target only certain objects. By creating an "Interactable" layer, your raycast ignores walls and furniture and only detects objects the player can interact with.

  • Back in the Scripts folder, create a new C# script named Interactor.
  • Double-click Interactor.cs to open it in VS Code, then replace all of the default content with this code:
using UnityEngine;

public class Interactor : MonoBehaviour
{
    [SerializeField] private float interactionRange = 3f;
    [SerializeField] private LayerMask interactableLayer;
    [SerializeField] private InteractionUI interactionUI;

    private IInteractable currentInteractable;
    private Camera playerCamera;

    private void Start()
    {
        playerCamera = GetComponent<Camera>();
    }

    private void Update()
    {
        CheckForInteractable();
        HandleInteractionInput();
    }

    private void CheckForInteractable()
    {
        Ray ray = new Ray(playerCamera.transform.position, playerCamera.transform.forward);

        if (Physics.Raycast(ray, out RaycastHit hit, interactionRange, interactableLayer))
        {
            if (hit.collider.TryGetComponent(out IInteractable interactable))
            {
                currentInteractable = interactable;
                interactionUI.ShowPrompt(interactable.PromptMessage);
                return;
            }
        }

        currentInteractable = null;
        interactionUI.HidePrompt();
    }

    private void HandleInteractionInput()
    {
        if (currentInteractable != null && Input.GetKeyDown(KeyCode.E))
        {
            currentInteractable.Interact();
        }
    }
}

What does this code do?

  • CheckForInteractable() fires a ray from the camera each frame. If it hits something on the Interactable layer that has an IInteractable component, it stores a reference and shows the prompt.
  • HandleInteractionInput() checks if the player presses E while looking at an interactable object. If so, it calls Interact() on that object.
  • TryGetComponent is the modern Unity pattern for checking if a GameObject has a specific component without returning null.
  • Save Interactor.cs.
  • Switch back to Unity. Wait for it to compile (the spinner in the bottom-right corner of the Editor disappears when done).

Seeing compile errors?

If Unity shows an error about InteractionUI not being found, that is expected. You will create the InteractionUI script in the next substep, and the error will resolve then.

Help me fix compile errors in my Interactor script.

✔️ Awesome, I've got everything!

Great. Make sure both scripts are saved before continuing.

ⓧ I'd like to double check the full code

using UnityEngine;

public class Interactor : MonoBehaviour
{
    [SerializeField] private float interactionRange = 3f;
    [SerializeField] private LayerMask interactableLayer;
    [SerializeField] private InteractionUI interactionUI;

    private IInteractable currentInteractable;
    private Camera playerCamera;

    private void Start()
    {
        playerCamera = GetComponent<Camera>();
    }

    private void Update()
    {
        CheckForInteractable();
        HandleInteractionInput();
    }

    private void CheckForInteractable()
    {
        Ray ray = new Ray(playerCamera.transform.position, playerCamera.transform.forward);

        if (Physics.Raycast(ray, out RaycastHit hit, interactionRange, interactableLayer))
        {
            if (hit.collider.TryGetComponent(out IInteractable interactable))
            {
                currentInteractable = interactable;
                interactionUI.ShowPrompt(interactable.PromptMessage);
                return;
            }
        }

        currentInteractable = null;
        interactionUI.HidePrompt();
    }

    private void HandleInteractionInput()
    {
        if (currentInteractable != null && Input.GetKeyDown(KeyCode.E))
        {
            currentInteractable.Interact();
        }
    }
}
Create the UI prompt system

The Interactor detects objects, but the player needs to see the prompt on screen. Unity's UI system uses a Canvas to render 2D elements on top of the 3D scene.

  • In the Hierarchy window, right-click in an empty area.
  • Select UI, then Canvas.
  • Select the new Canvas in the Hierarchy. In the Inspector, confirm that Render Mode is set to Screen Space - Overlay (this is the default).

You need two separate UI panels. One shows the interaction prompt ("Press E to read"). The other shows the story text when the player actually interacts.

  • Right-click the Canvas in the Hierarchy and select Create Empty. Name it PromptPanel.
  • Right-click PromptPanel and select UI, then Text - TextMeshPro.
  • If Unity asks you to import TMP Essentials, click Import TMP Essentials.
  • Name this text object PromptText.
  • Select PromptText and in the Inspector, set the Alignment to center (both horizontal and vertical).
  • Position the PromptPanel near the center-bottom of the screen using the Rect Transform anchors.
  • Now create the story display panel. Right-click the Canvas again and select Create Empty. Name it StoryPanel.
  • Right-click StoryPanel and select UI, then Text - TextMeshPro.
  • Name this text object StoryText.
  • Center the text alignment and position the StoryPanel in the center of the screen.
  • Set StoryPanel to inactive by unchecking the checkbox at the top-left of the Inspector. The story text should only appear when triggered.

Now create the script that controls these UI elements.

  • In the Scripts folder, create a new C# script named InteractionUI.
  • Open InteractionUI.cs in VS Code and replace all of the default content with this code:
using UnityEngine;
using TMPro;

public class InteractionUI : MonoBehaviour
{
    [SerializeField] private TextMeshProUGUI promptText;
    [SerializeField] private GameObject promptPanel;

    public void ShowPrompt(string message)
    {
        promptText.text = message;
        promptPanel.SetActive(true);
    }

    public void HidePrompt()
    {
        promptPanel.SetActive(false);
    }
}

What does this code do?

  • ShowPrompt() sets the text content to the interactable object's prompt message and makes the panel visible.
  • HidePrompt() deactivates the panel when the player looks away. This keeps the screen clean unless you are aiming directly at something interactive.
  • TextMeshProUGUI is the TextMeshPro component for UI text. It lives in the TMPro namespace.
  • Save InteractionUI.cs.
  • Switch back to Unity and wait for compilation to finish.

Now wire everything together in the Unity Inspector.

  • Select the Canvas in the Hierarchy.
  • In the Inspector, click Add Component and search for InteractionUI. Add it.
  • Drag the PromptText object from the Hierarchy into the Prompt Text field on the InteractionUI component.
  • Drag the PromptPanel object into the Prompt Panel field.
  • Set PromptPanel to inactive (uncheck the checkbox at the top-left of its Inspector). It should only appear when the raycast finds a target.
  • Now attach the Interactor to the player camera. In the Hierarchy, expand PlayerCapsule and find its child Camera object (often named MainCamera or a child under PlayerCameraRoot).
  • Select the GameObject that has the Camera component.
  • Click Add Component and search for Interactor. Add it.
  • In the Interactor component, set the Interactable Layer dropdown to the Interactable layer you created earlier.
  • Drag the Canvas object (which has InteractionUI attached) into the Interaction UI field on the Interactor component.
  • Save your scene with Ctrl+S (Windows) or Cmd+S (macOS).

Still seeing compile errors?

Make sure all three scripts (IInteractable.cs, Interactor.cs, InteractionUI.cs) are saved and located in the Assets/Scripts folder.

Check that IInteractable.cs does not have a class declaration wrapping the interface. Unity auto-generates a class template, and you need to replace all of it.

Help me fix compile errors in my interaction scripts.

✔️ Awesome, I've got everything!

Great. Double check you have saved your scene.

ⓧ I'd like to double check the full code

using UnityEngine;
using TMPro;

public class InteractionUI : MonoBehaviour
{
    [SerializeField] private TextMeshProUGUI promptText;
    [SerializeField] private GameObject promptPanel;

    public void ShowPrompt(string message)
    {
        promptText.text = message;
        promptPanel.SetActive(true);
    }

    public void HidePrompt()
    {
        promptPanel.SetActive(false);
    }
}
Create interactive story objects

With the detection and UI systems wired up, you need actual objects the player can examine. Each story object reveals a piece of narrative about the missing father.

  • In the Scripts folder, create a new C# script named StoryNote.
  • Open StoryNote.cs in VS Code and replace all of the default content with this code:
using UnityEngine;
using TMPro;

public class StoryNote : MonoBehaviour, IInteractable
{
    [SerializeField] private string promptMessage = "Press E to read";
    [SerializeField][TextArea] private string noteContent = "Dad's handwriting... 'If you're reading this, I had no choice. Go to the study.'";
    [SerializeField] private TextMeshProUGUI storyText;
    [SerializeField] private GameObject storyPanel;
    [SerializeField] private float displayDuration = 4f;

    public string PromptMessage => promptMessage;

    public void Interact()
    {
        storyText.text = noteContent;
        storyPanel.SetActive(true);
        Invoke(nameof(HideStoryText), displayDuration);
    }

    private void HideStoryText()
    {
        storyPanel.SetActive(false);
    }
}

What does this code do?

  • StoryNote implements IInteractable, meaning it fulfills the contract your Interactor expects.
  • When the player presses E, Interact() sets the story text content, makes the panel visible, and uses Invoke to hide it after displayDuration seconds (default 4).
  • The [TextArea] attribute gives you a larger text field in the Inspector so you can write longer narrative content comfortably.
  • Save StoryNote.cs and switch back to Unity.

✔️ Awesome, I've got everything!

Great. Make sure you see no compile errors in the Unity Console before continuing.

ⓧ I'd like to double check the full code

using UnityEngine;
using TMPro;

public class StoryNote : MonoBehaviour, IInteractable
{
    [SerializeField] private string promptMessage = "Press E to read";
    [SerializeField][TextArea] private string noteContent = "Dad's handwriting... 'If you're reading this, I had no choice. Go to the study.'";
    [SerializeField] private TextMeshProUGUI storyText;
    [SerializeField] private GameObject storyPanel;
    [SerializeField] private float displayDuration = 4f;

    public string PromptMessage => promptMessage;

    public void Interact()
    {
        storyText.text = noteContent;
        storyPanel.SetActive(true);
        Invoke(nameof(HideStoryText), displayDuration);
    }

    private void HideStoryText()
    {
        storyPanel.SetActive(false);
    }
}

Now place the three story objects in your scene.

  • In the Hierarchy, right-click and select 3D Object, then Cube. Name it Letter.
  • In the Inspector, set the Scale to X: 0.3, Y: 0.02, Z: 0.2. This makes a thin envelope shape.
  • Position the Letter on top of the Desk in the study room.
  • Make sure the Letter has a Box Collider (Unity adds one by default on Cubes).
  • Set the Letter's Layer (dropdown at the top of the Inspector) to Interactable.
  • Click Add Component and add the StoryNote script.
  • In the StoryNote component fields, drag the StoryText object from the Canvas into the Story Text field.
  • Drag the StoryPanel object into the Story Panel field.
  • Leave the default noteContent text as is, or customize it with your own narrative.
  • Create the second story object. Right-click in the Hierarchy and select 3D Object, then Cube. Name it PhotoFrame.
  • Scale it to a flat rectangle shape (for example, X: 0.4, Y: 0.3, Z: 0.02) and mount it against a wall in the main room.
  • Set the Layer to Interactable.
  • Add the StoryNote component. Change the noteContent to something unique (for example, "A family photo. Everyone is smiling except dad. His eyes look tired.").
  • Wire up the Story Text and Story Panel fields the same way as the Letter.
  • Create the third story object. Right-click in the Hierarchy and select 3D Object, then Cube. Name it LockedDoor.
  • Scale it to a door shape (for example, X: 1, Y: 2.2, Z: 0.1) and place it in the hallway.
  • Set the Layer to Interactable.
  • Add the StoryNote component. Change the promptMessage to something like "Press E to examine" and the noteContent to "It is locked. The handle will not budge."
  • Wire up the Story Text and Story Panel fields.
  • Save your scene with Ctrl+S (Windows) or Cmd+S (macOS).
  • Press Play to test.
  • Walk up to the Letter in the study. You should see a "Press E to read" prompt appear on screen.
  • Press E. The story text should display for 4 seconds and then disappear.
  • Walk away from the Letter. The prompt should disappear.

Prompt not appearing?

Check that the Letter's Layer is set to Interactable in the Inspector. If it is still on Default, the raycast will miss it entirely.

Also verify that the Interactor's Interactable Layer field is set to the Interactable layer. If it shows Nothing, the raycast has no layers to check.

Help me debug my interaction system.

Your interaction system is working. Next up, you will transform this space from a quiet walk-through into a tense horror experience with moody lighting and ambient audio.

Create Atmosphere with Lighting and Audio

Your interaction system is working. Players can walk up to objects and read story clues. But right now, the scene is brightly lit and silent. That does not feel like a horror game.

In this step, you will transform the mood of your scene using point lights and ambient audio. Darkness forces players to move cautiously, and sound fills the silence with dread.

In this step, get ready to:
  • Set up moody point lighting with shadows.
  • Add looping ambient audio for tension.
  • Polish camera settings and complete a final playtest.
Set up moody lighting

Horror games rely on darkness to create tension. Instead of a single bright Directional Light illuminating everything evenly, you will use small Point Lights that only reach a few meters. This forces most of the scene into shadow.

  • In the Hierarchy panel, find and select any remaining Directional Light in the scene.
  • Right-click it and select Delete.

Your scene goes dark. That is exactly what you want.

  • Go to Window > Rendering > Lighting to open the Lighting window.
  • In the Environment tab, find the Environment Lighting section.
  • Change the Source dropdown from Skybox to Color.
  • Click the color swatch next to it and pick a very dark blue-grey (something like R:10, G:10, B:20). This provides the faintest ambient fill without washing out your shadows.

What is Environment Lighting?

Environment Lighting applies a uniform flat color to all surfaces in the scene as ambient light. Setting it to a very dark color means objects in shadow are nearly invisible, which is perfect for horror.

Now you will add individual Point Lights to illuminate only the areas you want the player to notice.

  • Right-click in the Hierarchy and select Light > Point Light.
  • Rename this light to Study Desk Light.
  • Position it just above the desk in the study room.
  • In the Inspector, set the Color to a warm orange tone.
  • Set Intensity to 2.
  • Set Range to 5.
  • In the Shadows section of the Light component, set Shadow Type to Soft Shadows.

Why enable Soft Shadows?

Shadows make light feel real. Without them, objects appear to float because there is no visual connection between them and the surfaces below. Soft Shadows have blurred edges that look more natural than Hard Shadows.

  • Create a second Point Light by right-clicking in the Hierarchy > Light > Point Light.
  • Rename it to Hallway Light and position it in the hallway.
  • Set its Color to a cool blue-white tone.
  • Set Intensity to 1.
  • Set Range to 3.
  • Create a third Point Light.
  • Rename it to Main Room Doorway Light and position it near the doorway leading into the main room.
  • Keep this one very faint. Set Intensity to 0.5 and Range to 3. The main room should feel uncomfortably dark.

Press Play and walk through your rooms. You should see isolated pools of light with deep darkness between them.

Scene still looks bright?

Make sure you deleted the Directional Light. Check the Hierarchy for any light you may have missed. Also confirm the Environment Lighting Source is set to Color (not Skybox) and that the color is very dark.

Help me troubleshoot why my scene is still too bright after removing the Directional Light and changing Environment Lighting.

Add ambient audio

A dark room is unsettling. A dark room with a faint, droning hum is terrifying. Audio fills the silence and keeps the player on edge even when nothing is happening on screen.

  • First, find a free ambient horror audio clip. Open your browser and visit a free sound site like freesound.org.
  • Search for a dark ambient loop or horror drone. Download a .wav or .mp3 file.
  • In your Unity Project window, right-click the Assets folder and select Create > Folder. Name it Audio.
  • Drag your downloaded audio file into the Assets/Audio folder to import it.
  • Right-click in the Hierarchy and select Create Empty.
  • Rename the new GameObject to AmbientAudio.
  • With AmbientAudio selected, click Add Component in the Inspector.
  • Search for and add an Audio Source component.
  • Drag your imported audio clip from the Assets/Audio folder into the AudioClip field on the Audio Source component.
  • Check the Loop checkbox so the audio repeats continuously.
  • Check the Play On Awake checkbox so the audio starts automatically when the scene loads.
  • Set the Volume slider to 0.3. Subtle audio creates more dread than loud audio.

Press Play. You should hear the ambient sound loop begin as soon as the scene starts.

No audio playing?

Make sure Play On Awake is checked. Confirm that the AudioClip field is not empty. Also check that your system volume is not muted and that the Unity Editor is not muted (click the audio icon in the Game view toolbar).

Help me figure out why my AudioSource is not playing in Unity.

Final polish and playtest

Two quick checks will make the experience feel more polished. A narrow field of view creates claustrophobia, and a locked cursor keeps the player immersed.

  • In the Hierarchy, expand the PlayerCapsule prefab and select the child object with the Camera component.
  • In the Inspector, find the Field of View property on the Camera component. Confirm it is set between 60 and 65. If it is higher, lower it to 60 for a tighter, more claustrophobic feel.

Why a narrow Field of View?

A lower FOV zooms the camera in slightly, reducing peripheral vision. This makes the player feel like they cannot see what is lurking just outside the frame. Horror games typically use 60-65 compared to the 80-90 that action games prefer.

  • Press Play and confirm the cursor is locked to the center of the screen (the Starter Assets handle this automatically).
  • Walk through all three rooms. Verify that you can hear the ambient audio, see the isolated light pools with shadows, and interact with all three story objects.
  • Press Escape to unlock your cursor and exit Play mode.
  • Save your scene with Ctrl+S (Windows) or Cmd+S (macOS).

Your scene should feel dark and atmospheric with visible light pools. Walking through the space and interacting with objects should feel like the opening of a horror game.

Cursor not locking in Play mode?

The Starter Assets prefab handles cursor locking automatically. If it is not working, make sure the PlayerCapsule prefab is in your scene and that its scripts are enabled. Click inside the Game view window after pressing Play to ensure Unity has focus.

Help me fix cursor locking in my Unity first-person game.

Secret mission

Add a Scripted Horror Event

Your horror scene has atmosphere, but it is missing a jump scare moment. In this secret mission, you will script a door that slams shut behind the player when they read the letter in the study. This introduces event-driven gameplay and makes the experience genuinely tense.

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally on your machine using Unity Personal (free license) and free assets. There are no ongoing cloud costs or subscriptions to worry about.

Decide whether to keep your resources running, pause them to come back later, or delete them entirely.

Resources you used:

  • The HorrorExploration Unity project folder on your local disk.
  • Unity 6.3 LTS editor installed via Unity Hub.
  • Audio files (ambient loop and door slam clip) imported into Assets/Audio.
  • Starter Assets - FirstPerson | URP claimed on your Unity Asset Store account.

Keep everything running

No action needed. Choose this if you plan to keep building on this horror game or want to revisit the project later.

  • Your HorrorExploration project stays on disk, ready to open in Unity Hub at any time.
  • Unity 6.3 LTS remains installed for future projects.
  • The Starter Assets stay in your Asset Store library for reuse in other projects.

Pause - I'll come back to this later

Close Unity to free up system memory. Your project files stay on disk so you can pick up where you left off.

  • In Unity, save your scene with Ctrl+S (Windows) or Cmd+S (macOS).
  • Close the Unity Editor.
  • When you want to return, open Unity Hub and your HorrorExploration project will appear in the Projects list.

Delete - I don't want to use this again

Remove all project files from your machine. This cannot be undone.

  • Close the Unity Editor if it is open.
  • In Unity Hub, right-click the HorrorExploration project in the Projects list and select Remove project from list.
  • Open File Explorer (Windows) or Finder (macOS) and navigate to the folder where you created the project.
  • Delete the entire HorrorExploration folder.
  • To uninstall Unity 6.3 LTS, open Unity Hub, go to Installs, click the three-dot menu on the Unity 6.3 LTS entry, and select Uninstall. Only do this if you no longer need Unity for other projects.
  • The Starter Assets remain in your Unity Asset Store account at no cost. No action needed to remove them.

Nice Work!

Nice Work!

You just built a playable first-person horror exploration scene from scratch in Unity. A player can now walk through a dark house, discover story fragments about a missing father, and feel genuine tension from the atmosphere you designed.

You've learned how to:

  • Built a multi-room indoor environment using ProBuilder for in-editor level design, applying materials and placeholder furniture to create a low-poly house interior.
  • Wrote C# scripts implementing a raycast-based interaction system with an IInteractable interface, letting players examine story objects that reveal narrative text on screen.
  • Created atmospheric horror lighting using point lights with soft shadows and looping ambient audio to build tension throughout the scene.
  • Secret Mission: Implemented a scripted horror event where a door slams shut behind the player when they read a key item, introducing event-driven gameplay patterns with Quaternion.Lerp animation and triggered audio.

Ready to quiz yourself?