- Home /
How to make letters fall from sky like snow?
Hi,
Unity newbie here.
I am working on a VR project for school in which the user will enter the mind of a poet and sort of depicts the creative process. I am trying to make the letters fall from the sky, as the poem is about snow and in another scene they see snow falling.
I know how to use the particle system, but do I have to make several independent particles with letters as materials and then put them into the scene? I think this may put a huge strain on Unity. Is there another way to do this/best way to do this? Do I need to script this?
Thanks!
Just create a texture sheet material with each letter in their individual tile, then in the particle system, enable Texture Sheet Animation module, enter the correct XY tile division, and change the value type of Frame over Time from curve to “random between constants”, the range should be zero to 25 if you have 26 letters/tiles.
Answer by Happeloy · Nov 16, 2018 at 08:56 PM
Here's a way you could do it. Just create a script named LetterRain.cs and add this to it, then add that to a gameobject in your scene. This is far from perfect, but it works and does what I believe you are looking for. You can tweak the startPosMax and starPosMin, and probably set those positions based on the current camera location.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LetterRain : MonoBehaviour {
private List<GameObject> letterPool; // Creating a pool of objects is the most memory efficient way to handle things like this. No new memory will be allocated during runtime.
private List<GameObject> lettersAlive; //A list of the letters currently alive.
private int poolSize; //Poolsize, will be set based on lenght of poem.
public string poem = "This is a very nice litle poem. It is about letters raining";
public Vector3 startPosMax = new Vector3(10, 10, 3);
public Vector3 startPosMin = new Vector3(-10, 10, -3);
public float lettersPerSecond = 10; //How many letters per second. Max is one per frame, see how it's implemented in update.
public float aliveTime = 2f; //How long each letter should live.
private float timer = 0; //Timer to keep track of when to add new letters.
// Use this for initialization
void Start () {
CreatePool();
}
private void CreatePool(){
poolSize = poem.Length;
letterPool = new List<GameObject>();
lettersAlive = new List<GameObject>();
for (int i = 0; i < poolSize; i++){
GameObject particle = new GameObject(); //Create particle
particle.AddComponent<TextMesh>().text = poem[i].ToString(); //Let particle letter be the next one in the poem
particle.AddComponent<Rigidbody>(); //Add a rigidbody to the particle
particle.transform.parent = transform; //Set the particle as a child of this gameobject, mostly to keep hierarchy cleaner.
particle.AddComponent<Letter>(); //Add component Letter to keep track of how long it's been alive. This class is written in the same file, check below.
particle.SetActive(false); //Turn it off for now.
letterPool.Add(particle); //Add to pool
}
}
void Update () {
timer += Time.deltaTime;
if(timer > (1/lettersPerSecond)){ //Doing it this way means the maximum letters per secons will be one each frame.
timer = 0; //reset timer
ShowNewParticle();
}
for (int i = lettersAlive.Count - 1; i >= 0; i--){ //Check if any particles should die. Iterating backwards is always best when removing stuff from a list during iteration.
if(lettersAlive[i].GetComponent<Letter>().timeAlive > aliveTime){ //This isn't very good, GetComponent shouldn't be called in an update. Figure out a better way to do this if it impacts performance. Perhaps with event from Letter?
ReturnLetterToPool(i);
}
}
}
/// <summary>
/// Returns the letter to pool.
/// </summary>
/// <param name="index">Index in alive-pool</param>
private void ReturnLetterToPool(int index){
lettersAlive[index].SetActive(false);
letterPool.Add(lettersAlive[index]);
lettersAlive.RemoveAt(index);
}
/// <summary>
/// Shows the new particle. Select random from letterPool, remove from that pool and add to alive pool
/// </summary>
private void ShowNewParticle(){
if(letterPool.Count == 0){
Debug.Log("Pool is empty. Chose a longer poem or less particles per second.");
return;
}
int index = Random.Range(0, letterPool.Count-1);
letterPool[index].transform.position = new Vector3(Random.Range(startPosMin.x, startPosMax.x), Random.Range(startPosMin.y, startPosMax.y), Random.Range(startPosMin.z, startPosMax.z)); //Randomize position
letterPool[index].SetActive(true);
letterPool[index].GetComponent<Rigidbody>().velocity = Vector3.zero;
letterPool[index].GetComponent<Letter>().timeAlive = 0;
lettersAlive.Add(letterPool[index]);
letterPool.RemoveAt(index);
}
}
/// <summary>
/// Component added to each particle. Normally this would probably be in a seperate file, but I kept it in the same file for ease of use.
/// Should be pretty self explanatory
/// </summary>
public class Letter : MonoBehaviour{
public float timeAlive = 0;
private Vector3 rotations = new Vector3(3, 12, 50);
private void OnEnable()
{
transform.eulerAngles = new Vector3(Random.Range(0, 360), Random.Range(0, 360), Random.Range(0, 360));
}
private void Update()
{
timeAlive += Time.deltaTime;
transform.Rotate(rotations * Time.deltaTime);
}
}
WOW! Thank you SO much! It works!
Do you have any idea how I could manipulate the text of the letters that is falling? Like change the color, size, font, etc?
Thanks again so much!
I'm glad it works for you! Yes of course, if you look at line 30, where I add the textmesh component, you could edit that any way you want. If you add a 3d-text to your scene, you'll see what options you have on that. You said you're a newbie, but it shouldn't be too hard to figure out how to change the color. If you can't figure it out, let me know and I'll help you.
I tried for like an hour but couldnt figure it out. BUT i want to figure it out. Could you give me some hints to change color and make the letters 3D?
Your answer
Follow this Question
Related Questions
Change TextMesh text in script 1 Answer
Display Emojis using its HTML code in a text 1 Answer
Is it possible to make textMeshProGui text to toggle with the unity editor gizmo's button? 0 Answers
TextMeshPro smallcaps option is converting "i" to "İ" not "I", why ? 1 Answer
Wrap text textmesh 0 Answers