GET IN TOUCH
Check what other game developers say about working with RocketBrush Studio:
Developing our game The Unliving, we decided to seek for the possibility to display in-game messages with numerical values such as damage inflicted, reward value, the number of health points restored and others, using the Particle System. We decided to do so in order to get more opportunities to customize the effects of the appearance and further behavior of such messages in future. Also, it was difficult to implement this solution using standard elements of Unity's UI-system.
Moreover, this kind of approach implies using only one instance of the Particle System for each type of the message, which provides a huge increase in productivity compared to the output of the same messages using Unity UI.
Using the shader, we display the pre-prepared texture using the correct UV coordinates. Information containing UV-coordinates is transmitted by two vertex streams to ParticleSystem using ParticleSystem.SetCustomParticleData as a List<vector4>.</vector4>
Our implementation presumes using the texture containing 10 rows and 10 columns of symbols. You can use any monospace font. This is to avoid different spacing between message characters.
Original Texture in PSD: monospaced_font.psd
Creating Vector4 for transmition to Vertex Stream
To describe the character set, we will use the structure SymbolsTextureData.
The chars array must be filled manually, by adding all the font texture symbols to it in the order starting from the top left corner.
As a result, we get a class TextRendererParticleSystem. When calling the public SpawnParticle method, one particle of the Particle System will spawn to the desired position, with the desired value, colour and size.
Particle System in Unity allows you to transfer custom data in the form of two streams List<vector4>:</vector4>
We intentionally added an extra stream with UV2 to avoid a shift in the coordinates of the streams. If this is not done, then the X and Y coordinates Custom1-vector in C# will correspond Z and W TEXCOORD0 shaders. And consecutively, Custom1.z = TEXCOORD1.x, Custom1.w = TEXCOORD1.y, which will cause a lot of inconveniences in the future.
As described earlier, we will use two Vector4 to convey the message length and UV-coordinates of the symbols. Since Vector4 contains 4 "float" type elements, then by default we can pack 4 * 4 = 16 bytes of data into it. Because our message will contain only the length of the message (two-digit number) and the coordinates of the symbols (a two-digit number for each symbol), then the "byte" type of the range (0-255) is redundant for us. Whereas using decimal places will do just fine.
"Float" precision is 6-9 symbols, which means that we can safely use 6 digits of each coordinate Vector4 and don't worry for their integrity and the accuracy of the data. Actually, we tried to pack 7, 8 and 9 characters, but "float" accuracy was not enough.
It turns out that using decimal places we will pack as many as 6 digits in each "float", unlike the standard four-byte version. Thus one Vector4 will contain 24 single-digit numbers in total.
We can transfer 2 vectors in one stream, so we will use both to transmit messages up to 23 characters long:
Custom1.xyzw - first 12 symbols of the message.
Custom2.xyzw - another 11 symbols of the message + the length of the message (the last two symbols).
For example, "Hello" message will look like this:
The coordinates of the symbols correspond to the column number and the row of the symbol's position in the texture.
In the code, packing a row into two Vector4 will look like this:
The vectors with CustomData are ready. It's time to spawn the new particle manually with needed parameters.
The first thing we need to do is to make sure that CustomData streams are activated in the particle system's Renderer settings:
To create a particle, we use the Emit() method of the ParticleSystem class.
Adding both blocks to the method SpawnParticle(), and C# part is ready: the message is packed and sent to the GPU in the form of two Vector4 in Vertex Stream. The rest is the most interesting thing: to accept this data and display it correctly.
We create the material and assign our shader to it. On the scene, we create an object with the ParticleSystem component and assign the created material. Then we adjust the particle behaviour and turn off the Play On Awake parameter. Then calling the method RendererParticleSystem.SpawnParticle() from any class or using the debugging method:
Source code, resources, and usage examples are available here.
That's it! Displaying messages using Particle System is done. We hope this solution will benefit Unity game developers. Don't forget to check out our game The Unliving where we implement this system in action!
See also: