Unity typewriter effect made easy with Unity. I wanted to use this effect in another little project I was doing, and made this little project for learning purposes. Just started learning Unity myself. I tried a few times in the past but never used Unity for more than a few weeks at the time before I uninstalled it. So you will find a uninstall article on my page dating a few years back.
The background is just a image with the C64 colours. Once you got that in place, and your sprites like the cursor and font. Everything is included in the GitHub repository, or you can download the assets. Check out the links. It will not open a pop-up spam hell.
A blank “canvas”
The scripts
I made two scripts in this project. One to get the cursor blinking and one to control the scene. I start with the SceneManager.
SceneManager.cs
The variable declarations got nothing special.
[SerializeField]
public GameObject letter;
[SerializeField]
public GameObject cursor;
[SerializeField]
public AudioClip typeSound;
[SerializeField]
public AudioClip endOfLineSound; // not used in the terminal example
[SerializeField]
public Sprite[] characters;
Vector2 startPos = new Vector2(0f, 3.6f);
Vector2 pos;
readonly float lineSpacing = 0.5f;
readonly float charSpacing = 0.35f;
char[] convertedString;
GameObject spriteChar;
GameObject spriteCursor;
AudioSource audioPlayer;
readonly string[] data = { "terminal or", "typewriter effect", " ", "check out description", "for source code" };
Start function
The start function is straight forward. Get the starting position, get the audio source component and start the PrintOut function. Or coroutine since I used
void Start()
{
pos = startPos;
audioPlayer = GetComponent<AudioSource>();
StartCoroutine(PrintOut());
}
SelectChar
If you checked out my previous Retro Demo code, you will recognize this function. Is it an easy way to convert from chars to ASCII code (integer).
int SelectChar(char selChar)
{
return selChar - 97;
}
Just convert from char to int and subtract 97 since the ASCII code for the letter a is 97. b is 98, c is 99 and so on. The letters in my font sprite sheet start with 0. That is the reason I need to convert the chars to numbers starting with
PrintOut function
IEnumerator PrintOut()
{
int charToPrint;
Vector2 lastPos = new Vector2(0, 0);
spriteCursor = Instantiate(cursor, pos, Quaternion.identity);
foreach (string singleLine in data) // Handle each line
{
convertedString = singleLine.ToCharArray();
pos.x = ((singleLine.Length * charSpacing) / 2) * -1;
foreach (char singleChar in singleLine) // Handle each character
{
charToPrint = SelectChar(singleChar);
if (charToPrint >= 0 && charToPrint <= 26) // only accept lower cap characters
{
spriteChar = Instantiate(letter, pos, Quaternion.identity);
spriteChar.GetComponent<SpriteRenderer>().sprite = characters[charToPrint];
spriteCursor.transform.position = pos + new Vector2(charSpacing, 0);
audioPlayer.PlayOneShot(typeSound, 1f);
yield return new WaitForSeconds(Random.Range(0.05f, 0.35f)); // Min/max random delay between characters
}
pos.x += charSpacing; // testnumber for char width + char spacing
}
lastPos = pos;
pos.y -= lineSpacing;
pos.x = startPos.x;
}
spriteCursor.transform.position = lastPos;
}
First I instantiate the cursor before cycling thru each line and cycle thru each word in that line. That’s why there are nested
convertedString = singleLine.ToCharArray();
pos.x = ((singleLine.Length * charSpacing) / 2) * -1;
Then we need to calculate the x position where to start printing that line. Each character has a fixed size including the space between them. So I multiply the numbers of characters with the character space and divide it by 2 to get the middle of the line. Because of the Unity coordinate, origo being in the middle, we multiply with -1 to get a negative number. So the line starts at the left side of the screen.
charToPrint = SelectChar(singleChar);
if (charToPrint >= 0 && charToPrint <= 26) // only accept lower cap characters
{
spriteChar = Instantiate(letter, pos, Quaternion.identity);
spriteChar.GetComponent<SpriteRenderer>().sprite = characters[charToPrint];
spriteCursor.transform.position = pos + new Vector2(charSpacing, 0);
audioPlayer.PlayOneShot(typeSound, 1f);
yield return new WaitForSeconds(Random.Range(0.05f, 0.35f)); // Min/max random delay between characters
}
pos.x += charSpacing;
Inside the inner
Then we instantiate the character, select the correct sprite using SpriteRenderer, and move the cursor to the next position. Next line we play a typing sound. At the end of the if statement we pause for a random time between 0.05s to 0.35s to simulate human writing this text. At the
lastPos = pos;
pos.y -= lineSpacing;
pos.x = startPos.x;
After each line is written I copy the position into lastPos. Move the y position to the next line and reset the x position to start a new line.
Not so blank canvas
The blinking cursor
I have a separate script to make the cursor blink. This can probably be done in an easier way. Here is my script.
public class Cursor : MonoBehaviour
{
private IEnumerator coroutine;
private Renderer rend;
void Start()
{
rend = GetComponent<SpriteRenderer>();
coroutine = BlinkCursor(0.25f);
StartCoroutine(coroutine);
}
private IEnumerator BlinkCursor(float waitTime)
{
while (true)
{
yield return new WaitForSeconds(waitTime);
if (rend.enabled == true)
{
rend.enabled = false;
}
else
{
rend.enabled = true;
}
}
}
}
This script should also be straight forward. The BlinkCursor just go in an eternal loop checking if the renderer is enabled, and turn it off. And vice versa. It does this every 0.25 seconds.
Unity Typewriter YouTube example video
That is how I made this Unity typewriter effect. Enjoy the code if you want.