UNITY - Introduction to Unity User Interface Tools
  In the UnityUI Tutorial we saw the basics of using Canvas tools and scripts to update them.


Visual Novel / Dialogue System
0.
1-5.
6.
7.
8.
9.
10.

11.
12.
Summary
Steps to Build a Scene
Main Script
Game Handler
Scene Management
Pause Menu and Audio
Using Stats in Your Game
Adding UI Art / Fonts
Common Errors

12. Effects to Enhance Your Project:
      [A]: Type-On Effect
      [B]: Image Fade In / Fade Out
      [C]: Text Shake
      [D]: Input Name Field
      [F]: Trigger Multiple Audio Files
      [F]: Animated Logo / BG
      [G]: Custom Cursor

      Export your build as WebGL
See past narrative game projects from MassArt and Harvard

How to Design a Visual Novel Short Story

PLANNING YOUR STORY:
A Branching Narrative Game is a chance to flex storytelling muscles and invite players to explore a world of choices. The design of this system turns some choices into places: big decisions are about going somewhere else for a new interaction. Smaller "story" choices affect the flow of the conversation in a Scene, and help the player define their character.

Consider this OUTLINE and FLOW for a short interactive story about a turtle who has just hatched from its shell. The first choice is to decide what to do next. Does it follow a girl turtle DOWN the beach to the one big light, or the boy turtle UP the beach to the many lights, or its own nose to the sweet smell ALONG the beach?

Each of these Scene Change choices leads to places (new Unity Scenes) with choices that can lead to death (and being eaten by vultures), or chances to revisit old choices, and one slim path for victory.

The text of every Scene is meant to be a dialogue, so in addition to the player there should always be at least one other character for conversation and conflict. This crerates opportunity in each Scene for character-driven Story choices: how does your player choose to respond to the other character?
The player is often not visualized in these types of games, so players can project themselves onto the character, but some stories prefer a specific, visualized player character.

While story paths can intersect, be careful to not allow a player to revisit the same Scene and see the same text, or the game will feel broken. A Player Stat can be used to change the text when returning to a place.

Consider other Player Stats you can track to provide alternative outcomes: objects the player collects, characters the player befriended or pissed-off, that could change later inetractions / access).
Also consider motion effects to enhance the experience, like type-on or shaky text, or fade-away images.

PLANNING THE VISUALS:
Type an ART BACKLOG: Once you have outlined your story and flow diagram, type a list of all the images you will need for your Scenes. Consider hand-drawn / painted elements and / or manipulated photography.

Each Scene needs unique content:
At least one background
1280x720, 72ppi




At least 2-5 images to represent each character in the Scene.
1280x720, 72ppi. Transparent negative space,
    Position character centered on the left or on right side.

Create multiple images per character.
   Change poses and faces to support their performance.


Also plan your UI art with a consistent look and feel to go across all Scenes:
Background images for the text fields (suggested: namebox 250x50 and speachbox 800x200).
Images for Buttons in the Frame Scenes and Pause Menu (play, quit, etc, try 250x80).
Also make Splash Art (full page images, 1280x720) for the Main Menu, Win and Lose Scenes.

PRACTICE ZERO-DRAFTING!: Please draft all art as super-quick roughs the first week, so the entire game can be implemented and revised WHILE the more polished art is still being produced!

AUDIO: Background music and ambient sounds can add a lot to a Scene's mood and immersion, if you have someone on your team willing to make them! At the very least, choose one event in your game to emphasize with an audio event, like a creaky door opening.

UNITY TUTORIAL:

UNITY CANVAS: a Canvas is a 2D space to hold UI Game Objects like Text, Images, and Buttons.

In the Scene view the Canvas appears over-large, but in the Game view the Canvas maps over the visible screen and tracks with camera movement. This works best if the Canvas is set to 1280x720 and the Game view is set to display at 16:9.

UI Objects can be static (display a message or image and not change) or be updated by a script.

Buttons can get OnClick() Event Triggers to call (activate) a script on another object.

The Canvas Hierarchy display order is vertical: elements lower in the Hierarchy under Canvas display in the Scene on top of elements that are higher up in the Canvas.

Canvas Text elements display blurry in the Scene view if the physical size of the Game view window is small. Increase the Game view to the full intended size to see them more clearly. If they still look blurry, increase the text object Rect and Font size to at least 30, and then scale down to intended size in Canvas.


 
0. UNITY VISUAL NOVEL: SUMMARY OF DIALOGUE SYSTEM:
(Source video: terrible recording, but good basics)

In this Branching Narrative Unity project, each story Scene gets a UI > Canvas object containing Image, Text, and Button elements.

Each Scene gets one long C# script, named for the scene, including:
Actions (player hits "Next" or Spacebar to follow a part of the story)
Interactions (player chooses between option buttons to direct the story).

This script is applied to the Canvas object, and then its script slots are populated in the Inspector with the Image, Text, and Button elements in the Canvas, to control when they appear on screen.

These scripts use one critical variable to progress the story: "primeInt".
This integer drives the forward movement of the story by incrementing every time the Next() function is called through the "Next" button.

primeInt is the index of the entire story scene.
Each Story Unit (a character name and what they say) is assigned a primeInt value to find it ("if primeInt == [this number], play this story unit").

A Story Unit can end with a primeInt value, to send the reader to any next story unit:
The Next() function automatically adds 1 to primInt, so hitting "Next" goes to the next integer: 2, 3, 4, etc. This is good when a designer wants a sequence of "Next" buttons to just passively follow a conversation.
When a designer wants to manage multiple choices, each choice might lead to a primeInt number many integers away by assigning the previous value below it (so, set primeInt = 39 to make the Next button go to 40).

Each story unit is a series of on-off switches for each Canvas element in the scene. Want to switch which character Image is visible?
Just turn one off: ArtChar1.SetActive(false);
and turn the other one on: ArtChar2.SetActive(true);

a scripted-scene can be as long or as short as you want, but should feel substantial, with at least 10 lines of dialogue and at least one dialogue choice before the next Scene choice.

Because this is made in Unity, each unit can include animation, particles or other VFX, ambient audio, or any other enhancement. AND, best of all, you can always include a link that goes to a new Unity Scene with entirely other interaction as an interlude from the story (3D or 2D exploration, combat, a puzzle, etc), before returning back to the Visual Novel format.











DIALOGUE SYSTEM STEPS (AND A SHORT EXAMPLE)
 
01. PREPARATION:

a. START by creating a 2D Unity project
(NOTE: This work CAN be done in a 3D Unity project, but this creates more work: the Sprite Editor package must be added, every Scene must be set to 2D, and every image must be set to Sprite. If the project is 2D by default, all of this is automatic).

b. In Game view, change framing from "Free Aspect" to 16:9.

c. Import your character and background art PNGs:
RightClick the Project panel Assets folder, select Import New Asset, and choose your PNGs.
In the Inspector make sure the texture type for each is Sprite (2D and UI).
These images should all be 1280x720, and characters should have transparent backgrounds.

d. Make a File > New Scene.
File > Save As
to name it "Scene1", save into Assets > Scenes folder.
(set number per Scene, and use letters for sibling scenes in your flow diagram: Scene 1, Scene 2a, Scene 2b, Scene3a, Scene 3b, etc).

NOTE: Does your Unity automatically add ".unity" to the end of new scene names? In the Project panel, open a different scene, then rename the Scene you created to remove ".unity".


NOTE #1: Working with a team? Coordinate who is creating which Scene and what they are named, to be sure each is unique.

Pushing two same-named scenes to GitHub will result in one person losing their work.


 
02. CANVAS:

a. In Scene View: Create a CANVES: GameObject > UI > Canvas.

b. In the Inspector:
Set Canvas Scaler > UI Scale Mode = "Scale with Screen Size".
Set Reference Resolution to 1280x720.


 
03. IMAGES (Backgrounds and Characters):

a. RightClick the Canvas to add a UI > Image.
In the Inspector name it "ImageBG".
Set PosX and PosY = 0, and width / height = 1280 x 720.
In Image > Source Image hit the hotspot (target icon, far right) to select the background art sprite for the Scene (or drag it from the Project panel into that slot).

b. In the Hierarchy select ImageBG and hit [Ctrl/Cmd]+[d] to duplicate.
In the Inspector change the name to "ImageChar1".
Click the Source Image hotspot to set this image to the character.

c. Set Canvas Order:
Objects in the Canvas are displayed more in the front if they are lower in the Hierarchy.
Put ArtBG at the top of the Canvas (so it is furthest back), then ArtChar below it.

The following interface elements (DialogueDisplay and Buttons) go even lower in the Canvas, so they appear in front in the Scene.







 
04. DIALOGE DISPLAY:

a. RightClick the Canvas to add a UI > Image.
    In the Inspector Name it "DIALOGUE_DISPLAY".
    Set PosX and PosY = 0, and width / height = 1280 x 720.
    Find the color rectangle to set the alpha = 0 for full transparency.


b. Add 2 IMAGES (as children of DIALOGUE DISPLAY):
    RightClick DIALOGUE_DISPLAY, UI > Image.
    In the Inspector name them "CharName" and "CharSpeech".

CharSpeech
Inspector:

    Set Size: Width / Height = 850 x 250.
    Click color block to choose a low-saturation hue. Set alpha = 150.
    Source Image: hit hotspot, choose "Background" (or custom PNG).
Scene View:
    Position: hit [w] to move the image in the Scene view into the lower-left corner of the Canvas, but leave a small buffer on the sides.
Optionally, position anchors (clear triangles) at corners.

CharName
Inspector:

    Set size: Width / Height = 300 x 80.
    Click color block to choose a low-saturation hue. Set alpha = 150.
    Source Image: hit hotspot, choose "Background" (or custom PNG).
Scene View:
    Position: hit [w] to move the image in the Scene view directly above the upper-left corner of the CharSpeech image (leave a small buffer between them). Optionally, position anchors (clear triangles) at corners.


c. Make Name TEXT objects:
RightClick CharName in the Hierarchy to add a UI > Legacy > Text
(it should be a child of ImageName).
Inspector:
    Name it TextChar1Name.
    Set Rect Width / Height = 280 x 60.
    Set Font Size = 40, Font Style = Bold
    In the Text Field type "Character 1"

