Simple (audio)dialogue scrip on Unity

So I made simple and really easy to use dialoque script that allows you to make simple and small conversations with npc or yourself. There is also audio which is added to list so you can play audio same time with correct text on screen.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using System.Text;
using System.IO;

public class Dialog : MonoBehaviour
{
//distance between npc and player
public float distance;
public Transform player;
public bool activez;
//number that decides which text is shown and which is not.
public int count;
//dictionary where we store our text
Dictionary<int, string> test = new Dictionary<int, string>();
//List for Audio files. Drag and drop files to here in inspector
public List<AudioClip> audios = new List<AudioClip>();
// Use this for initialization
void Start()
{

//all text is stored in dictionary and accessible with numbers
test.Add(0, "Text 1");
test.Add(1, "Text 2");
test.Add(2, "Text 3");
test.Add(3, "Text 4");
test.Add(4, "Text 5");
test.Add(5, "Text 6");
test.Add(6, "Text 7");
test.Add(7, "Text 8");
test.Add(8, "Text 9");
test.Add(9, "Text 10");
test.Add(10, "Text 11");
test.Add(11, "Text 12");
test.Add(12, "Text 13");
test.Add(13, "Text 14");
test.Add(14, "Text 15");
test.Add(15, "Text 16");
test.Add(16, "Text 17");
test.Add(17, "Text 18");
test.Add(18, "Text 19");
}

// Update is called once per frame
void Update()
{
//if player is close enought npc we "activate" script
distance = (transform.position - player.position).magnitude;
if (distance < 5)
{
activez = true;
}
else
{
activez = false;
}

}
void OnGUI()
{
//if script is "actived"
if(activez == true)
{
// if count is 0 which is the start, do gui button that changes count to 1 if pressed to start "conversation"
if(count == 0)
{
if(GUI.Button(new Rect(Screen.width/2,Screen.height/2,250,50),"Hey there do you understand me?"))
{
//Play audio file "element" 0 in list
audio.clip = audios[0];
audio.Play();
//make count to 1
count = 1;
}
}
//if count = 1 we make 3 more gui buttons wich set count to 2,3,4
if(count == 1)
{
GUI.Label(new Rect(10,Screen.height/2,500,100),test[4]);
if(GUI.Button(new Rect(Screen.width/2,Screen.height/2-100,250,50),test[5]))
{
//Play anotehr audio file from audio list
audio.clip = audios[1];
audio.Play();
//make count to 2
count = 2;
}
if(GUI.Button(new Rect(Screen.width/2,Screen.height/2-200,500,50),test[6]))
{
audio.clip = audios[2];
audio.Play();
count = 3;
}
if(GUI.Button(new Rect(Screen.width/2,Screen.height/2-300,250,50),test[7]))
{
audio.clip = audios[3];
audio.Play();
count = 4;
}
}
//checks if count is 2 ,3 ,4 and gives us text and back button,
//wich takes count back to earlier number, so you can choose again
if(count == 2)
{
GUI.Label(new Rect(10,Screen.height/2,500,100),test[8]);
if(GUI.Button(new Rect(Screen.width/2,Screen.height/2-300,250,50),test[12]))
{
count = 1;
}
}
if(count == 3)
{
GUI.Label(new Rect(10,Screen.height/2,500,100),test[9]);
if(GUI.Button(new Rect(Screen.width/2,Screen.height/2-300,250,50),test[12]))
{
count = 1;
}
}
if(count == 4)
{
GUI.Label(new Rect(10,Screen.height/2,500,100),test[10]);
//if player presses this button we move conversation to count 5
if(GUI.Button(new Rect(Screen.width/2,Screen.height/2-300,250,50),test[13]))
{
count = 5;
}
if(GUI.Button(new Rect(Screen.width/2,Screen.height/2-200,250,50),test[12]))
{
count = 1;
}
}
}
//if count = 5 button will spawn if player clicks it,
//it will start coroutine lol
if(count == 5)
{
if(GUI.Button(new Rect(Screen.width/2,Screen.height/2-200,250,50),test[14]))
{
count = 6;
StartCoroutine("lol");
}
}
if(count == 7)
{
GUI.Label(new Rect(Screen.width/2,Screen.height/2-200,250,50),test[15]);
}
if(count == 8)
{
GUI.Label(new Rect(10,Screen.height/2,500,100),test[16]);
}
if(count == 9)
{
GUI.Label(new Rect(Screen.width/2,Screen.height/2-200,250,50),test[17]);
}
if(count == 10)
{
GUI.Label(new Rect(Screen.height/2 +100,Screen.height/2-50,500,100),test[18]);
}
}
//waits several seconds and then shows different texts and plays audios
IEnumerator lol()
{
audio.clip = audios[4];
audio.Play();
count = 7;
yield return new WaitForSeconds(7);
audio.clip = audios[5];
audio.Play();
count = 8;
yield return new WaitForSeconds(5);
audio.clip = audios[6];
audio.Play();
count = 9;
yield return new WaitForSeconds(7);
audio.clip = audios[7];
audio.Play();
count = 10;
yield return new WaitForSeconds(2);
count = 11;
}
}

