Advertisement

Dynamic Avatars in Unity

by

In this tutorial I'll show you how to create a simple character-customization menu, and how to save the necessary data for use in a game. We'll create a player avatar (an airplane in this example), customize it by adding optional attachments or changing color, save the data, load another level, and recreate it from the saved data. This effectively allows you to customize it outside the game world; in a menu system, so it's available anywhere you want, even after quitting and restarting the game.


Click the buttons to change your avatar.

You'll need a basic understanding of Unity for this. If you want to model your own objects, you can do so too, but the 3d-model used in this tutorial are also available for you to download here. The entire project, in case you want to look something up, can also be downloaded here.


Setting Up the Project

Create a new Unity-project. We'll need 2 levels in there, so we can switch between them. Save the current scene and name it "levelMenu". Then open the build settings (file -- build settings) and press "add current scene". This is necessary so that we can later access it and load to it directly.

Then create a new scene and name it "levelGame", and add it to the build settings too. Now the basic scenes should be present, allowing us to fill them up with things.

cc01

Creating the Plane

We'll use an airplane as "character" for now (this is much easier to handle than a full-on human :). Get the 3d-assets (here they are again) and copy them into your asset-folder. Create a cube, and swap out the mesh for the plane-mesh. Create a new material and add it to the airplane. Finally, drag the plane into the project-folder to make a prefab out of it.


Avatar Customization GUI

In order to customize the plane we'll need some kind of interface.

Create a new scripts and name it plane.js. Put the following code into it

function OnGUI()
{
    if(Application.loadedLevel == 0)
    {
	if(GUI.Button(Rect(10, 10, 100, 50), "Red"))
	{	
	    renderer.material.color = Color.red;
	}

	if(GUI.Button(Rect(10, 70, 100, 50), "Blue"))
	{
	    renderer.material.color = Color.blue;
	}

	if(GUI.Button(Rect(10, 130, 100, 50), "Green"))
	{
	    renderer.material.color = Color.green;
	}
    }
}

Add the script to the plane-prefab, and put a plane in the scene. Move the camera so that it looks at the plane, so that we can see the changes we'll make to it. When you run it, if should look like this:

cc05

If you press a button, the color of the plane should change. You can try it out in this build: DOWNLOAD SOURCE PROJECT 1.

The if(Application.loadedLevel == 0)-bracket disables the button if another level except the menu (level 0) is loaded. This is useful for managing gui-systems.


Loading the Next Level

In your "levelGame", put another plane, and make the camera look at it. If you try it out, nothing should happen yet, as we haven't added the adaptation to the saved data yet. While you're in there, make the scene different from the "levelMenu"-scene, so that telling both apart is easier. Giving it a different background-color in the Main Camera should suffice.

Now go back to the "levelMenu"-level, everything will be done from there. Open the plane-script and add the following lines to it, right underneath the code for the buttons:

function OnGUI()
{
    if(GUI.Button(Rect(120, 10, 100, 50), "Load Level"))
    {
	Application.LoadLevel(1);
    }
}

Try it out! A new button should appear, and if you press it, it will load the new level. The plane in the other level will have the "basic" look though. The next step will be to adapt it once the level has been loaded.


Saving the Avatar Data

Unity comes with "PlayerPrefs"-functions. These allow to save and load data on any device it is used. First we'll save the color of the plane, and then see about re-creating it on the second loaded level.

Adapt the load-level-button to look like this:

if(GUI.Button(Rect(120, 10, 100, 50), "Load Level"))
{
    PlayerPrefs.SetFloat("planeColorR", renderer.material.color.r);
    PlayerPrefs.SetFloat("planeColorG", renderer.material.color.g);
    PlayerPrefs.SetFloat("planeColorB", renderer.material.color.b);

    Application.LoadLevel(1);
}

When clicking the "load level"-button, the game will now save the red, green and blue-components of the colors as three separate values. Red will be saved as "planeColorR", green will be saved as "planeColorG", and blue is saved as "planeColorB". These values are saved outside the game on the computer (or any device this will run on, like an iOS-device, Android or Ouya), and can be retrieved at any point at any time.


Adapting the Player's Avatar to the Saved Data

Not add this code to the script:

function Start()
{
    renderer.material.color.r = PlayerPrefs.GetFloat("planeColorR");
    renderer.material.color.g = PlayerPrefs.GetFloat("planeColorG");
    renderer.material.color.b = PlayerPrefs.GetFloat("planeColorB");
}