Duplicate the text: select it and hit [Ctrl / Cmd] + [d]
Inspector:
    Name it TextChar2Name.
    Change the Color: Choose a distinct, dark hue.
    In the Text Field type "Character 2"


d. Make Speech TEXT objects:
Select both Name text objects, duplicate them [Ctrl / Cmd] + [d].
Drag the duplicates onto ImageSpeech to make them children.
Inspector:
    Name them textChar1Speech and textChar2Speech.
    In Text field type "Character 1 Speech" and "Character 2 Speech".
Scene View:
    Hit [w], move them down to the upper-left corner of ImageSpeech.
    Use Rect tool to drag the lower-right corner of both text fields almost to the lower-right corner of ImageSpeech, so text can fill that space, around 830 x 230.


e. Make the DIALOGUE DISPLAY into a PREFAB:
This Dialogue Display will be used in all of your Story Scenes.
Character1 should always be the player, should have a consistant color, and could have a custom font. The art behind the name and speech blocks could be customized to match the style of your game art.

The efficient way to make future changes is to only have to do them once, and have those changes appear in all of your scenes!
We do this by making the DIALOGUE_DISPLAY into a Prefab.

Project panel > Assets Folder:
    Create a Prefab folder if you do not already have one:
RightClick in the Assets folder to Create a new Folder. Name it "Prefabs".

Hierarchy:
    Make sure all images and texts meant to be parented under DIALOGUE_DISPLAY (as explained in this section) are parented there.
    Select DIALOGUE DISPLAY.
    Drag DIALOGUE DISPLAY into the Project panel > Assets > Prefabs folder. The new Prefab shows up blue in both places, to indicate a Prefab.

NOW, any changes meant to effect all Scenes can be made in the Prefab:
    Select the Prefab in the Prefabs folder.
    DoubleClick this Prefab to "open" it in the Scene view.
    Make changes there to change all Scenes, like adding a particular font to a text object.
    Hit the little triangle in the UpperLeft corner of the Hierarchy to return to normal Scene view.

Any changes intended to be specific to a scene (like adding more characters) can just be made in those Scenes.






















05. BUTTONS:
NOTE: Buttons always go last / at the bottom of the Canvas,
to be sure they are not blocked by any other elements.

a. NEXT BUTTON:
RightClick the Canvas to add a UI > Legacy > Button.
Inspector Button Settings:
    Name it "ButtonNext".
    Set Width / Height = 200 x 100
    Under "Button" set the first three color options as desired:
Normal, Highlighted, and Pressed (this should eventually be consistent across all buttons in all Scenes).
    Set Navigation from "Automatic" to "None".
    Select the Button. At the Inspector bottom find the "OnClick" section.
    Hit [+] to ad an OnClick event.

Inspector Text Settings:
In the Hierarchy click the triangle to the left of the Button to select the child Text object.
    Set Font Size = 40, Font Style = bold.
    Change Text field to "NEXT".

Make a Prefab:
Drag ButtonNext from the Hierarchy into the Project > Assets > "Prefabs" folder.
Now, when you want to make changes to this button, like custom image art a text font, this can be done in the Project panel Prefab and it will populate to all Scenes.


b. CHANGE BUTTONS:
RightClick the Canvas to add a UI > Legacy > Button.
Inspector Button Settings:
    Name it "ButtonChange".
    Set Width / Height = 400 x 90
    Under "Button" set the first three color options as desired:
Normal, Highlighted, and Pressed (this should eventually be consistent across all buttons in all Scenes).
    Set Navigation from "Automatic" to "None".
    Select the Button. At the Inspector bottom fin the "OnClick" section.
    Hit [+] to add an OnClick event.

Inspector Text Settings:
In the Hierarchy click the triangle to the left of the Button to select the child Text object.
    Set Font Size = 40, Font Style = bold.
    Change Text field to "Choice Text" (this will be set differently for each Choice Button in each scene, depending on the choices).

Make a Prefab:
Drag ButtonChange from the Hierarchy into the Project > Assets > "Prefabs" folder.
Now, when you want to make changes to this button (font, colors, image), don't change it in the Scene. Instead, open the Prefab in the Project panel. Changes made to the source Prefab appear in all Scenes!

In the Hierarchy, duplicate ButtonChange to create a total of 4 ButtonChange BUTTONS:
[Ctrl/Cmd] +[d].
    In the Hierarchy, position them lower than DialogueDisplay under the Canvas,
so they appear in front (this is critical for the buttons to function).

NOTE: This is the minimum number of buttons for most scenes, including a Next button, two buttons for a single Story Choice, and two buttons for Scene Changes at the end of the Scene.
If your Scene has more story choices or Scenes to go to, more buttons are needed.


c. Per the chart below:
    In the Inspector set the buttons Names and Sizes (colors should be consistent).
    In the Scene view hit [w] to set the Scene location of each Button.


d. A Text object is available under each Button.
    In the Hierarchy click the Button's triangle to see and select the Text.
    In the Inspector set Font Size = 40 and change the Text contents to describe player actions:
      (These examples are for the provided script. Change them to fit your story!)

BUTTON NAME SIZE TEXT CONTENT LOCATION FUNCTION
ButtonNext 200 x 100 "NEXT" bottom-right Next()
ButtonChoice1a 400 x 90 "NO!" bottom-center-left Choice1aFunct()
ButtonChoice1b 400 x 90 "YES..." bottom-center-right Choice1bFunct()
ButtonSceneChange1 400 x 90 "Run to warn Ragu" middle SceneChange1()
ButtonSceneChange2 400 x 90 "Lead Jeda to Ragu" middle SceneChange2()


 
06. ADD THE SCRIPT:

a. In the Project panel Asset folder, RightClick to Create > C# script.
Name it "Scene1Dialogue", hit [Enter], and then DoubleClick to open in your script editor.

b. Replace all content with the provided script (below). Save.
NOTE: All scene elements get listed in every "primeItem" unit.
Character Text that we don't want visible is set to empty "".
Images we don't want visible are set SetActive(false).
Naturally, you will replace all the Story Units (pimeInt==2, etc) with your own dialogue, and add more Story Units as your script requires.

c. In Unity drag-and-drop this script from the Project Assets folder to the Hierarchy onto the Canvas object.

d. Select each Button to add OnClick functionality:
    In the Inspector find the OnClick field, hit [+] to add an "event".
    Drag the Canvas object into the "None" slot and set the Function:
            ButtonNext = Scene1Dialogue > Next()
            ButtonChoice1a = Scene1Dialogue > Choice1aFunct()
            ButtonChoice1b = Scene1Dialogue > Choice1bFunct()
            ButtonSceneChange1 = Scene1Dialogue > SceneChange1()
            ButtonSceneChange2 = Scene1Dialogue > SceneChange2()
(if your scene has more story choices or Scenes to go to, more buttons are needed)

e. Select the Canvas Object, and into each DialogueScene1 script slot drag the corresponding Image, Text, or Button!

Hit [Play] to test!




SCRIPT NOTES:
Each Scene in your Visual Novel will have its own DialogueScene script, numbered for the Scene number:
  Scene1Dialogue.cs
  Scene2aDialogue.cs
  Scene2bDialogue.cs
  etc.

Be sure to change the Class name in the script to match, or the wscript will not function in Unity.


Usually, each interactive GameObject in Unity gets its own script; having one big script run the majority of the game like this is unusual for a Unity project.




Scene_1_Dialogue.cs:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using UnityEngine.Audio;

public class
Scene_1_Dialogue : MonoBehaviour {
        // These are the script variables.
        // For more character images or buttons, duplicate the ArtChar ones listed here and renumber.
        public int primeInt = 1;         // This integer drives game progress!
        public Text Char1name;
        public Text Char1speech;
        public Text Char2name;
        public Text Char2speech;
       //public Text Char3name;
       //public Text Char3speech;
        public GameObject DialogueDisplay;
        public GameObject ArtChar1a;
       //public GameObject ArtChar1b;
       //public GameObject ArtChar2;
        public GameObject ArtBG1;
        public GameObject Choice1a;
        public GameObject Choice1b;
        public GameObject NextScene1Button;
        public GameObject NextScene2Button;
        public GameObject nextButton;
       //public AudioSource audioSource1;
        private bool allowSpace = true;

// Initial visibility settings. Any new images or buttons need to also be SetActive(false);
void Start(){  
        DialogueDisplay.SetActive(false);
        ArtChar1a.SetActive(false);
        ArtBG1.SetActive(true);
        Choice1a.SetActive(false);
        Choice1b.SetActive(false);
        NextScene1Button.SetActive(false);
        NextScene2Button.SetActive(false);
        nextButton.SetActive(true);
   }

// Use the spacebar as a faster "Next" button:
void Update(){        
        if (allowSpace == true){
                if (Input.GetKeyDown("space")){
                       Next();
                }
        }
   }

//Story Units! The main story function. Players hit [NEXT] to progress to the next primeInt:
public void Next(){
        primeInt = primeInt + 1;
        if (primeInt == 1){
                // audioSource1.Play();
        }
        else if (primeInt == 2){
                ArtChar1a.SetActive(true);
                DialogueDisplay.SetActive(true);
                Char1name.text = "";
                Char1speech.text = "";
                Char2name.text = "Jeda";
                Char2speech.text = "Wakey wakey, human.";
        }
       else if (primeInt ==3){
                Char1name.text = "YOU";
                Char1speech.text = "Wuh..? What happened?";
                Char2name.text = "";
                Char2speech.text = "";
                //gameHandler.AddPlayerStat(1);
        }
       else if (primeInt == 4){
                Char1name.text = "";
                Char1speech.text = "";
                Char2name.text = "Jeda";
                Char2speech.text = "I know I did not hit you that hard.";
        }
       else if (primeInt == 5){
                Char1name.text = "YOU";
                Char1speech.text = "Hit me? Why?";
                Char2name.text = "";
                Char2speech.text = "";
        }
       else if (primeInt == 6){
                Char1name.text = "";
                Char1speech.text = "";
                Char2name.text = "Jeda";
                Char2speech.text = "I am searching for a fugitive. Ragu Fahn.";
        }
       else if (primeInt ==7){
                Char1name.text = "YOU";
                Char1speech.text = "Why do you think I know anything?";
                Char2name.text = "";
                Char2speech.text = "";
        }
       else if (primeInt == 8){
                Char1name.text = "";
                Char1speech.text = "";
                Char2name.text = "Jeda";
                Char2speech.text = "Do not play the stupid. You will take me to him.";
                // Turn off the "Next" button, turn on "Choice" buttons
                nextButton.SetActive(false);
                allowSpace = false;
                Choice1a.SetActive(true); // function Choice1aFunct()
                Choice1b.SetActive(true); // function Choice1bFunct()
        }

       // after choice 1a
       else if (primeInt == 20){
                //gameHandler.AddPlayerStat(1);
                Char1name.text = "";
                Char1speech.text = "";
                Char2name.text = "Jeda";
                Char2speech.text = "Then you are no use to me, and must be silenced.";
        }
       else if (primeInt == 21){
                Char1name.text = "";
                Char1speech.text = "";
                Char2name.text = "Jeda";
                Char2speech.text = "Come back here! Do not think you can hide from me!";
                // Turn off the "Next" button, turn on "Scene" button/s
                nextButton.SetActive(false);
                allowSpace = false;
                NextScene1Button.SetActive(true);
        }

       // after choice 1b
       else if (primeInt == 30){
                Char1name.text = "";
                Char1speech.text = "";
                Char2name.text = "Jeda";
                Char2speech.text = "Do not think you can fool me, human. Where will we find him?";
        }
       else if (primeInt == 31){
                Char1name.text = "YOU";
                Char1speech.text = "Ragu hangs out in a rough part of town. I'll take you now.";
                Char2name.text = "";
                Char2speech.text = "";
                // Turn off the "Next" button, turn on "Scene" button/s
                nextButton.SetActive(false);
                allowSpace = false;
                NextScene2Button.SetActive(true);
        }

      //Please do NOT delete this final bracket that ends the Next() function:
     }

// FUNCTIONS FOR BUTTONS TO ACCESS (Choice #1 and SceneChanges)
        public void Choice1aFunct(){
                Char1name.text = "YOU";
                Char1speech.text = "I don't know what you're talking about!";
                Char2name.text = "";
                Char2speech.text = "";
                primeInt = 19;
                Choice1a.SetActive(false);
                Choice1b.SetActive(false);
                nextButton.SetActive(true);
                allowSpace = true;
        }
        public void Choice1bFunct(){
                Char1name.text = "YOU";
                Char1speech.text = "Sure, anything you want... just lay off the club.";
                Char2name.text = "";
                Char2speech.text = "";
                primeInt = 29;
                Choice1a.SetActive(false);
                Choice1b.SetActive(false);
                nextButton.SetActive(true);
                allowSpace = true;
        }

        public void SceneChange1(){
               SceneManager.LoadScene("Scene2a");
        }
        public void SceneChange2(){
                SceneManager.LoadScene("Scene2b");
        }
}