Unity thirdperson controller, camera and animation scripts

I wanted to make 3rd person controller and got it to work pretty nicely.

So first of all. What do we need? Well we need a camera ofc and somekind of 3d model to animate ( you will need to make/download your own). Ground and some light should be in the scene too.

First lets do the the script that moves the player.

We need to attach RigidBody and collider to our model. I prefer using capsule collider altought you have to scale it to fit your character. Set rigidbody rotation to freeze from inspector and last remove gravity from rigidbody. We will also have to go to Edit->Project settings->Input->Horizontal and set our negative and positive alt buttons to q and e instead of a and d. Script will make character move forward/backward/left/right, run, turn left/right and jump.

Then to the script.

using UnityEngine;
using System.Collections;

public class thirdperson : MonoBehaviour {

//Walking speed
public float speed = 6;
//Running speed of our character
public float runSpeed = 9;
//Speed of how fast our character turns
public float rotateSpeed = 90;
// is character grounded
public bool grounded;
//is character jumping
public bool isJumping;
// which way our character is moving. Defaul value is zero
public Vector3 moveDirection = Vector3.zero;

void Start()
{
//in start we set grounded and isjumping to false
grounded = false;
isJumping = false;
}

void Update ()
{
//we set rigidbodys velocity to 0
rigidbody.velocity = Vector3.zero;
//checks if there is anything under character if is set grounded to true if not set it to false
if(Physics.Raycast(transform.GetChild(0).position,Vector3.down,transform.localScale.y/2))
{
grounded = true;
}
else
{
grounded = false;
}
//checks if we are grounded so we cant jump again in air and if we press jump button. else we are not jumping so isjumping = false
if(Input.GetKeyDown(KeyCode.Space) &amp;&amp; grounded == true)
{
//Starts jump ienumerator
StartCoroutine("jump");
}
else
{
isJumping = false;
}
//If we press "d" we rotate our player as long as "d" is pressed down and if we press "a" rotate other way
if(Input.GetKey(KeyCode.D))
{
transform.Rotate(Vector3.up, Mathf.Clamp(180f * Time.deltaTime, 0f, 360f));
}
if(Input.GetKey(KeyCode.A))
{
transform.Rotate(Vector3.up, -Mathf.Clamp(180f * Time.deltaTime, 0f, 360f));
}
//set out movedirection equal to our horizontal and vertical axis and out transform direction to those axis.
moveDirection = new Vector3(Input.GetAxis("Horizontal"),0,Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);

// checks if we push left shift if yes it multiplies our movedirection speed with runspeed variable if not we go with normal speed
if(Input.GetKey(KeyCode.LeftShift))
{
moveDirection *= runSpeed;
}
else
{
moveDirection *= speed;
}
//Checks if our character is not jumping and its not grounded. then moves character down "gravity"
if(isJumping == false &amp;&amp; grounded == false)
{
transform.Translate(Vector3.down * 3 * Time.deltaTime);
}
//we set rigidbodys velocity to our movedirection wich contains speed and rotation of our character
rigidbody.velocity = moveDirection;

}

IEnumerator jump()
{
//First we ste player to jumping so gravity dsnt affect it
isJumping = true;
//We make loop that moves our player up multiple times if its not in touch with anything in front of it
for(int i = 0; i &lt; 30; i++)
{
if(Physics.Raycast(transform.position,Vector3.forward,transform.localScale.y/2 + 0.5f))
{
break;
}
else
{
transform.Translate(Vector3.up * 15 * Time.deltaTime,Space.World);
}
yield return null;
}
//last we set jumping back to false
isJumping = false;
}
}

Then we need third person camera, so we can look our character. I added 1st person mode aswell so player can look enviroment better. We make a camera and attach this script to it. To make script to work we will need to drag & drop our character into the player field in inspector. Camera will be moving depending on your mouse position and will never go under/behind anything. You can also increase distance between camera and player with mouse scroll wheel. Character will also change its X rotation to same as cameras X rotation if you press right mouse button.

Here is the code :

using UnityEngine;
using System.Collections;

public class cameraorbit : MonoBehaviour {
//This camera
public Camera mainCamera;
//Our character
public Transform player;
//distance between character and camera
public float distance = 5.0f;
//x and y position of camera
float x = 0.0f;
float y = 0.0f;
//x and y side speed, how fast your camera moves in x way and in y way
public float xSpeed = 120.0f;
public float ySpeed = 120.0f;
//Minium and maximum distance between player and camera
public float distanceMin = 0.5f;
public float distanceMax = 15f;
//checks if first person mode is on
private bool click = false;
//stores cameras distance from player
private float curDist = 0;

private void Start()
{
//make variable from our euler angles
Vector3 angles = transform.eulerAngles;
//and store y and x angles to different values
x = angles.y;
y = angles.x;
//sets this camera to main camera
mainCamera = Camera.main;
}

private void LateUpdate ()
{
//gets mouse movement x and y and multiplies them with speeds and moves camera with them
x += Input.GetAxis("Mouse X") * xSpeed * distance * 0.02f;
y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
//set rotation
Quaternion rotation = Quaternion.Euler(y, x, 0);
//changes distance between max and min distancy by mouse scroll
distance = Mathf.Clamp(distance - Input.GetAxis("Mouse ScrollWheel")*5, distanceMin, distanceMax);
//negative distance of camera
Vector3 negDistance = new Vector3(0.0f, 0.0f, -distance);
//cameras postion
Vector3 position = rotation * negDistance + player.position;
//rotation and position of our camera to different variables
transform.rotation = rotation;
transform.position = position;
//cameras x rotation
float cameraX = transform.rotation.x;
//checks if right mouse button is pushed
if(Input.GetMouseButton(1))
{
//sets CHARACTERS x rotation to match cameras x rotation
player.eulerAngles = new Vector3(cameraX,transform.eulerAngles.y,transform.eulerAngles.z);
}
//checks if middle mouse button is pushed down
if(Input.GetMouseButtonDown(2))
{
//if middle mouse button is pressed 1st time set click to true and camera in front of player and save cameras position before mmb.
//if mmb is pressed again set camera back to it's position before we clicked mmb 1st time and set click to false
if(click == false)
{
click = true;
curDist = distance;
distance = distance - distance - 1;
}
else
{
distance = curDist;
click = false;
}
}
//store raycast hit
RaycastHit hit;
//if camera detects something behind or under it move camera to hitpoint so it doesn't go throught wall/floor
if(Physics.Raycast(player.position,(transform.position - player.position).normalized,out hit,(distance <= 0 ? -distance : distance)))
{
transform.position = hit.point;
}
}
}

Then the animations. I’m no good in doing animations so I had a friend of mine to do them for me. Blender is the easiest tool to get into animating 3d models,
but I’m not going into the details how to do it (to get animation script to work you will need to have your own animations done and added to character model), but more into how to make animations play in script and to do it so they play nice and in correct order.

I had some problems in making first person mode to work well so I made empty game object and made that “the player” and character model its child,
so I could change characters center point more up. That is the reason why I’m calling my gameobjects 1st child’s animations instead of players animation as animation is
attached in the model not the empty gameobject.

I’m using a lot of “if”s which is propably not the best way to do it, but I got it to work anyway.  I made different script instead of inserting animations into my movement script just to make it easier to read. Here is what I did in script.

using UnityEngine;
using System.Collections;

public class Animations : MonoBehaviour {


void Start ()
{
//calls this objects 1st childs animation and changes that animations speed. 1f is the curent speed of animation.
//You can change animations speed by what looks best
transform.GetChild(0).animation["Idle"].speed=0.8f;
//sets animations mode to loop so it continues smoothly if it is repeating itself
transform.GetChild(0).animation["Idle"].wrapMode = WrapMode.Loop;

transform.GetChild(0).animation["Walk"].speed=1;
transform.GetChild(0).animation["Walk"].wrapMode = WrapMode.Loop;

transform.GetChild(0).animation["JumpForward"].speed=2.5f;

transform.GetChild(0).animation["Run"].speed=1.5f;
transform.GetChild(0).animation["Run"].wrapMode = WrapMode.Loop;

transform.GetChild(0).animation["Landing"].speed=1;
//sets so this animation only plays once when it playes and doesnt loop
transform.GetChild(0).animation["Landing"].wrapMode = WrapMode.Once;


}
//is our character landing?
bool landing = false;

void Update () {
//sets idle to true
bool idle = true;
//we only do otehr animations if jump animation is not playing
if(!transform.GetChild(0).animation.IsPlaying("JumpForward"))
{
if(transform.GetComponent<thirdperson>().grounded)
{
//checks from anotehr script if we are in ground and we are landing and sets landing to false and plays landing animation
if(transform.GetComponent<thirdperson>().grounded  && landing == true)
{
landing = false;
transform.GetChild(0).animation.Play("Landing");
}
//checks if we press any movement keys and sets idle to false as we are moving and not doing idle animation
if(Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.Q) || Input.GetKey(KeyCode.E))
{
idle = false;
//checks if we press left shift with movement keys and plays running animation else it playes walking animation
if(Input.GetKey(KeyCode.LeftShift) && transform.GetChild(0).animation.IsPlaying("Run") == false)
{   //crossfade makes animation changing smooth
transform.GetChild(0).animation.CrossFade("Run",1f);
}
else if(transform.GetChild(0).animation.IsPlaying("Walk") == false && !Input.GetKey(KeyCode.LeftShift))
{
transform.GetChild(0).animation.CrossFade("Walk",1f);
}
}


//checks if we press space(jump) and sets idle to false and landing to true and plays jump animation
if(Input.GetKey(KeyCode.Space))
{
idle = false;
landing = true;
transform.GetChild(0).animation.CrossFade("JumpForward",1f);
}
//if idle is true aka no otehr animations are playing and idle is not playing already plays idle animation
if(idle == true && !transform.GetChild(0).animation.IsPlaying("Idle"))
{
transform.GetChild(0).animation.CrossFade("Idle",1f);
}


}
}
}
}


 

Here is a few Screen shots how it looked in my project.

Spacemanpic1

Character running and playing running animation, camera next to character.

Spacemanpic2

Camera behind, character playing idle animation.

Spacemanpic3

Character jumping, camera behind, playing jump animation

Spacemanpic4

Camera infront under character, playing idle animation, looking up with camera.

Thank you for reading. I hope this helps someone. And again as I’m still a student so if you have any better ways of doing something I’m all ears. 🙂