Creating a Unity Splash Screen

This article shows how I made a simple splash screen for our app - start to finish. As is custom, here is the finished result first:

alt text

It’s well known that your team’s logo/splash screen is one of the most important steps in your app development lifecycle and can ultimately make or break your game. In fact, it’s so important that it should be one of the first things you do - even before you start developing the actual game! (/s)

In all seriousness, splash screens can be useful in helping users of your app recognize your company/team, but most users will not care how cool your splash screen is. Most users only care about one thing: time-to-play (TTP). With that in mind, it is my philosophy that splash screens should be short and simple and not overly concerned with “wow factor”.

Unity has a built-in Splash Screen API. However, it is very limited due to the fact that it runs before the engine is loaded - it only really allows fades and zooms and that’s it. A more complex logo can be run starting in your first scene or maybe when the user navigates to a credits scene. So, how might one create a simple, animated logo?

Rapid Prototyping

Unity is good for prototyping a lot of things, but animated logos on not among them. For that I personally use Microsoft PowerPoint. Before you scoff, here me out: PowerPoint is readily available (i.e. free for most people), has basic vector graphics tools (shape merge/path edit) as well as built in animation tools. This make it ideal for quickly sketching out logo designs and splash screens. You can also export anything you create as PDF, which can be imported into Inkscape and then re-exported to SVG, PNG, or whatever you like.

After messing around in PowerPoint for an hour or so, I came up with the following basic logo:

alt text

Not the best colors in the world, but gets the job done. I built the crown out of rectangles and merged them into a single shape using Merge Shapes. Merge Shapes is a really nice tool for building complex shapes out of simple ones. In this case, I merged 6 rectangles of various sizes into the top half of the crown. Still not convinced? Here is the Unity logo built in PowerPoint using Merge Shapes to add together rectangles and triangles (orange) and subtract away diamonds (green):

alt text

Anyway, back to animating the original logo:

alt text

Not too bad.

Now that I have a working prototype I’m happy with, I: - Exported the PowerPoint to PDF - Imported the PDF into Inkscape - Deleted the grey background (this is important) - Exported the logo to PNG

This is the end result (note transparent background since I deleted it earlier):

alt text

Importing into Unity

Now that I have a PNG with transparent background, I can import into Unity and use the sprite editor to slice it into multiple sprites. I can then assign each sprite to a Game Object and group them together, like this (you can’t see the text because it is behind the other 2):

alt text

Scripting the Animation

We now have the 3 pieces we need, and we can essentially follow the steps we did to animate it under PowerPoint, but using C#. There are probably multiple ways to do this. I initially considered using a particle system to generate the splash screen, since Unity’s particle system allows for easy manipulation of transparency, velocity, etc, but ultimately I was struggling maniplating the 3 pieces exactly how I wanted them and switched to just writing my own script (if anyone knows how the end result could have been easily accomplished with a particle system, let me know).

This was the script I came up with:

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

public class LogoSplash : MonoBehaviour
{
    public GameObject crown;
    public GameObject crown_base;
    public GameObject text;
    private SpriteRenderer crown_render;
    private SpriteRenderer crown_base_render;
    private SpriteRenderer text_render;

    public float fadeInSpeed      = 1;
    public float fadeOutSpeed     = 1;
    public float textFadeOutSpeed = 2;
    public float textLinger       = .5f;
    public float gapSpeed         = 5;
    public float gapSpeedDrift    = .2f;
    public float gap              = .7f;

    private float crown_initial_y;
    private bool started;

    void Start()
    {
        crown_initial_y   = crown.transform.position.y;
        crown_render      = crown.GetComponent<SpriteRenderer>();
        crown_base_render = crown_base.GetComponent<SpriteRenderer>();
        text_render       = text.GetComponent<SpriteRenderer>();
        reset();
    }

    private void reset()
    {
        started = false;

        var crown_pos = crown.transform.position;
        crown_pos.y = crown_initial_y;
        crown.transform.position = crown_pos;

        var color = crown_render.color;
        color.a = 0;
        crown_render.color = color;

        color = crown_base_render.color;
        color.a = 0;
        crown_base_render.color = color;

        color = text_render.color;
        color.a = 1;
        text_render.color = color;
        text_render.enabled = false;
    }

    // Update is called once per frame
    void Update()
    {
        if (!started) {
            started = true;
            StartCoroutine(animateLogo());
        }

#if UNITY_EDITOR
        if (Input.GetMouseButtonDown(0)) {
            reset(); //Play splash again on click
        }
#endif
    }

    private void setAlpha(SpriteRenderer r, float alpha)
    {
        var tempColor = r.color;
        tempColor.a   = alpha;
        r.color       = tempColor;
    }

    private void setY(GameObject o, float y)
    {
        var o_pos            = o.transform.position;
        o_pos.y              = y;
        o.transform.position = o_pos;
    }

    private IEnumerator animateLogo()
    {
        //Fade in
        float ztime = 0;
        while (ztime * fadeInSpeed < 1) {
            ztime += Time.deltaTime;

            setAlpha(crown_render,      Mathf.Lerp(0, 1, ztime * fadeInSpeed));
            setAlpha(crown_base_render, Mathf.Lerp(0, 1, ztime * fadeInSpeed));

            yield return null;
        }

        //Make text instally appear behind crown
        text_render.enabled = true;

        //Move top half of the crown upwards
        ztime = 0;
        while (ztime * gapSpeed < 1) {
            ztime += Time.deltaTime;

            setY(crown, Mathf.Lerp(crown_initial_y, crown_initial_y + gap, ztime * gapSpeed));

            yield return null;
        }

        //Fade out crown
        ztime = 0;
        while (ztime * fadeOutSpeed < 1) {
            ztime += Time.deltaTime;

            setY(crown, Mathf.Lerp(crown_initial_y + gap, crown_initial_y + gap * 2, ztime * gapSpeedDrift)); //Keep top half moving up, but at a much slower rate
            setAlpha(crown_render,      Mathf.Lerp(1, 0, ztime * fadeOutSpeed));
            setAlpha(crown_base_render, Mathf.Lerp(1, 0, ztime * fadeOutSpeed));

            yield return null;
        }

        //Have text wait a little
        yield return new WaitForSeconds(textLinger);

        //Fade out text
        ztime = 0;
        while (ztime * fadeOutSpeed < 1) {
            ztime += Time.deltaTime;

            setAlpha(text_render, Mathf.Lerp(1, 0, ztime * textFadeOutSpeed));

            yield return null;
        }
    }
}

I decided to use a coroutine because they allow you to code the animation procedurally from top to bottom. This is because every time Unity calls Update(), it jumps back into the coroutine at the last yield and resumes execution there… pretty neat. Mathf.Lerp is what’s used to phase the transparency or position of the various game objects between 2 values.

Here is the finished result (again):

alt text

All the speeds and timing are easily tweaked via the inspector fields for fine tuning.

Any that’s it - feel free to use this script as a template to spruce up your app intro/credits scenes with a sweet animated logo!