Rustbelt

Software Used: Unity C#, Substance Painter, Blender 2.8
Solo Project

Rustbelt is a thrilling first person horror game where the player’s objective is to infiltrate a sci fi fortress by hacking into a terminal while evading security bots. The end of the game features an epic getaway from the boss's war torn lair.

Dialogue System

The player is guided by a remote communicator through voice and text dialogue. When the player reaches a certain bench mark, the dialogue system activates.

Event Trigger System

Rustbelt utilizes an event trigger system which creates a standardized execution of events in one master controller class. Examples of an event would be activating a security bot or the dialogue system.

This code block is the dialogue manager. It controls when and how messages are displayed in the player's HUD. Demo is shown in the video above.

 1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class DialogueManager : MonoBehaviour
{
    //Simple singelton pattern that allows other classes to reference a single instance of this one. (There will only be one instance of this class).
    #region Singelton
    public static DialogueManager instance;
    private void Awake()
    {
        if (instance != null)
        {
            Debug.LogError("More than one instance detected!!");
            return;
        }
        instance = this;
    }
    #endregion

    
    //Three lists the hold data for message strings, message sounds, and the time required to display each message. 
    //A queue would have been just as effective for this version but in the future extra flexibility may be needed.   
    public List<string> messages;
    public List<AudioClip> messageSounds;
    public List<float> messageTimes;

    //Objects that hold necessary items in the HUD
    public Text nameText;
    public Text messageText;
    public GameObject dialogueBox;
    

    void Start()
    {
        StartCoroutine("dialogue");
    }

    private void Update()
    {
     if (Input.GetKeyDown(KeyCode.R))
        {
            SkipMessage();
        }
    }

    //This method controls when messages are displayed and when to remove messages from the list.
    //When an event trigger with dialogueue is activated, it sends messages to the three lists in this class. 
    //This method then activates and displays those messages properly. 
    IEnumerator dialogue()
    {
        ToggleText(false);

        while (true)
        {
            while (messages.Count != 0)
            {
                ToggleText(true);

                StartCoroutine(Filldialogue(messages[0]));

                GetComponent<AudioSource>().clip = messageSounds[0];

                GetComponent<AudioSource>().Play();

                //Each time a message is finished being displayed, it is removed from the list. 
                messageSounds.RemoveAt(0);
                messages.RemoveAt(0);


                yield return new WaitForSeconds(messageTimes[0]);
                messageTimes.RemoveAt(0);
            }

            ToggleText(false);
            yield return new WaitForSeconds(.5f);
        }

    }


    //This method toggles the visability of the HUD. 
    //Usually, when a message needs to be displayed, the HUD is visible. 
    void ToggleText(bool trueFalse)
    {
        dialogueBox.gameObject.SetActive(trueFalse);
    }

    //This method slowly fills in the HUD message with the latest message in the messages list. 
    //It inserts a character from the message once every two frames
    //until the message is completely displayed. 
    IEnumerator Filldialogue(string text)
    {
        messageText.text = "";
        foreach (char letter in text.ToCharArray())
        {
            messageText.text += letter;

            yield return null;
            yield return null;
        }
    }

    //If a player hits the 'r' hotkey, this method will be called. It clears the messageText buffer
    //and continues onto the next message in the list. 
    public void SkipMessage()
    {
        if (messageSounds.Count > 0)
        {
            //All coroutines are temporarily stopped because we do not want leftovers from the previous message 
            //to be filled into the new message. 
            StopAllCoroutines();

            messageText.text = "";

            //Clearing the current message in the lists. 
            messageSounds.RemoveAt(0);
            messages.RemoveAt(0);
            messageTimes.RemoveAt(0);

            GetComponent<AudioSource>().Stop();

            StartCoroutine("dialogue");
        }
    }
}

This code block is the base class for the event trigger.

 1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EventTrigger : MonoBehaviour
{

    //If checkpoint does not equal zero, this variable will set the checkpoint.
    public int checkPoint = 0;

    //Check point threshold for event trigger.
    public int checkPointNeeded = 0;
    

    //Method name in the Master Controller that the event trigger will call.
    //If "nothing", then no method call will happen. 
    public string methodName = "nothing";

    public bool destroyAfterActivating = true;

    //If any delay after the trigger is activated is desired, these variables exist. 
    public float methodDelay = 0;
    public float speakingDelay = 0;


    public AudioSource anyAudio; 

    //Put in an embedded class to keep organization.
    [System.Serializable]
    public class DialogueStuff{
    [TextArea(2, 2)]
    public string[] messages;
    public AudioClip[] messageSounds;
    public float[] times;
}
    public DialogueStuff dialogue; 


    //This method logic is run when the player enters the bounding box of the trigger.
    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            if (PlayerPrefs.GetInt("CheckPoint") >= checkPointNeeded)
            {
                if (checkPoint != 0 && PlayerPrefs.GetInt("CheckPoint") < checkPoint)
            {
                //If checkpiont variable is not zero, the checkpoint will be set. 
                PlayerPrefs.SetInt("CheckPoint", checkPoint);
                print("Checkpoint is now " + PlayerPrefs.GetInt("CheckPoint"));
            }

                //Activate event trigger.
                StartCoroutine("DoActivation");
            }
        }
    }


    //This method is called if dialogue is contained in the event trigger. It sends dialogue to the dialogue manager.  
    void Senddialogue()
    {
        for (int i = 0; i < dialogue.messages.Length; i++)
        {
            //Adding message(s) to the lists of the dialogue manager.
            DialogueManager.instance.messages.Add(dialogue.messages[i]);
            DialogueManager.instance.messageSounds.Add(dialogue.messageSounds[i]);
            DialogueManager.instance.messageTimes.Add(dialogue.times[i]);
        }
    }


    //This method is called if the event trigger needs to be manually activated by another script. 
    public void Activate()
    {
        if (anyAudio != null)
        {
            anyAudio.Play();
        }
        StartCoroutine("DoActivation");
    }

    //This is the main activation method. It calls the specified method in the Master Controller and sends dialogue if there is any. 
    //It also destroys the object if desired. 
    public IEnumerator DoActivation()
    {
        if (methodName != "nothing")
        {
            //"CallMethod" in MasterController is the same as calling a method in MasterController, 
            //but this specific method calls the desired method with a variable delay. 
            MasterController.instance.CallMethod(methodName, methodDelay);
        }

        yield return new WaitForSeconds(speakingDelay);

        if (dialogue.messages.Length != 0)
        {
            Senddialogue();
        }

        if (destroyAfterActivating)
        {
            Destroy(gameObject);
        }
    }
}