using System.Collections;
using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class CountdownTimer : MonoBehaviour { public float currentTime = 0f; public float startingTime = 100f; public GameObject CanvasSim; public GameObject CanvasXR; public GameObject Audio; [SerializeField] Text countdownText; private void Start() { currentTime = startingTime; } private void Update() { currentTime -= 1 * Time.deltaTime; countdownText.text = currentTime.ToString(); if (CanvasSim.tag == "reset" || CanvasXR.tag=="reset" ) { currentTime = startingTime; CanvasSim.tag = "EndReset"; CanvasXR.tag = "EndReset"; } if (currentTime < 11f) Audio.SetActive(true); if (currentTime < 0f) { CanvasSim.SetActive(false); CanvasXR.SetActive(false); } } } |
Through this script I was able to create the countdown timer. Initializing the starting time to 100 (easily changeable from the inspector since it's a public variable) the script starts by setting currentTime to 100 and every update decreases the float by one times time.DeltaTime which allows the timer to decrease each second. The time is the converted into a string and then displayed on both canvas (UnityXRCameraRig and SimulatedCameraRig).
When the NormalMode button on the settings wall is touched, the canvas' tag is set to "reset" and through this script, when it is set to reset the timer is restarted from the starting Time. Then the tag is set to "endReset" so it doesn't enter the if anymore. When below 11 seconds, the Countdown audio plays so that the it is synchronized with the seconds going down from 10 to 0. When the timer reaches 0, the canvas are set to false so that the timer disappears and the player won't be able to see the timer going to negative values. |
using System.Collections;
using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class CountdownSecond : MonoBehaviour { public float currentTime = 0f; public float startingTime = 20f; public GameObject CanvasSIM; public GameObject CanvasXR; public GameObject Scaler; public GameObject InteractableMaze; public GameObject LowerLight; [SerializeField] Text countdownText; private void Start() { currentTime = startingTime; } private void Update() { currentTime -= 1 * Time.deltaTime; countdownText.text = currentTime.ToString(); if(currentTime < 0f) { Scaler.tag = "FlyDown"; InteractableMaze.tag = "BackOn"; LowerLight.tag = "BackOn"; CanvasSIM.SetActive(false); CanvasXR.SetActive(false); currentTime = startingTime; } } } |
Similarly to the script above, this script represents the countdown from 20 seconds to 0.
What's different is that when it reaches 0, since this script is associated to 3 different functions (flying function, lights off function, and lowering of the lights function), the gameObjects' tags associated to the activation of these three functions are set to either BackOn or FlyDown. The interactable associated to the flying phase to watch the maze from above is set to "FlyDown" which will be used in another script to bring the character back to the ground. The other two interactables are set to "BackOn" which will turn the lights back on after 20 seconds of having touched a wall or turn them to the normal intensity after the second interactable along the maze has been touched (all done in two more scripts). |
using System.Collections;
using System.Collections.Generic; using UnityEngine; public class Fly : MonoBehaviour { public GameObject Scaler; public Vector3 newScale; public Vector3 stopScale; public Vector3 normScale; public GameObject countdownSIM; public GameObject countdownXR; //public float speed = 2.0f; // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { if (Scaler.tag == "fly") { Scaler.transform.localScale += newScale; countdownSIM.SetActive(true); countdownXR.SetActive(true); if (Scaler.transform.localScale == stopScale) Scaler.tag = "EndFly"; } if (Scaler.tag == "FlyDown") { if(Scaler.transform.localScale != normScale) { Scaler.transform.localScale -= newScale; if (Scaler.transform.localScale == normScale) Scaler.tag = "EndFly"; } } } } |
Thanks to this script, when the first interactable along the maze is touched and the tag set to "fly", the local scale is updated of a 1 unit in the y axis until it reaches the publicly set height of 50 (stopScale). It was chosen to do this way to have the appearance of the character smoothly flying instead of being teleported to the correct height. The canvases connected to the 20 seconds countdown are activated and when the correct height is reached the tag is changed to have the character stop flying.
When the 20 seconds get to 0 the tags are set to FlyDown as shown on the script above and thanks to this script the character is similarly from before brought back to its normal scale. |
using System.Collections;
using System.Collections.Generic; using UnityEngine; public class MoveToStart : MonoBehaviour { public GameObject player; public GameObject CanvasSIM; public GameObject CanvasXR; public Vector3 startPos; private void OnCollisionEnter(Collision collision) { player.transform.position = startPos; CanvasSIM.tag = "reset"; CanvasXR.tag = "reset"; } } |
Thanks to this short script, the player (to which a gameObject called Scaler which contains the tracked Alias, the CameraRigs and other important objects) is moved to a certain position when a specific object is collided with. Being this script associated to the NormalMode button and the FreeMode button, both of them move the player to the entrance of the maze when collided with the controllers. Also the Canvases are set to "reset" which enables the timers in the normal mode to start back from the initial Time.
|
public class LightsBackOn : MonoBehaviour
{ public GameObject SpotLight; public GameObject Lightning; public GameObject InteractableMaze; // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { if (InteractableMaze.tag == "ambient") { RenderSettings.ambientLight = Color.black; } if(InteractableMaze.tag == "BackOn") { SpotLight.SetActive(false); Lightning.SetActive(true); RenderSettings.ambientLight = Color.grey; } } } |
This script does two different things. When the walls are touched and their parent tag is set to "ambient" changes the rendering ambient light to black. This was done since setting all the lighting gameobjects to false wasn't enough to have a completely black scene where the only source of light would have been the spotlight that represents the torch connected to the right controller.
The second thing it does is that when the 20 seconds get to 0 and the walls' parent is set back to "BackOn", the torch is set back to inactive, the lighting is turned on again and the rendering light is set back to its initial color, which is grey. |
using System.Collections;
using System.Collections.Generic; using UnityEngine; public class Slender : MonoBehaviour { public GameObject LowerLight; public GameObject Light1; public GameObject Light2; public float LightStep; public GameObject Sword; public GameObject Penny; public GameObject PennyInter; public GameObject Slander; // Start is called before the first frame update void Start() { } void Update() { if (LowerLight.tag == "ambient") { Light1.GetComponent<Light>().intensity -= LightStep * Time.deltaTime; Light2.GetComponent<Light>().intensity -= LightStep * Time.deltaTime; RenderSettings.ambientLight = new Color(0.3f, 0.3f, 0.3f, 1); } if (LowerLight.tag == "BackOn") { Light1.GetComponent<Light>().intensity = 1f; Light2.GetComponent<Light>().intensity = 1f; RenderSettings.ambientLight = Color.grey; Sword.SetActive(false); Penny.SetActive(false); PennyInter.SetActive(false); Slander.SetActive(false); } } } |
Thanks to this script, when the second interactable that can be found along the maze is touched and its tag is set to LowerLight, the light intensity of the main two sourced of light is slowly lowered to 0 starting from 1. At the same time, the render lighting is lowered as well but only to (0.3, 0.3, 0.3) so that the player will still be able to see around even if hardly. This was chosen to be this way since the player will have to fight against two horror characters but has no torch light, so he will still have to see partially them. It also helps bringing the player into a more "horror" setting. Its really important not to touch the walls with the sword, since in that case not only the lights will lower but they will completely turn off.
When the 20 seconds get back to 0 and the tag is set back to "backOn" then the light intensity is turned back to 1 and the rendering light is turned back to grey. Also, the sword disappears, pennyWise and the interactable associated to it disappear and SlanderMan disappears as well. |
using System.Collections.Generic;
using UnityEngine; public class GlowScript : MonoBehaviour { // Start is called before the first frame update public GameObject NoteDoGLight; public GameObject NoteReGLight; public GameObject NoteMiGLight; public GameObject NoteFaGLight; public GameObject NoteLaGLight; public GameObject NoteSiGLight; public GameObject NoteDoG; public GameObject NoteReG; public GameObject NoteMiG; public GameObject NoteFaG; public GameObject NoteLaG; public GameObject NoteSiG; void Start() { } // Update is called once per frame void Update() { if (NoteDoG.tag == "glow") { NoteDoGLight.SetActive(true); } if (NoteReG.tag == "glow") { NoteReGLight.SetActive(true); } if (NoteMiG.tag == "glow") { NoteMiGLight.SetActive(true); } if (NoteFaG.tag == "glow") { NoteFaGLight.SetActive(true); } if (NoteLaG.tag == "glow") { NoteLaGLight.SetActive(true); } if (NoteSiG.tag == "glow") { NoteSiGLight.SetActive(true); } if (NoteDoG.tag == "noGlow") { NoteDoGLight.SetActive(false); } if (NoteReG.tag == "noGlow") { NoteReGLight.SetActive(false); } if (NoteMiG.tag == "noGlow") { NoteMiGLight.SetActive(false); } if (NoteFaG.tag == "noGlow") { NoteFaGLight.SetActive(false); } if (NoteLaG.tag == "noGlow") { NoteLaGLight.SetActive(false); } if (NoteSiG.tag == "noGlow") { NoteSiGLight.SetActive(false); } } } |
This script, after the interactable from the Simon wall is set to "glow" turns its corresponding light source to on. When the tag is set to "noGlow", it turnes the light source back to off. The tag can be changed either when the interactable is touched (see the interactable's inspector) or when the SongSimon script runs to play the code song to unlock the wall.
|
using System.Collections;
using System.Collections.Generic; using UnityEngine; public class SongSimon : MonoBehaviour { // Start is called before the first frame update public AudioSource DoSound; public GameObject DoG; public AudioSource ReSound; public GameObject ReG; public AudioSource MiSound; public GameObject MiG; public AudioSource FaSound; public GameObject FaG; public AudioSource LaSound; public GameObject LaG; public AudioSource SiSound; public GameObject SiG; void Start() { StartCoroutine(waiter()); } // Update is called once per frame void Update() { } IEnumerator waiter() { //do re mi mi la la fa //Wait for 4 seconds yield return new WaitForSeconds(4); DoSound.Play(); DoG.SetActive(true); yield return new WaitForSeconds(1); DoG.SetActive(false); ReSound.Play(); ReG.SetActive(true); yield return new WaitForSeconds(1); ReG.SetActive(false); MiSound.Play(); MiG.SetActive(true); yield return new WaitForSeconds(1); MiG.SetActive(false); LaSound.Play(); LaG.SetActive(true); yield return new WaitForSeconds(1); LaG.SetActive(false); FaSound.Play(); FaG.SetActive(true); yield return new WaitForSeconds(1); FaG.SetActive(false); } } |
Thanks to this script the code song to unlock the wall plays once after having touched the interactable that makes the wall appear. A coroutine is created that allows the song to start after 4 seconds the interactable has been touched. This allows the user to move in front of the wall before the song plays. After that, the notes and the corresponding lights play and turn on every second, which allows the code song to play slow enough for the user to listen clearly and see clearly which interactables on the wall he needs to touch and in which order.
|
using System.Collections;
using System.Collections.Generic; using UnityEngine; public class SongTest : MonoBehaviour { // Start is called before the first frame update public GameObject NoteDoG; public GameObject NoteReG; public GameObject NoteMiG; public GameObject NoteFaG; public GameObject NoteLaG; public GameObject NoteSiG; public GameObject Simon; private int a; private int b; private int c; private int d; private int e; private int f; private int g; private int ok = 0; void Start() { a = 0; b = 0; c = 0; d = 0; e = 0; f = 0; } // Update is called once per frame void Update() { if (NoteDoG.tag == "glow" || a==1) { print("Ciao"); a = 1; print(a); if (NoteReG.tag == "glow" || b == 1) { b = 1; if (NoteMiG.tag == "glow" || c == 1) { c=1; if (NoteMiG.tag == "glow" || d == 1) { d = 1; if (NoteLaG.tag == "glow" || e == 1) { e = 1; if (NoteLaG.tag == "glow" || f == 1) { f=1; if (NoteFaG.tag == "glow" || g == 1) { g =1 ; ok = 1; } else if (NoteDoG.tag == "glow" || NoteReG.tag == "glow" || NoteMiG.tag == "glow" || NoteSiG.tag == "glow") { a = 0; b = 0; c = 0; d = 0; e = 0; f = 0; } } else if (NoteDoG.tag == "glow" || NoteReG.tag == "glow" || NoteFaG.tag == "glow" || NoteMiG.tag == "glow" || NoteSiG.tag == "glow") { a = 0; b = 0; c = 0; d = 0; e = 0; f = 0; } } else if (NoteDoG.tag == "glow" || NoteReG.tag == "glow" || NoteFaG.tag == "glow" || NoteSiG.tag == "glow") { a = 0; b = 0; c = 0; d = 0; e = 0; f = 0; } } else if (NoteDoG.tag == "glow" || NoteReG.tag == "glow" || NoteFaG.tag == "glow" || NoteLaG.tag == "glow" || NoteSiG.tag == "glow") { a = 0; b = 0; c = 0; d = 0; e = 0; f = 0; } } else if (NoteDoG.tag == "glow" || NoteFaG.tag == "glow" || NoteLaG.tag == "glow" || NoteSiG.tag == "glow") { a = 0; b = 0; c = 0; d = 0; e = 0; f = 0; } } else if (NoteMiG.tag == "glow" || NoteFaG.tag == "glow" || NoteLaG.tag == "glow" || NoteSiG.tag == "glow") { a = 0; b = 0; c = 0; d = 0; e = 0; f = 0; } } else if (NoteReG.tag == "glow" || NoteMiG.tag == "glow" || NoteFaG.tag == "glow" || NoteLaG.tag == "glow" || NoteSiG.tag == "glow") { a = 0; b = 0; c = 0; d = 0; e = 0; f = 0; } print("a"); print(a); print("b"); print(b); if (ok == 1) Simon.SetActive(false); } } |
Thanks to this script the interactables that are being touched are registered, and if and only if the interactables are touched in the correct order, the wall will disappear. This is performed through a set of ifs and flags that are raised just when the correct interactable is touched after the previously correct one has been touched. As soon as the user touches the wrong interactable, all the flags are set back to zero which force the user to start from the first correct one.
Basically, the user is able to touch whichever interactable from the Simon wall. When the purple one which is the first from the code song is touched, the first flag (a) is raised to 1. If the second interactable is the yellow one, which is the correct one, a second flag is rased and the user enters the second if, and so on. The touching is checked through the interactables' tags. If the user doesn't touch the wrong interactable and only touches the correct ones in the correct order, he will be able to get to the last if that raises the "ok" flag which when raised will turn the entire Simon wall to inactive, allowing the user to walk through. |