When the level is being started, the plane will get the saved color-data, and apply it to the plane. If you try it out now, and it appears black, that's because no data has been saved yet! In order to prevent this, you can set it to only adapt in the second level:

if(Application.loadedLevel == 1)
{
    PlayerPrefs.SetFloat("planeColorR", renderer.material.color.r);
    PlayerPrefs.SetFloat("planeColorG", renderer.material.color.g);
    PlayerPrefs.SetFloat("planeColorB", renderer.material.color.b);
}

Accessories

Let's do some other stuff to customize the plane! In the 3d-files you will also find some bombs. We'll make it so those can be put beneath the plane and saved too.

Start by creating a bomb-object. Make a cube and swap out the mesh for the bomb-mesh. Add a grey color, and then parent the missile to the plane and center it beneath it. It should look like this:

cc04

If you press "apply" while the plane is in the inspector, the new bombs will be added to the prefab, and the plane in the "levelGame"-level will be automatically updated too.

Now add these lines to the script:

var bombs: GameObject;
function Start()
{
    bombs.SetActive(false);
    if(PlayerPrefs.GetInt("bombs") == 1)
    bombs.SetActive(true);
}
function OnGUI()
{
    if(GUI.Button(Rect(10, 190, 100, 50), "Bombs"))
    {
        bombs.SetActive(!bombs.activeSelf);
    }
}
function LoadLevel()
{
    if(bombs.ActiveSelf())
    {
        PlayerPrefs.SetInt("planeBombs", 1);
    }
    else
    {
        PlayerPrefs.SetInt("planeBombs", 0);
    }
}

Before trying it out, remember to drag the "bomb"-object in the scene into the "bombs"-slot in the plane, otherwise it will not work.

cc03

The entire script should look like this:

#pragma strict

var bombs: GameObject;

function Start()
{
    if(Application.loadedLevel == 1)
    {
        renderer.material.color.r = PlayerPrefs.GetFloat("planeColorR");
        renderer.material.color.g = PlayerPrefs.GetFloat("planeColorG");
        renderer.material.color.b = PlayerPrefs.GetFloat("planeColorB");
    }

    bombs.SetActive(false);
    if(PlayerPrefs.GetInt("planeBombs") == 1)
    {
        bombs.SetActive(true);
    }
}

function OnGUI()
{
    if(Application.loadedLevel == 0)
    {
        if(GUI.Button(Rect(10, 10, 100, 50), "Red"))
        {    
            renderer.material.color = Color.red;
        }

        if(GUI.Button(Rect(10, 70, 100, 50), "Blue"))
        {
            renderer.material.color = Color.blue;
        }

        if(GUI.Button(Rect(10, 130, 100, 50), "Green"))
        {
            renderer.material.color = Color.green;
        }

        if(GUI.Button(Rect(10, 190, 100, 50), "Bombs"))
        {
            bombs.SetActive(!bombs.activeSelf);
        }

        if(GUI.Button(Rect(120, 10, 100, 50), "Load Level"))
        {
            PlayerPrefs.SetFloat("planeColorR", renderer.material.color.r);
            PlayerPrefs.SetFloat("planeColorG", renderer.material.color.g);
            PlayerPrefs.SetFloat("planeColorB", renderer.material.color.b);

            if(bombs.activeSelf)
            {
                PlayerPrefs.SetInt("planeBombs", 1);
            }
            else
            {
                PlayerPrefs.SetInt("planeBombs", 0);
            }

            Application.LoadLevel(1);
        }
    }
    else
    {
        if(GUI.Button(Rect(10, 10, 100, 50), "Load Menu"))
        {    
            Application.LoadLevel(0);
        }
    }
}

When you press the "load level"-button now, the state of the bombs is saved. When starting the new level, the bombs are then either deactivated or activated, depending on the saved state. You can try it out in this build: DOWNLOAD SOURCE PROJECT 2.


Conclusion

We're done! Now you know how to

  • customize a "character"
  • save the data to any device the game runs on
  • recreate the character with the saved data

This customized player "character" will then be available at any point during the game.

We've only used a simple airplane as our example "character", but it can be anything. Boats, car, humans, animals, even simple things, like cubes or spheres, could be used to represent your players in your games. This can be also used to customize other items, like weapons, vehicles, customes, hair-styles or even decarations in a vast persistent home. Go wild!

Advertisement