SCRIPT REVISION NOTES: As you make this script your own and change it for each of your Scenes in Unity, you will want to add more character art, choice buttons, and possibly more speakers.
To do this, you will need to:

(1). In the Scene_#_Dialogue script, add GameObject variables for each new element (duspliacet existing examples of character art, buttons, and text, and change the numbers in their names).

(2). In the Start() function, make sure to add any new images or buttons to the list of .SetActive(false); .

(3). In the body of Next(), pay attention to when you want these images to be .SetActive(true) or false. All text objects for name and speach must be included in primeInt == 2 to set them to a silent "".
In general, it is good practice to include all text name and speach objects in every primeInt Story Unit, so if you have 5 speakers in a scene, you would include them all (usually as "") in every primeInt.

(4). In the Scene Hierarchy, add the images, choice buttons, and text objects for name and speach to the Scene Hierarchy (duplicate existing ones, rename them, be sure to change the text color for each new character, and to set button text and OnClick functionality). Drag the new elements into the new Canvas script slots

 
07. GAME HANDLER:
a. Create an Empty GameObject, name it "GameHandler". Import and add the below script to it.

b. Drag GameHandler into the Project panel Assets folder to make it a Prefab, and add it to every Scene (to provide an Escape-Quit) and to end-scenes (functions for the Restart and Quit buttons).


GameHandler.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class
GameHandler : MonoBehaviour{

        public static int playerStat1;
        // public GameObject textGameObject;

        // void Start () { UpdateScore (); }

        void Update(){         //delete this quit functionality when a Pause Menu is added!
                if (Input.GetKey("escape")){
                        Application.Quit();
                }

                // Stat tester:
                //if (Input.GetKey("p")){
                //       Debug.Log("Player Stat = " + playerStat1);
                //}

        }

        // void UpdateScore () {
        //        Text scoreTemp = textGameObject.GetComponent<Text>();
        //        scoreTemp.text = "Score: " + score; }

        public void StartGame(){
                SceneManager.LoadScene("Scene1");
        }

        public void OpenCredits(){
                SceneManager.LoadScene("Credits");
        }

        public void RestartGame(){
                SceneManager.LoadScene("MainMenu");
        }

        public void QuitGame(){
                #if UNITY_EDITOR
                UnityEditor.EditorApplication.isPlaying = false;
                #else
                Application.Quit();
                #endif
        }
}


 
08. SCENE MANAGEMENT
Create the remaining story scenes and all 4 framing scenes for your game:
a) Other Story Scenes   |   b) Main Menu   |   c) Win and Lose  |   d) Credits   |   e) Unity Build Settings

 
a). CREATE OTHER STORY SCENES:
Duplicate your Dialogue Scene to create other needed story Scenes: File > Save As and choose the new names (for this 3-scene example I used "Scene2a" and "Scene2b").

Replace the Background and Character images for each new Scene. Some Scenes may need more character Images, character Text objects, or choice Buttons.

Replace the DialogueScript on the Canvas in each.
Here are the scripts for this example project: Scene2aDialogue.cs and Scene2bDialogue.cs.
Be sure to populate all script slots and Button names / onclick functions (see commented notes at top of scripts).

Replace the text for each choice Button, to indicate the action in the script .





NOTE #4: To duplicate a Scene or rename a Scene, open the Scene and use File > Save As. Do not directly rename a Scene in the Project panel, as it may delete the content of that Scene.




 
b)
Create a MAIN MENU:
1. Make a File > New Scene.
    File > Save As to name it "MainMenu".
    (save into Assets > Scenes folder).

2. Add a GameObject > UI > Canvas.
Inspector:
    Set UI Scale Mode = "Scale With Screen Size".
    Set Reference Resolution width / height = 1280 x 720.

3. Add BACKGROUND art:
RightClick the Canvas, add UI > Image.
Inspector:
    Set width / height to 1280 x 720.
    Under Image set Source Image to the desired splash art (which should be a PNG, 1280x720).

4. Add TITLE text:
RightClick the Canvas to add an UI > Legacy > Text.
In Scene view hit [w] for Move tool. Drag up near top.
Inspector:
    Name it TextTitle.
    Set Rect width / height = 800 x 150.
    Set Font Size = 80, Font Style = bold.
    Set Alignment = center (mid choices in groups of 3).
    Set text field to say your game title, all-caps.
NOTE: Replace this text with Game Logo Art when ready!

5. Add EXPLANATION text:
RightClick Canvas to add another UI > Legacy > Text.
In Scene view hit [w], drag below TextTitle.
Inspector:
    Name it TextExplain.
    Set Rect width / height = 600 x 150.
    Set Font Size = 40, Font Style = bold.
    Set Alignment = center (mid choices in groups of 3).
    Set text field to 1-2 sentences to an introductory sentence: pitch the game!

6. Add GAMEHANDLER Prefab:
    Drag the GameHandler Prefab from the Project panel into your Scene Hierarchy.

7. Add PLAY Button:
RightClick the Canvas to add a UI > Legacy > Button.
Set Inspector Button Settings:
    Name it "Button_Play".
    Set Width / Height = 300 x 80
    Under "Button" set the first three color options as desired: Normal, Highlighted, and Pressed (this should eventually be consistent across all buttons in all Scenes).        Set Navigation from "Automatic" to "None".

Inspector Text Settings:
In the Hierarchy click the triangle to the left of the Button to open it and select the child Text object.
    Set Font Size = 40, Font Style = bold.
    Change Text field to "PLAY".

8. Duplicate for a CREDITS Button:
Select the button, hit [Ctrl/Cmd] + [d].
Make two changes in the Inspector:
    Change Button name to "Button_Credits".
    Change Text field to "CREDITS".
In the Scene view hit [w] to move the new button down, to see both buttons.

9. Duplicate for a QUIT Button:
Select the button, hit [Ctrl/Cmd] + [d].
Make two changes in Inspector:
    Change Button name to "Button_Quit".
    Change Text field to "QUIT".
In the Scene view hit [w] to move the new button down, to see all three buttons.

10. Add Onclick events to each button:
Select all buttons (hold [Shift] to add to selection).
Set OnClick function in the Inspector:
    Towards Inspector bottom find "OnClick" and hit [+] to add an event.
    Drag the GameHandler object from the Hierarchy into the "None" slot (Please do NOT use the GameHandler Prefab from the Project panel-- only the one from the current Scene Hierarchy!).
    Select one button at a time, set Functon for each:
            GameHandler > StartGame()
            GameHandler > OpenCredits()
            GameHandler > QuitGame()






 
c) Create at least 2 END SCENES:
"SceneWin" and "SceneLose".

1. Make a File > New Scene.
    File > Save As to name it "End_Win" or "End_Lose".
    (save into Assets > Scenes folder).

2. Add a GameObject > UI > Canvas.
Inspector:
    Set UI Scale Mode = "Scale With Screen Size".
    Set Reference Resolution to 1280 x 720.

3. RightClick the Canvas to add an UI > Image.
Inspector:
    Set width / height to 1280x720.
    Under Image set Source Image to the desired splash art (which should be a PNG, 1280x720).

4. RightClick the Canvas to add an UI > Legacy > Text.
In Scene view hit [w] for Move tool. Drag up near top.
Inspector:
    Name it TextTitle.
    Set Rect width / height = 800 x 150.
    Set Font Size = 80, Font Style = bold.
    Alignment = center (mid choice in each group of 3).
    Set text field to say "YOU WIN!!" or "YOU LOSE".

