Trailer for Upcoming Steam release of our game.
What Lies Frozen is a psychological horror game with puzzle elements inspired by games like P.T. and Stay Out of the House.
I was this project's lead programmer, making all the different puzzles, triggers, and the player controller.
The programs I used for this project are: Unity, Visual Studio, Trello, Discord, and Word.
Code Snippets
using System.Collections;
using UnityEngine;
using static GlobalVariables;
public class InteractableObject : MonoBehaviour
{
public bool isInteractable = true;
[SerializeField] private Interaction interaction;
public GameObject triggerToActivate;
public ActionSubtitles actionSubtitles;
/// <summary>
/// The type of interactable object.
/// </summary>
public enum InteractableType
{
Key,
Lighter,
LighterFluid,
Door,
KeyPad,
Lightswitch,
TVRemote,
KeyPiece
}
/// <summary>
/// The type of interaction. Mostly used for the button prompt.
/// </summary>
public enum InteractionType
{
Pickup,
Use,
Open,
Close,
TurnOn,
TurnOff
}
public InteractableType type;
public InteractionType interactionType;
public MeshRenderer rend;
private void Start()
{
rend = GetComponent<MeshRenderer>();
interaction = FindObjectOfType<Interaction>();
actionSubtitles = FindObjectOfType<ActionSubtitles>();
}
/// <summary>
/// Interacts with the object. The specific interaction depends on the object's type.
/// </summary>
public void Interact()
{
Debug.Log("Interacting with " + type);
switch (type)
{
case InteractableType.Key:
Key();
break;
case InteractableType.Lighter:
Lighter();
break;
case InteractableType.LighterFluid:
LighterFluid();
break;
case InteractableType.Door:
Door();
break;
case InteractableType.KeyPad:
KeyPad();
break;
case InteractableType.Lightswitch:
Lightswitch();
break;
case InteractableType.TVRemote:
TVRemote();
break;
case InteractableType.KeyPiece:
KeyPiece();
break;
}
if (triggerToActivate != null)
{
triggerToActivate.SetActive(true);
}
}
#region Interactable Methods
/// <summary>
/// Adds the key to the player's inventory.
/// </summary>
public void Key()
{
Key key = GetComponent<Key>();
interaction.inventory.GetKeys().Add(key.keyID);
StartCoroutine(actionSubtitles.ShowSubtitle("Key picked up"));
interaction.inventory.keyGameObject.SetActive(true);
StartCoroutine(DestroyPickup());
}
/// <summary>
/// Adds the lighter to the player's inventory or refills the lighter fluid if the player already has it.
/// </summary>
public void Lighter()
{
if (interaction.lighter.hasLighter == false)
{
interaction.lighter.hasLighter = true;
}
else if (interaction.lighter.hasLighter == true)
{
interaction.lighter.AddLighterFluid(lighterPickupIncrease);
}
StartCoroutine(actionSubtitles.ShowSubtitle("Lighter picked up"));
StartCoroutine(DestroyPickup());
}
/// <summary>
/// Refills the lighter fluid.
/// </summary>
public void LighterFluid()
{
interaction.lighter.AddLighterFluid(lighterFluidPickupIncrease);
StartCoroutine(actionSubtitles.ShowSubtitle("Lighter fluid picked up"));
StartCoroutine(DestroyPickup());
}
/// <summary>
/// Tries to open the door.
/// </summary>
public void Door()
{
Door door = GetComponent<Door>();
if (!door.isOpen)
{
door.TryOpen();
}
else if (door.isOpen)
{
door.Close();
}
}
/// <summary>
/// Opens the keypad UI.
/// </summary>
public void KeyPad()
{
this.isInteractable = false;
interaction.keypadUI.SetActive(true);
interaction.gameManager.ChangeGameState(GameManager.GameState.KeyPad);
interaction.codeLock.currentKeypad = GetComponent<Keypad>();
}
/// <summary>
/// Toggles the lightswitch.
/// </summary>
public void Lightswitch()
{
Lightswitch lightswitch = GetComponent<Lightswitch>();
StartCoroutine(actionSubtitles.ShowSubtitle("Lightswitch flicked"));
lightswitch.ToggleSwitch();
}
/// <summary>
/// Toggles the TV remote.
/// </summary>
public void TVRemote()
{
Debug.Log("TV Remote flicked");
}
void KeyPiece()
{
KeyPiece keyPiece = GetComponent<KeyPiece>();
interaction.inventory.AddKeyPiece(keyPiece);
StartCoroutine(DestroyPickup());
}
#endregion
/// <summary>
/// Destroys the pickup object. Disables the object and the interact text.
/// </summary>
public IEnumerator DestroyPickup()
{
rend.enabled = false;
yield return new WaitForSeconds(actionSubtitles.subtitleDuration);
gameObject.SetActive(false);
//interaction.interactableFinder.interactText.gameObject.SetActive(false);
}
}
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
public class Trigger : MonoBehaviour
{
public bool soundTrigger;
public bool doorTrigger;
public bool lightTrigger;
public Trigger nextTrigger;
public GameObject objectToDestroy;
public GameObject objectToSpawn; // ill probably change this to an animation later
public List<GameObject> objectsToDestroy;
[Header("Sound Trigger Settings")]
public GameObject soundPosition;
public AudioClip sound;
public bool playOnStart = false;
public bool loop = false;
public float spacialBlend = 1;
public float volume = 1;
private AudioSource audioSource;
[Header("Door Trigger Settings")]
public Door door;
[Header("Light Trigger Settings")]
public bool lightOnOff = false; // if true, the lights will turn on, if false, the lights will turn off
public GameObject[] lights;
public GameObject[] lightObjects;
public enum DoorActionType
{
Open,
Close,
Unlock,
Lock,
Crack
}
public DoorActionType actionType;
public void Start()
{
if (soundTrigger && soundPosition == null)
{
Debug.Assert(soundPosition != null, "Sound Position is null");
}
if (soundTrigger)
{
audioSource = soundPosition.AddComponent<AudioSource>();
audioSource.clip = sound;
audioSource.playOnAwake = playOnStart;
audioSource.loop = loop;
audioSource.spatialBlend = spacialBlend;
audioSource.volume = volume;
}
if (lightTrigger)
{
}
if (nextTrigger != null)
{
nextTrigger.gameObject.SetActive(false);
}
}
private void OnTriggerEnter(Collider other)
{
if (other.tag != "Player")
{
return;
}
if (soundTrigger)
{
audioSource.Play();
}
if (doorTrigger)
{
switch (actionType)
{
case DoorActionType.Open:
door.Open();
break;
case DoorActionType.Close:
door.Close();
break;
case DoorActionType.Unlock:
door.UnlockDoor();
break;
case DoorActionType.Lock:
door.Lock();
break;
case DoorActionType.Crack:
door.Crack();
break;
}
}
if (nextTrigger != null)
{
nextTrigger.gameObject.SetActive(true);
}
if (objectToDestroy != null)
{
objectToDestroy.SetActive(false);
}
if (objectToSpawn != null)
{
objectToSpawn.SetActive(true);
}
if (objectsToDestroy.Count > 0)
{
foreach (GameObject obj in objectsToDestroy)
{
obj.SetActive(false);
}
}
Destroy(this);
}
private void TriggerLights()
{
if (lights != null)
{
foreach (GameObject light in lights)
{
light.SetActive(lightOnOff);
}
}
foreach (GameObject lightObject in lightObjects)
{
Renderer renderer = lightObject.GetComponent<Renderer>();
if (renderer != null)
{
Material material = renderer.material;
if (lightOnOff)
{
material.EnableKeyword("_EMISSION");
//material.SetColor("_EmissionColor", new Color(207, 140, 43));
}
else
{
material.DisableKeyword("_EMISSION");
//material.SetColor("_EmissionColor", Color.black);
}
}
// lightObject.GetComponent<Light>().color = new Color(-1f, -1f, -1f); if this is on the light will remove light from the area. could be used for something cool?
}
}
}
#if UNITY_EDITOR
[CustomEditor(typeof(Trigger))]
public class TriggerEditor : Editor
{
public override void OnInspectorGUI()
{
Trigger trigger = (Trigger)target;
EditorGUILayout.PropertyField(serializedObject.FindProperty("soundTrigger"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("doorTrigger"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("lightTrigger"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("objectToSpawn"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("objectToDestroy"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("objectsToDestroy"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("nextTrigger"));
if (trigger.soundTrigger)
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("soundPosition"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("sound"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("playOnStart"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("loop"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("spacialBlend"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("volume"));
}
if (trigger.doorTrigger)
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("door"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("actionType"));
}
if (trigger.lightTrigger)
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("lights"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("lightObjects"));
}
serializedObject.ApplyModifiedProperties();
}
}
#endif