5. RightClick Canvas to add another UI > Legacy > Text.
In Scene view hit [w], drag below TextTitle.
Inspector:
    Name it TextExplain.
    Set Rect width / height = 600 x 150.
    Set Font Size = 40, Font Style = bold.
    Alignment = center (mid choice in each group of 3).
    Text field: 1-2 sentences to explain the player's fate.

6. Drag the GameHandler Prefab from the Project panel into your Scene Hierarchy.

7. RightClick the Canvas to add UI > Legacy > Button.
Inspector Button Settings:
    Name it "Button_Restart".
    Set Width / Height = 300 x 80
    Under "Button" set the first three color options as desired: Normal, Highlighted, and Pressed (this should eventually be consistent across all buttons in all Scenes).        Set Navigation from "Automatic" to "None".

Inspector Text Settings:
In the Hierarchy click the triangle to the left of the Buttons to select the child Text object.
    Set Font Size = 40, Font Style = bold.
    Change Text field to "MAIN MENU".

8. Duplicate the Button:
Select the button, hit [Ctrl/Cmd] + [d].
Make two changes in Inspector:
    Change Button name to "Button_Quit".
    Change Text field to "QUIT".

9. Add Onclick events to each button:
Select all buttons (hold [Shift] to add to selection).
Inspector:
    Towards Inspector bottom find "OnClick" and hit [+] to add an event.
    Drag the GameHandler object from the Hierarchy into the "None" slot (Please do NOT use the GameHandler Prefab from the Project panel-- only the one from the Hierarchy!).
    Select just one button at a time, set the Functons to GameHandler > RestartGame() and QuitGame().




 
b)
Create a CREDITS Scene:

1. Make a File > New Scene.
    File > Save As to name it "Credits"
    (save into Assets > Scenes folder).

2. Add a GameObject > UI > Canvas.
Inspector:
    Set UI Scale Mode = "Scale With Screen Size".
    Set Reference Resolution width / height = 1280 x 720.

3. Add BACKGROUND art:
RightClick Canvas, add UI > Image.
Inspector:
    Set width / height to 1280 x 720.
    Under Image set Source Image to the desired splash art (which should be a PNG, 1280x720).

4. Add TITLE text:
RightClick the Canvas to add an UI > Legacy > Text.
In Scene view hit [w] for Move tool. Drag up near top.
Inspector:
    Name it TextTitle.
    Set Rect width / height = 800 x 150.
    Set Font Size = 80, Font Style = bold.
    Set Alignment = center (mid choices in groups of 3).
    Set text field to "CREDITS".

5. Add NAMES text:
RightClick Canvas to add another UI > Legacy > Text.
In Scene view hit [w], drag below TextTitle.
Inspector:
    Name it TextExplain.
    Set Rect width / height = 600 x 500.
    Set Font Size = 40, Font Style = bold.
    Set Alignment = center (mid choices in groups of 3).
    Set text field to list the names of the creators.

6. Add GAMEHANDLER Prefab:
    Drag the GameHandler Prefab from the Project panel into your Scene Hierarchy.

7. RightClick the Canvas to add UI > Legacy > Button.
Inspector Button Settings:
    Name it "Button_MainMenu".
    Set Width / Height = 300 x 80
    Under "Button" set the first three color options as desired: Normal, Highlighted, and Pressed (this should eventually be consistent across all buttons in all Scenes).        Set Navigation from "Automatic" to "None".

Inspector Text Settings:
In the Hierarchy click the triangle to the left of the Buttons to select the child Text object.
    Set Font Size = 40, Font Style = bold.
    Change Text field to "MAIN MENU".


8. Add Onclick event to the button:
Select the button.
Inspector:
    Towards Inspector bottom find "OnClick" and hit [+] to add an event.
    Drag the GameHandler object from the Hierarchy into the "None" slot (Please do NOT use the GameHandler Prefab from the Project panel-- only the one from the Hierarchy!).
    Set the Functon to GameHandler > RestartGame().







 d. POPULATE BUILD SETTINGS:
Scene switching only works for Scenes added to the Build Settings!

a. Open File > Build Settings to add all of your Scenes.

b. Drag MainMenu to the top so it is the first Scene to Play in an actual build.

c. Hit [Player Settings] and under Resolution and Presentation set FullscreenMode to "Windowed" (1280x720) and turn on "Resizeable Window".

d. Optionally, you can also replace the default cursor in [Player Settings] with a custom image: 32x32, set import settings = Cursor.

WEBGL NOTE: To eventually publish the game on itch.io, you will need to set the project to WebGL and turn off compression. If you select that option from the target platform list you can install it (10-20 min) and switch to that platform (10-20 min). See more at this link, on the left.





 
09. PAUSE MENU:
Add the following PauseMenu to the Canvas in each Scene.

Create it once and drag it into the Project panel to make it a Prefab, to easily add to the other Scenes and update as needed.

Use the GameHandler script for all PauseMenu methods.

Delete the [ESC]-Quit option from Update so the Pause Menu toggles on / off when hitting [ESC].




PAUSE MENU STEPS:
IMPORTANT PREFAB NOTES:

Use SCENE objects for SCRIPT SLOTS!


When dragging the PauseMenu into the pauseMenuUI script slot, be sure to drag in the PauseMenu from inside the Scene, NOT the Prefab from the Project panel.


Similarly, when dragging the GameHandler into the PauseMenu button OnClick and Slider functions, be sure to drag in the GameHandler from inside the Scene, NOT the Prefab from the Project panel.
1. Create the parent Image object:
    a. Select your Canvas, RightClick to create a UI > Image.
    b. In Inspector name it "PAUSEMENU".
        Check that PosX and PosY = 0, set size 1280 x 720.
    c. Click the color rectangle to set alpha=0 (to make it invisible).

2. Create the Background Image object:
    a. In Hierarchy RightClick PAUSEMENU to create a UI > Image.
        The Image should now be a child of PAUSEMENU and centered.
    b. In Inspector name it "ImageBG".
        Check that PosX and PosY = 0, set size 550 x 680.
    c. Click the color rectangle to set a dark color and alpha=150
        (to make it semi-transparent)

    Want to add custom splash art?
        Import a PNG image to your project (600x700). In the Inspector make sure type = Sprite 2D
        In the Inspector with ImageBG selected, drag the PNG into the Source Image slot.

3. Create two Text labels: PAUSED and VOLUME:
    a. In the Hierarchy RightClick your PAUSEMENU to create a UI > Legacy > Text.
        The Text should now be a child of the PAUSEMENU and centered.
    b. In Inspector rename it "textPaused". Set PosX = 0, Y=200, and size width and height = 500 x 80.
    c. Set Text field to "PAUSED", set font bold and size = 60, align centered. Set color as desired.
    d. Select textPaused in the Hierarchy and duplicate ([Ctrl/Cmd] + [D]) to make a second Text label.
        Name the second label "textVolume" and Set text to "VOLUME". Drag down closer to middle.

4. Add 1st Button: Resume:
    a. RightClick your PAUSEMENU to create a UI > Legacy > Button.
        The Button should now be a child of the PAUSEMENU and centered.
    b. In Inspector rename it "ButtonResume". Set PosX = 0 and size = 300 x 80.
    c. Set Button text to "RESUME", set font bold and size = 40. Set color as desired.
    d. Set Button colors: Normal Color, Highlighted Color, Pressed Color. Optionally, add a custom PNG.
NOTE: All buttons should be located below the text objects so they are not blocked.

5. Duplicate for 2nd and 3rd buttons: Restart and Quit:
    a. Select ButtonResume in the Hierarchy and duplicate ([Ctrl/Cmd] + [D]) to make a second button.
        Name the second button "ButtonRestart" and Set text to "RESTART".
   b. Select ButtonResume and duplicate ([Ctrl/Cmd] + [D]) again to make a third button.
        Name the third button "ButtonQuit" and Set text to "QUIT".

6. Create the volume Slider:
    a. RightClick your Canvas to create a UI >Slider.
    b. In the Inspector, with anything selected, add a new Tag called "PauseMenuSlider".
    c. Select your Slider in the Hierarchy and in the Inspector add the new tag "PauseMenuSlider".
    d. Set Slider Min Value to 0.0001 (leave Max Value at 1) and Value = 1.

NOTE: Make sure your tag is spelled and capitalized correctly, or script can disable on play.

7. Create the Audio Mixer:
    a. Open Window > Audio > AudioMixer.
    b. In the Mixer panel hit [+] to create a new mixer. Name it "MyMusicMixer".
    c. Select Mixer Groups > Master.
    d. In Inspector RightClick Volume to choose: "Expose 'Volume (of Master)' to Script."
    e. In UpperRight corner of Mixer click Exposed Parameters rolldown.
    f. Change name "Volume of Master" to "MusicVolume".


8. Add to the GameHandler.cs script:
Open the GameHandler scipt and copy the content below into it.
Save the script and return to Unity to compile the changed script.

add the bold faced content into GameHandler.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using UnityEngine.Audio;

public class
GameHandler : MonoBehaviour {

        public static int playerStat1;

        public static bool GameisPaused = false;
        public GameObject pauseMenuUI;
        public AudioMixer mixer;
        public static float volumeLevel = 1.0f;
        private Slider sliderVolumeCtrl;


        void Awake(){
                SetLevel (volumeLevel);
                GameObject sliderTemp = GameObject.FindWithTag("PauseMenuSlider");
                if (sliderTemp != null){
                        sliderVolumeCtrl = sliderTemp.GetComponent<Slider>();
                        sliderVolumeCtrl.value = volumeLevel;
                }
        }


        void Start(){
                pauseMenuUI.SetActive(false);
                GameisPaused = false;
        }


        void Update(){
                if (Input.GetKeyDown(KeyCode.Escape)){
                        if (GameisPaused){ Resume(); }
                        else{ Pause(); }
                }
                // Stat tester:
                //if (Input.GetKey("p")){
                //       Debug.Log("Player Stat = " + playerStat1);
                //}

        }


        void Pause(){
                pauseMenuUI.SetActive(true);
                Time.timeScale = 0f;
                GameisPaused = true;
        }


        public void Resume(){
                pauseMenuUI.SetActive(false);
                Time.timeScale = 1f;
                GameisPaused = false;
        }


        public void SetLevel (float sliderValue){
                mixer.SetFloat("MusicVolume", Mathf.Log10 (sliderValue) * 20);
                volumeLevel = sliderValue;
        }



        public void StartGame(){
                SceneManager.LoadScene("Scene1");
        }

        public void OpenCredits(){
                SceneManager.LoadScene("Credits");
        }

        public void RestartGame(){
                Time.timeScale = 1f;
                SceneManager.LoadScene("MainMenu");
                // Please also reset all static variables here, for new games!
        }

        public void QuitGame(){
                #if UNITY_EDITOR
                UnityEditor.EditorApplication.isPlaying = false;
                #else
                Application.Quit();
                #endif
        }
}


9. Fill Hierarchy GameHandler script slots:
    a. Select the GameHandler in the Hierarchy (NOT the prefab in the Project panel).
    b. In the Inspector, into the "pauseMenuUI" script slot drag your Hierarchy PauseMenu object.
    c. For the "mixer" script slot hit the hotspot to load your MyMusicMixer object.

10. Set-up Pause Menu Buttons functionality:
    a. Select each Button, in Inspector find OnClick field, hit [+].
    b. Drag Hierarchy GameHandler object into the "None" slot.
    c. Click [No Function] to find the GameHandler() script and choose the corresponding function:
        QuitGame() for Quit
        RestartGame() for Restart
        Resume() for Resume

11. Set-up Pause Menu Slider functionality:
    a. Select the Slider.
    b. In Inspector find the OnValueChanged field and hit [+].
    c. Drag GameHandler into None,
    d. Click [No Function] to find the GameHandler() script.
    At top of options under Dynamic float choose "SetLevel"
    (use the top option, NOT the lower one).


12. Add an Audio file to your Scene:
    a. Create an Empty G.O., name it "AudioManager"
    b. Drag an audio file onto this object to add it as an Audio Source Component
        (music or other ambient sounds, as .MP3 or .WAV).
    c. Under the AudioSource Component > Output hit the hotspot to add the MyMusicMixer.
    d. Drag the AudioManager object into the Project panel to make it a Prefab.
        Now you can easily add the Prefab to other Scenes, where the music file can also be changed.

To playtest, hit Play and at any time tap the [Esc] key to toggle your Pause Menu!
Turn off Play for the final step.


13. FINALLY, REPLICATE PAUSE MENU AS PREFAB:
    a. Drag the PauseMenu into the Project panel to make a Prefab.
    b. Then, drag this PauseMenu Prefab into all Scenes, onto the existing Canvas object (to parent).
        The GameHandler Prefab should be in each Scene, as well.
    c. Redo steps 9, 10, and 11 for each Scene:
            Step 9: Fill the GameHandler script slots in the Inspector.
            Step 10: Connect the Buttons to the in-Hierarchy GameHandler and their functions.
            Step 11: Connect the Slider to the in-Hierarchy GameHandler and its function.


IMPORTANT: The default Update() function in the original GameHandler script using the [ESC] key to quite the game, needs to be deleted or commented out, or otherwise every time you try to hit [ESC] to pause the game in the actual build, it will instead close the game.



 
09b. ADDING AUDIO:
Each game MUST have at least one sound effect OR music (and can certainly have both, and many).

[OPTION A] HOW DO I ADD MUSIC TO MY GAME?
If someone on your team can and wants to compose music, they should!

Framing Scenes are great places to put music (MainMenu, Credits, End_Win and End_Lose Scenes).
Length: About 1-2 minutes long, designed to loop.
Format: Save as MP3 (the prefered format for Unity to import longer sound files).

Don't have anyone on the team with music composotion experience?
You can make decent ambient music yourself using an online piano, using only black keys (major scale).
Try this virtual piano (register for a free account to be able to download your creations).

Steps to Add Music to Unity:
In Unity, import the music MP3 file into the Assets folder.
In a Scene you want the music to play, RightClick the Hierarchy to create an Empty Game Object.
In the Inspector, name it "AudioManager" and Reset Transforms.
Drag the MP3 audio clip onto the Audio Manager object in the Hierarchy..
In the Inspector, not that a new componebnt has veen added to the AudioManager: an AudioSource.
In the AudioSource component set the Output to your MyMusicMixer > Master (if you have completed the PauseMenu). For music, leave on the option to "Play on Awake".

To have the music play continuously through framing sceners without restarting on scene change, try the script for "Continuous Play" found here.



[OPTION B] HOW DO I ADD A SOUND EFFECT TO MY GAME?
Do you want a door creak sound every time yopur player changes rooms?
Or a ghostly cry when the ghost appears?

1. RECORDING: Sound effects can be recorded with your phone, and made with mouth sounds or "foley" work (banging / rubbing / dropping things in the real world-- stay safe!). The file type should be WAV for Unity (the prefered format for short audio clips: Waveform Audio format). If your phone makes an m4a file, please use an online convertor (search on Google).

2. EDITING: Edit your sound effect (SFX) .WAV file in your prefered program (Audacity is free).
Be sure to remove any extra time before and after the desired sound.
Export the shorter clip as a WAV.

3. UNITY SCRIPT:
In a Scene you want this clip to play:
   a. Open the Dialogue script in your script editor.
   b. In the top class variables, find and uncomment this line:
                        //public AudioSource audioSource1;

   c. Then find a Story Unit when you want the clip to play, one of these: else if (primeInt == #){ }.
   Add this command to the content of that Story Unit (usually at the top, above name and speech lines):
                        audioSource1.Play();

   d. Save your script, return to Unity to compile. If there are no errors, continue!


4. UNITY SCENE:
In Unity, import the final clip into the Project panel > Assets folder.
   a. In the Scene you want this clip to play, RightClick the Hierarchy to create a new Empty Game Object.
   b. In the Inspector, name it "AudioManager"and Reset Transforms.
   c. Drag the .WAV audio clip from the Assets folder onto the AudioManager in the Hierarchy.
   d. In the Inspector, you will see it has been added as an AudioSource component.
   e. Set "Play on Awake" = off, so the sound effect does not play as soon as the Scene starts. Set the Output to your MyMusicMixer > Master (if you have completed the PauseMenu).
   f. Select the Canvas object in the Hierarchy to see the Dialogue script you modified in the Inspector.
Scroll down to find the new AudioSource empty script slot at the bottom of the Inspector.
Drag the AudioManager from the Hierarchy into this empty script slot.


Hit [Play], and when you reach that Story Unit, the audio clip should play!
If it does not, confirm that Unity audio is on (in the Game view, top bar)

To use the same sound effect in multiple Scenes:
Drag the AudioManager into the Project panel > Assets > Prefabs folder to make it a Prefab.
Drag the Prefab from the Prefabs folder into the Hierarchy of those other Scenes.
Repeat step 3 in those Scenes (edit the script to use an AudioSource object).
Drag the AudioManager from the Hierachy into the empty Script slot.

Learn how to Trigger Multiple Audio Files


 
10. PLAYER STATS:
Player stats are "static" variables added to your GameHandler that can be changed and tested by other scripts.

For example:
We can track player health with an integer:

1. GameHandler.cs script: Add a stat called "playerHealth" of type = int (integer):
          public static int playerHealth = 10;

2. Scene#Dialogue.cs scripts: Change this stat:
         Reduce it when the player is injured or hungry:       GameHandler.playerHealth -= 1;
         Increase it if the player is healed or fed:                  GameHandler.playerHealth += 1;
         

3. GameHandler.cs script: Test the playerHealth stat in the Update():
         If the stat ever goes below 1, the player "dies" (change scene to a Lose Scene).

          //in the GameHandler
          if (playerHealth <= 0){
               SceneManager.LoadScene("End_LoseDies");
          }

          //in a story unit script
          if (GameHandler.playerHealth <= 10){
               primeInt =39;
          }


Another example:
The simplest stats to track are booleans that simply allow or disallow some part of your game.
Imagine the following scenario:
      A game set in a house with two main story tracks: Going to the attic or going to the basement.
      After multiple Scenes, both tracks offer the player to change their mind to choose the other track.
      Now, imagine the player has chosen the basement, but before the final choices that lead to victory or death they are given a chance to change their mind and visit the attic, and they take it.
      So they follow the attic track, and at some point are presented the chance to change their mind and go down to the basement.
      Being abler to go to the basement instead makes sense if they had started in the attic, but beign able to go there again feels silly to a player they has already been to the basement. It feels like the game does not know what the player has been doing. We want that basement-option in the Attic track to not be available if the player has already been to the basement.

      To solve this basement case, we make 3 changes to the scripts:
      1. GameHandler: Add a static boolean "canBasement", set to "true" by default:

          public static bool canBasement = true;

      2. Track 1 SceneDialogue: Change the stat: set bool value false when we start on basement track:

         GameHandler.canBasement = false;

      3. Track 2 SceneDialogue: Test the stat: add an if-condition around the button visibility:

          if (GameHandler.canBasement == true){ ButtonChangeToBasementTrack.SetActive(true); }
          else { ButtonChangeToBasementTrack.SetActive(false); }


Now, when the player starts in the basement, the canBasement bool is set to false.
If they change their mind when offered to jump to the Attic track, the Attic track will NOT offer the option of jumping back to the basement.

Naturally, this should also be done in reverse as well:
      Add a canAttic static bool in the GameHandler.
      Change the stat to false in the Attic track.
      Test the stat in the basement track to decide if a button to the attic track is allowed.



Again, every STAT needs THREE TYPES OF SCRIPT CHANGES:

PART 1. GameHandler.cs script: Add a static variable (optionally, functions to change and check it).

PART 2. Dialogue.cs scripts: One or more places that change this value in Story Units (primeInts)

PART 3. Dialogue.cs or GameHandler.cs: One or more places that test this value to create consequences: which Story Units are available, which room-buttons are visible, which endings the player gets, etc.

NOTE: the GameHandler prefab must be in EVERY Scene to preserve static variables

Here are actual scripts for these options:

OPTION #1: INTs (a number for player health, fear, seashells collected, sanity level, etc):
PART 1. Add to GameHandler.cs (our script above already includes an example of this):
    a static variable to persist between Scenes:           public static int playerStat;
    a method to update this variable:                              public UpdatePlayerStat(){ }.
    a method to return the current value of variable:      public CheckPlayerStat(){ }.

PART 2. This Stat can be changed in a Dialogue story unit by doing the following:
   a.  Uncomment the variable public GameObject gameHandler;
   b.  Uncomment from the start function: find gameHandler.
   c.  Add to any story unit you want to change the stat:
add the bold faced lines to a Story Unit to update the stat (choose 1):
       else if (primeInt ==7){
                Char1name.text = "";
                Char1speech.text = "";
                Char2name.text = "You";
                Char2speech.text = "Why do you think I know anything?";

                GameHandler.playerHealth += 1;         // increase the stat by 1, or:
                GameHandler.playerHealth -= 1;        // decrease the stat by 1
        }
   d.  In Hierarchy select Canvas. Quick-Drag GameHandler object into gameHandler script slot.

PART 3. The Stat can be tested in a Story Unit by doing the following to any Dialogue script:
Add an IF-condition with gameHandler.CheckPlayerStat() to any Story Unit you want to test, checking for the stat being <= a value or >= a value, and set primeInt results from there:
add the bold faced lines to a Story Unit to test the stat:
       else if (primeInt ==7){
                Char1name.text = "";
                Char1speech.text = "";
                Char2name.text = "You";
                Char2speech.text = "Why do you think I know anything?";

              if (GameHandler.playerHealth <= 0){
                     primeInt = 39;
              }

        }
In this example, IF the stat is less than or equal to zero, then the primeInt is set to 39.
So the next time the player hit [NEXT] they will go to primeInt == 40.


OPTION #2: BOOLs (true or false, for setting an option on or off):
A static bool variable could track encounters to unlock options later in the game
EXAMPLE: Did the player talk to the Jester? Then at the end they get an escape option from the castle dungeons! Create a static bool isJestered and check that bool at the end.

Here is an example of BOOL Stats for collecting ITEMS that appear on screen:

PART 1: Add to GameHandler (full example script, includes PauseMenu functions)
SUMMARY: Add Static Variables, Push functions (to change values) and Pull functions (to test values).
NOTE: This example has a small inventory display of 2 inventory images to show if the 2 stats are true, updated by the GameHandler. These 2 small icon images need to be dragged into Thing1icon and Thing2icon script slots.
add these elements to your GameHandler.cs for the inventory / stat changes:
        // Here are static bool variables to record the presence of two inventory items.
        public static bool gotThing1 = false;
        public static bool gotThing2 = false;

        // Here are GameObject variables for the small image icons to appear on screen
        // when you have these items (and not appear when you don't):
        public GameObject Thing1icon;
        public GameObject Thing2icon;

        // In the Start function we call the Update functions to decide if the icons get displayed:
        public void Start(){
                UpdateThing1(gotThing1);
                UpdateThing2(gotThing2);
        }

        // Here are 2 functions to allow other scripts to "PUSH" changes to these static bools
        // and also change the display of the icons:
        public void UpdateThing1(bool thingBool){
                gotThing1 = thingBool;
                if (gotThing1 == true){
                        Thing1icon.SetActive(true);
                } else { Thing1icon.SetActive(false); }
        }

        public void UpdateThing2(bool thingBool){
                gotThing2 = thingBool;
                if (gotThing2 == true){
                        Thing2icon.SetActive(true);
                } else { Thing2icon.SetActive(false); }
        }

        // Here are 2 functions to "PULL" the currrent status of these bools, so if-conditions in
        // scripts can deliver specific content that depends on the Things being true or false.
        public bool IsThing1(){
                return gotThing1;
        }

        public bool IsThing2(){
                return gotThing2;
        }



PART 2: Add to Scene Dialogue Scripts to Change the Stat (example script)
SUMMARY: To "PUSH" changes to the static values in GameHandler.cs, add a variable reference to the GameHandler, and then a line that updates a static bool through the GameHandler. When this Dialogue script is saved, the actual GameHandler in Scene must be dragged into the script slot:
add to a SceneDialogue script where you want to PUSH the bool change:
        // At the top we add a variable for the GameHandler. When this script is saved,
        // the actual Gamehandler in Scene must be dragged into the script slot:
        public GameHandler gameHandler;

        // In the Next() or choice() functions we use this reference to the GameHandler
        // to access the UpdateThing functions. For example:
        else if (primeInt == 100){
                Char1name.text = "";
                Char1speech.text = "";
                Char2name.text = "CHARLOTTE";
                Char2speech.text = "Do you realize what we found? The Shard of Eternity!";
                gameHandler.UpdateThing1(true);
        }


PART 3: Add to a Dialogue Script to See a Stat and Show Conditional Content (example script)
SUMMARY: To "PULL" the current value of a static variable, given a variable reference to the GameHandler, add a line that looks at the current value through the GameHandler. Then, based on the result, use an IF-condition to deliver varied content (images and dialogue).
add to a SceneDialogue script where you want to PULL the bool change:
        // At the top we add a variable for the GameHandler. When this script is saved,
        // the actual Gamehandler in Scene must be dragged into the script slot:
        public GameHandler gameHandler;

        // In the Start() function we use this reference to GameHandler to access the current
        // values through the WhatIsThing functions, and decide what content to then show.

        // In this scenario, we could write 4 versions of what happens:
        // Got both Thing1 and Thing2? Read primeInt 2-17 (the default 15 lines in this scene)
        // Got just Thing1? Read primeInt 20-35 (skip the default! Would end in a choice)
        // Got just Thing2? Read primeInt 40-55 (Would end in a choice)
        // Got neither? Read primeInt 60-75 (Would end in a choice)
        public void Start(){
                if ((gameHandler.IsThing1()== true )&&(gameHandler.IsThing2()== false )){
                        primeInt = 19;         //so that hitting [NEXT] goes to primeInt = 20!
                }
                else if ((gameHandler.IsThing1()== false )&&(gameHandler.IsThing2()== true )){
                        primeInt = 39;         //so that hitting [NEXT] goes to primeInt = 40!
                }
                else if ((gameHandler.IsThing1()== false )&&(gameHandler.IsThing2()== false )){
                        primeInt = 59;         //so that hitting [NEXT] goes to primeInt = 60!
                }
        }


IMPORTANT RESET NOTE: Make sure your GameHandler Restart() function, used for the Pause Menu and the End Scenes, includes a RESET of any stats! Set booleans back to false, ints back to their starting value. etc, so progress does not carry over to a restart!!


NOTE 1: STATIC VARIABLES ARE USUALLY CHANGED DIRECTLY
As noted in the top examples of this tutorial on static variables, an awesome feature of static variables is that they can be accessed directly through the class:

Given this class and script...:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class
GameHandler : MonoBehaviour {
        public static int playerHealth = 10;
}

...We can update the variable from another script by refering directly to the actual class
(without first creating a variable for the GameHandler)
:
       GameHandler.playerHealth += 1;



NOTE 2: ENTIRE SCENE-SELECTION CAN BE BASED ON VARIABLES:
      Static variables are used to preserve values between Unity Scenes. But what if we did not need them?

      It is possible to run the entire game from a single Unity Scene.

      All interactions in that location (from all narrative branches) would be separate Canvas elements + Dialogue script, all set invisible unless called.

      To do this, the GameHandler object would hold public variables designed to make visible a specific Canvas based on the player choices (buttons clicked) from the previous Canvas.

      In this way, we could avoid using Static variables altogether: regular public variables would be enough.

      For a team project, each Canvas would be a Prefab that can be adjusted independantly without having to touch the actual "Scene". BUT, in general, the multiple-scene version of this project taught in this tutorial is MUCH easier to coordinate with a team.

 
11. UI ART:
Before the project is done, do a User Interface Art Pass
Paint Buttons art and create images for the following assets:

(1) Fancy button for MainMenu, PauseMenu, and Next Buttons:
300x80

PSD file


(2) Simpler button for gameplay choices:
400x90

PSD file
(3) Speech Name backing:
400x70

PSD file


Displayed at 75% size:
(4) Speech Text backing:
780x250

PSD file
Displayed at 75% size:
(5) Pause Menu backing:
550x680

PSD file





(6) Also, create a round-ish shape for the Volume Slider Handle
32x32 or 64x64.

Displayed at 75% size:


Examples of the art in game (click for larger images):







 
11b. CUSTOM FONTS:

Any True Type font can be imported into Unity by draggign the file into the
You can download free fonts, but be sure to cite the ones you use in the credits.
Choose fonts that fit the styel of your project, and most importantly are easy to read.

For Legacy Text objects and Buttons, the custom font can be dragged directly into the Text font slot in the Inspector

For Text Mesh Pro objects, the fnt must first be converted into the .asset format:
1. Open Window > TexMesh Pro > Font Asset Creator.
2. Select the font to convert.
3.






 
12. SOME COMMON ERRORS:

Script not compiling?
Check the console for errors and line numbers! Most errors are about:
  • Forgetting to end a line with a semicolon (;)
  • Not completing nesting brackets ({ }), especially at the end of the Next() function.
  • Having the wrong class name: When you duplicate and rename a script for a new Scene, be sure the Class name at the top of the script matches the script name!
  • Having the wrong variable name. Must be identical everywhere in the script, including capitalization.
  • Using GameObject vs gameObject incorrectly. "GameObject" = type, "gameObject" = instance.
  • Using the wrong access. To reference a function in another script, we need to set that function public!
  • Accidentally duplicating a script: there can only be one GameHandler!

    Objects appearing in Scene but not in the Game view?
    An issue with 2D games is to manage the display order of elements.
    In a Canvas, the higher an image is located the further back it appears.
    For Tilemaps and regular Sprite objects set Sprite Renderer > Additional Settings > Order in Layer in the Inspector: the lower the number, the further back it appears.
    Also, be sure to check that your object Z-position is not behind the Camera!
    A 2D Camera is typically position z position = -10. All of your 2D objects should be Z position = 0.

    Trying to load a function onto a Button Onclick, but it is not appearing in the list?
    To make a button work:
    (1) Select the button and in the Inspector add an Onclick function.
    (2) Drag an object with the relevant script onto the Onclick None slot (in the lower left, like GameHandler).
    (3) Search the Function list (to the right) for the relevant script and choose the function. If you cannot find the function in the list, chances are you have not yet set the function access to public in the script itself.

    Fully Set-Up buttons not working-- do not even show color change on rollover?
    Make sure your scene has the EventSystem game object. An Event System is auto-created when adding buttons to a scene, but can be easy to accidentally delete.

    OR, you may have a Canvas Image layer overlapping "in front" of the buttons, blocking their functionality. Buttons need to be "up front"-- i.e., at the bottom of the revelant Canvas area.
    Nothing can overlap in front of them: nothing in a Canvas can be below them in the Hierachy (except the Pause menu, which is SUPPOSED to block them when it is enabled).

    To Create Canvas "Folders": In general, avoid using nested Canvas objects or Empty Game Obects inside of a Canvas; instead, create a UI > Image object and set color alpha value = 0.



  •  
    12. WAYS TO ENHANCE YOUR PROJECT:


    a) TEXT (source):
    Play with imported fonts! Try a custom look and feel for each speaker's text.
    Just make sure the text is easily legible!

          TEXT COLORS: Give each character's speach and name a signature color that persists between Scenes. Change the color value of text objects in the Inspector (and copy / paste the hexadecimal value).

          TEXT CUSTOM FONTS: In your computer Start menu, type "fonts" to find the ones you have installed, and drag the font files into the Unity Project panel. From there it can be dragged onto a text object in the Hierarchy (rather than apply in Inspector).


    b) EFFECTS FUNCTIONALITY: Consider adding one or more of the Visual Effects explained below:
          [A]:Type-on Text, [B]: Fade-in-Image, [C]: Vibrating Text, and / or [D]: Custom Player Naming.



     
    [A]: EFFECT: TYPE-ON TEXT (source): Want your text to appear one letter at a time?

    TEST: Add this script to a Canvas Text object.
    Hit Play and test by typing into the fullText script slot in the Inspector.


    TypeFX.cs
    (NOTE:
    This full script is NOT for the Visual Novel tutorial. Use instead the partial script below):

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine.UI;

    public class
    TypeFX: MonoBehaviour {

            public float delay = 0.01f;
            public string fullText;
            private string currentText = "";

            void Start(){
                    StartCoroutine(ShowText());
            }

            IEnumerator ShowText(){
                    for(int i = 0; i < (fullText.Length + 1); i++){
                            currentText = fullText.Substring(0,i);
                            this.GetComponent<Text>().text = currentText;
                            yield return new WaitForSeconds(delay);
                    }
            }
    }


    To include this Fade-In / Out functionality in your Visual Novel:
    a) Add this Coroutine "TypeText" to the bottom of your SceneDialogue script (before the end bracket):
    Note the Next button and Spacebar are made inactive while the text displays/animates, so it is not interrupted:


    Add to bottom of SceneDialogue script:
            IEnumerator TypeText(Text target, string fullText){
                    float delay = 0.01f;
                    nextButton.SetActive(false);
                    allowSpace = false;

                    for (int i = 0; i < fullText.Length; i++){
                            string currentText = fullText.Substring(0,i);
                            target.text = currentText;
                            yield return new WaitForSeconds(delay);
                    }
                    nextButton.SetActive(true);
                    allowSpace = true;

            }

    b) Adjust any text input lines you want to have this effect as follows, with the speech ID and desired text INSIDE the Coroutine. So:

                    Char1speech.text = "Wakey wakey, human";

    becomes:
                 StartCoroutine(TypeText(Char1speech, "Wakey wakey, human"));


    IMPORTANT:
    ONLY use StartCoroutine for active (populated) text lines.
    All empty text lines ("") must NOT use this script, so they can immediately clear the space from previous text.

    We can even expose the delay variable to make the timing change-able for different character speech!


     
    [B]: EFFECT: IMAGE FADE IN / FADE OUT (ANIMATING VISIBILITY)
    SUMMARY: Object Visibility uses the Alpha property of an Object's renderer.We change it by capturing the value and assigning it a new variable and action. 3D Objects: this is a property in Material Renderer.

    CANVAS IMAGE OBJECTS: Alpha is part of color options in Image: (R,G, B, A)
    This script can be applied to a Canvas, then drag the image object into the script slot and hit Play.

    ChangeAlphaTime.cs
    (NOTE: This full script is NOT for the Visual Novel tutorial; use partial script below):

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;

    public class
    ChangeAlphaTime : MonoBehaviour {

            public GameObject imageToFade;
            public float alphaLevel = 0f;

            void Start(){
                    imageToFade.GetComponent().color = new Color(1, 1, 1, alphaLevel);
                    StartCoroutine(FadeIn(imageToFade));
            }

            IEnumerator FadeIn(GameObject fadeImage){
                   for (int i = 0; i < 100; i++){
                            alphaLevel += 0.02f;
                            yield return null;
                            fadeImage.GetComponent<Image>().color = new Color(1, 1, 1, alphaLevel);
                            Debug.Log("Alpha is: " + alphaLevel);
                    }
            }
    }


    To include this Fade-In / Out functionality in your Visual Novel:
    a) Add these two functions to the bottom of your SceneDialogue script (before the end-bracket):

    add to bottom of SceneDialogue script:
            IEnumerator FadeIn(GameObject fadeImage){
                    float alphaLevel = 0;
                    fadeImage.GetComponent<Image>().color = new Color(1, 1, 1, alphaLevel);
                    for(int i = 0; i < 100; i++){
                            alphaLevel += 0.01f;
                            yield return null;
                            fadeImage.GetComponent<Image>().color = new Color(1, 1, 1, alphaLevel);
                            Debug.Log("Alpha is: " + alphaLevel);
                    }
            }

            IEnumerator FadeOut(GameObject fadeImage){
                    float alphaLevel = 1;
                    fadeImage.GetComponent<Image>().color = new Color(1, 1, 1, alphaLevel);
                    for(int i = 0; i < 100; i++){
                            alphaLevel -= 0.01f;
                            yield return null;
                            fadeImage.GetComponent<Image>().color = new Color(1, 1, 1, alphaLevel);
                            Debug.Log("Alpha is: " + alphaLevel);
                    }
            }


    b) Add a call to one of these coroutines right before the image is made to appear.
    Note the desired Image is inside the coroutine, placed BEFORE the .SetActive() command:


    add to a primeInt unit in athe same SceneDialogue script:
                 StartCoroutine(FadeIn(ArtChar1));
                  ArtChar1.SetActive(true);



     
    [C]: EFFECT: VIBRATING TEXT (big emotions, or monsters): Want some text to shake?

    a. Create a new C# script called "Shaker.cs" with the content below.

    b. Add this script to any Canvas Text object you want to vibrate (like char1Speech).

    Shaker.cs:
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class
    Shaker: MonoBehaviour {

            public float shakeAmount = 2f;
            private Vector3 initialPosition;

            void Start () {
                    initialPosition = this.transform.position;
            }

            void Update () {
                    this.transform.position = Random.insideUnitSphere * shakeAmount + initialPosition;
            }

           public void ChangeShake (float newAmount) {
                    shakeAmount = newAmount;
           }
    }


    c. Adjust the SHAKE AMOUNT:
    By default, this script will apply the same shake amount to all appearances of the text to which it is applied.

    BUT, the amount of shake can be adjusted in the SceneDialogue script with just one line of code in each primeInt that displays that text, referencing the parent Text object and the "ChangeShake" function:

    Add the bold-faced line to the SceneDialogue.cs, setting the value as desired:
           else if (primeInt == 4){
                    Char1speech.gameObject.GetComponentInParent<shaker>().ChangeShake(10f);
                    Char1name.text = "Jeda";
                    Char1speech.text = "I know I did not hit you that hard.";
                    Char2name.text = "";
                    Char2speech.text = "";
            }



     
    [D]: INPUT NAME FIELD (source): Want to allow a player to enter a name for their character?
    SUMMARY: You will need: an Input Field, a Button, a Text and an Image UI objects. You will need the following script added to the Canvas and adjustments to both the GameHandler script and each SceneDialogue script.

    1. Create the UI Game Objects: Open your MainMenu scene (where we recommend you offer the option of customizing player name)
    a. Create a GameObject > UI > Input Field. Scale larger and position as desired (like high above the start button). In the Hierarchy click the triangle to view the children. Select Placeholder to change the default text to "Enter a name" and set font size to 30. Select Text and set the font to 30, and then in the Hierarchy move Text above Placeholder.

    b. Create a GameObject > UI > Legacy > Button. Move and scale to locate next to the Input Field. Select its Text and change font to 30 and text to "Enter" or just ">>".

    c. Create a GameObject > UI >Text. Move and scale to locate in the Scene below the Input field and above your start button. In the Inspector name it TextWelcome. Set Font Size to 30, and include placeholder text like "Welcome message."

    d. Create a GameObject > UI > Image. In the Inspector name this image "WelcomeDisplay". Set posX and posY = 0, set width and height to 1280x720, and set color alpha from 255 to 0 so it is invisible. In the Hierarchy move this image up so it is above all Buttons and the Input Field, and drag the TextWelcome object onto the WelcomeDisplay image to make it a child.


    2. Create the NameTransfer Script: RightClick in the Project panel Assets folder to Create a new C# script named NameTransfer.cs. Hit [ENTER] and DoubleClick it to open in your script editor.
    a. Replace all the code with the following, save and return to Unity:
    NameTransfer.cs:
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine.UI;

    public class
    NameTransfer : MonoBehaviour {

            public string theName;
            public GameObject inputField;
            public GameObject textDisplay;
            public GameHandler gameHandler;
            public GameObject welcomeDisplay;

            void Start () {
                    welcomeDisplay.SetActive(false);
            }

            public void StoreName(){
                    theName = inputField.GetComponentInChildren<
    Text>().text;
                    textDisplay.GetComponent<
    Text>().text = "Welcome, " + theName + ", to the game.";
                    welcomeDisplay.SetActive(true);
                    gameHandler.UpdateName(theName);
            }
    }

    b. Add this script to the Canvas.

    c. Select the Canvas, drag the InputField, TextWelcome, WelcomeDisplay, and the GameHandler into their script slots.

    d. Select the Button and in the Hierarchy find the OnClick() field, hit [+] to make an Event, drag the Canvas into it and choose your DialogueScript > StoreName().
    Hit Play to test, then turn off Play.


    3. Make the name persist in all Scenes:
    Open GameHandler.cs in your script editor, and add the following (copy from codeblock below):
    a. A "public static" string variable that will persist between scenes because it is located on an object that exists in all scenes (the GameHandler!).

    b. A method to update the public static string.

    c. A method to access the public static string (this last one is optional: we could refer to the class and variable directly in the SceneDialogue script).
          Add to the top of GameHandler.cs:

           public static string playerName = "YOU";
          Add to the bottom of GameHandler.cs:
          public void UpdateName(string newName){
                playerName = newName;
                Debug.Log("name changed to " + playerName);
          }
          public string GetName(){
                return playerName;
          }


    4. Populate the game with the name:
    Finally, we can pull the playerName from the GameHandler into each Dialogue Script.
    a. Be sure the GameHandler prefab exists in all your scenes (to pass the public static string along)


    b. To each SceneDialogue.cs script:
    At the top, add two variables: a new public string playerName and a reference variable to hold the GameHandler:
                  
                  Add these variables to the top Class variables:

           public string playerName;
           public GameHandler gameHandler;

    Load the local playerName variable with the string from GameHandler:

                  Add to the Start() method, load the name into the local variable, and capitalize:

           string pNameTemp = gameHandler.GetName();
           playerName = pNameTemp.ToUpper();

    In each dialogue section where the Player character speaks, or where another character says the Player's name, use this string variable:

                  Now we can use this name in the Next() method to identify the player:

           Char1name.text = playerName;


    c. Save the script, click back to Unity to compile.
          IMPORTANT: Select the Canvas and drag the GameHandler into the script slot.


    Hit [Play] to test!


     
    [E]: EFFECT: TRIGGER MULTIPLE AUDIO CLIPS: Want to use multiple audio clips in a scene?
    Create variables to hold multiple AudioSource components and then trigger each as needed.
    The following script is a simple example thqt uses keyboard input to trigger varied sounds.

    1. Create SFX (sound effects) .WAV files or try these 3 Sample Audio Clips.
    To make your own SFX, use a voice recording app on your phone and use your mouth or objects around you to generate sounds. Then edit the clips so each includes only one sound with no space before or after. Audacity is a free program commonly used for quick audio editing.
    In the Unity Project panel import your audio clips (the following assumes an example with 3 WAV clips).


    2. Create a GameObject > Empty GameObject. In the Inspector name it "AudioTest".
    a) Add three AudioSource components: Select the empty GameObject, and in the Inspector add the same AudioSource Component 3 times.

    (NOTE: dragging an audio clip from the Project panel onto a GameObject will create a single AudioSource component, but more than one need to be directly added by clicking the Inspector [Add Component] )

    b)
    Drag each audio clip into the Source slot of three AudioSource components.
    For each AudioSource, turn off "Play On Awake" (so they do not auto-play at Start)


    3.
    Create a new C# script named "AudioTest".
    a) Add the content below, Save, and click Unity to compile.

    b) Add the script to the AudioSource Game Object.

    c) Finally, drag each AudioSource component into each script slot (just click and drag from the rolldown name-bar of each into the slots).
    Hit [Play] and hit the keyboard numbers [5], [6], and [7] to test!

    AudioTest.cs:
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;

    public class
    AudioTest : MonoBehaviour {

            public AudioSource SFXClip1;
            public AudioSource SFXClip2;
            public AudioSource SFXClip3;

            void Update(){
                    if (Input.GetKeyDown("5")){
                            SFXClip1.Play();
                    }
                    if (Input.GetKeyDown("6")){
                            SFXClip2.Play();
                    }
                    if (Input.GetKeyDown("7")){
                            SFXClip2.Play();
                    }
            }
    }


    HOW DO I ADD THIS TO MY GAME?
    To integrate this functionality into your game scripts:

    1. Include the variables at the script top

    2. Put the "[clip variable name].Play()" commands wherever you want them to be triggered.

    3. Add the Audio Source Components in the Inspector:
            a) [Add Component] an AudioSource to the GameObject with the script for each audio clip
            b) drag the audio clip .WAV files into the AudioSource components source slots
            c) drag the AudioSource components into the script slots

    In this Narrative game, add the .Play() commands to story units. In an Action game, add them to the various movements: jump, punch, getHit, etc.



     
    [F]: EFFECT: ANIMATED MENUS

    ANIMATED BACKGROUND: Want an animated element in a background?
    In your 2D art tool of choice, create a 4 - 20 frame animation (Try these sample images). Each frame can be the entire background, but typically we just animate an isolated area, for more performant results.

    For example, in this Main Menu background image:


    Here is the actual background image, everything that is NOT animated, including the character body
    (1280x720 PNG):

    Here are the 4 animation frames of her hair
    blowing in the wind (each 512x512 PNGs):



    1. In the Hierarchy set up the two images in the Canvas:
    a) Create a Canvas (if one does not already exist in the Scene): GameObject > UI > Canvas.
         Set Canvas Scaler > UI Scale Mode = Scale with Screen Size.
         Set Reference Resolution to 1280x720.

    b)
    Create an Image: GameObject > UI > Image.
         In the Inspector name it "image_BG". Set position X and Y = 0. Set Size = 1280 x 720.
         Drag the Background image into the Source Image slot.

    c)
    Create a second Image: GameObject > UI > Image.
         In the Inspector name it "image_Anim1". Set position X and Y = 0. Set Size = 512 x 512.
         For this example, set Position X and Y = 130 x 110.
         Drag one frame of the animation into the Source Image slot.


    2. Create an animation clip:
    a) Open Window > Animation > Animation.

    b) With image_Anim1 selected hit the [Create] button at the center.

    c) Name the new clip “Anim1_anim”.

    d) Hit [OK].


    3. Populate the clip with animation:
    a) Drag all 4 frames into the animation panel's Timeline (at top).

    b) Drag the first frame into the Timeline again and place it at the end, for a total of 5 images.

    c) Set timing of these frames to 1, 8, 15, 23, 30.

    d) Hit the Animation Play triangle to see the Scene copy animate.
         Adjust timing as you desire. Close the Animation panel.







    ANIMATED BUTTONS: Buttons can be animated as well!
    a) Create a GameObject > UI > Legacy > Button.

    b) In the Inspector set name to "button_Play". Set size = 200 x 70.

    c) Open the button twirly to select the child Text object.

    d) In the Inspector set the text field = PLAY, the font size to 40, style to bold.

    e) Import the Button frames (each is 200 x70, to match the Button Object):





    f) With the Button Objects selected, set the source image to the first button.

    g) Set colors as desired: Normal Color, Highlighted Color, Pressed Color

    h) Open Window > Animation > Animation and hit [Create] to add a new clip: "buttonA_anim".

    i) Drag all four frames into the timeline: the plain button and the 3 reflections. Set the timing to 1, 5, 10, and 15. Drag inthe plain button twice more, and set timing to 20 and 60. This creates a quick relfection and then more than a second pause before the next animation.


    j) Duplicate the button twice ([Ctrl]+[d]), drag down, and change text for CREDITS and QUIT buttons.

    k) Optionally, offset the timing of the other buttons to vary the timing of the reflections.













     
    [G]: EFFECT: CUSTOM CURSOR:
    You can change your default cursor, and you can swap it based on context (rollover effect)!

    The Build Settings > Player Settings has an easy place to import a 32x32 PNG.
    If the Player Settings does not work, either in the Unity Editor or in the itch.io WebGL build,
    try this Custom Cursor System by adding a few lines of code to the GameHandler prefab:

    PART 1: Change the Default Cursor:
    a) Create your new cursor pointer art in Photoshop. Name it customCursor.png.
    It must be:
        A PNG sized 32 x 32, with a transparent background (72ppi, like all 2D Unity game art).
        Consistent design with your game content (in the art style, consistent with tone / genre)
        Easily visible against all scene art (a strong outline and high-contrast interior recomemended)

    In the Unity Project panel > Assets folder, import your customCursor art.

    b) Open your GameHandler.cs script and add two lines:

    To the top Class Variables, add a reference to your cursor pointer art:


            public Texture2D cursorArrow;


    In the Start() function, add this one bold-faced line

            void Start (){
                    pauseMenuUI.SetActive(false);
                    GameisPaused = false;
                    Cursor.SetCursor(cursorArrow, Vector2.zero, CursorMode.ForceSoftware);
            }

    Save, and return to Unity so the revised script compiles.

    c) In the Project panel > Assets folder, find and DoubleClick your GameHandler PREFAB to open it.
        Note in the Inspector the new "Cursor Arrow" script slot.
        Drag your customCursor.png file into this Cursor Arrow script slot.

    Your game should now show the custom cursor in all Scenes that include this GameHandler prefab! Hit play to test.


    PART 2: Change the Cursor when on a specfic object (WIP):
    a) Create a second cursor pointer art in Photoshop. Name it customCursorButton.png.
    Use the same parameters: 32 x 32, consistent design, easily visible.
    In the Unity Project panel > Assets folder, import your custom cursor art.

    b) Create a new C# script ButtonCursor.cs with the content below (this will be added to any Unity button that is meant to get the rollover effect):

    To the top Class Variables, add a reference to your new cursor pointer art:

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;

    public class
    ButtonCursor : MonoBehaviour {

            public Texture2D cursorArrow;
            public Texture2D cursorArrow2;

            void OnMouseEnter (){
                    Cursor.SetCursor(cursorArrow2, Vector2.zero, CursorMode.ForceSoftware);
            }

            void OnMouseExit (){
                    Cursor.SetCursor(cursorArrow, Vector2.zero, CursorMode.ForceSoftware);
            }
    }

    Save, and return to Unity so the revised script compiles.

    c) Open the MainMenu scene. Open the Canvas to see the buttons.
        Select any button and apply this ButtonCursor.cs script.
        Drag both customCursor art files into this Cursor Arrow and Cursor Arrow 2 script slots.

    The buttons should now show a different cursor on rollover!
    Hit play to test.



    2D vs 3D NOTE: For a 2D project like this Visual Novel, these images are automatically imported as Sprites, and are located in the Canvas as UI images.

    For a 3D project, the Spite Editor would need to be loaded, and each of these images would need to be set to Sprite mode in the Inspector. They could then be located in the Scene as 2D Sprite objects, with Order in Layer set to display the animated section on top of the background (a higher number).


    OTHER EFFECTS TO CONSIDER:
  • Character Image falls through screeen (top to bottom), or walks off screen (use for-loop).
  • Instantiating Particle Effects or 2D VFX sprites (looping or one-time).



    Tutorials prepared by Jason Wiser, Madwomb.com
    The instructional content of this page is © 2015-2023 Jason Wiser.
    See more Unity tutorials at http://www.Madwomb.com/Unity