Cookies info

This website uses Google cookies to analyse traffic. Information about your use of our site is shared with Google for that purpose. See details.

Unity animated character example

The example explained in this chapter is contained in the orc scene. The example implements a simple 2D character (the orc), walking on a (potentially scrollable) background. Both orc and background are native SVG files.

The orc asset is an SVG file where each body part is a separate first level group (<g> tag), each group has a well defined name (id attribute). This setup will allow to render each body part as a separate animable sprite. AmanithSVG atlas generator will perform an optimized sprite packing routine in the editor, and later on the target device (at runtime).

 
Adobe Illustrator allows to show and edit groups

Now we can proceed in the following way:

Please note that each instantiated sprite:

In order to animate each body part like a real character, we must setup:

Sprite namePivot (x)Pivot (y)
orc_head0.550.40
orc_body0.500.50
orc_dx_x5F_arm_x5F_down0.500.80
orc_dx_x5F_arm_x5F_up0.600.70
orc_dx_x5F_leg_x5F_down0.500.80
orc_dx_x5F_leg_x5F_up0.500.70
orc_sx_x5F_arm_x5F_down0.500.85
orc_sx_x5F_arm_x5F_up0.450.70
orc_sx_x5F_leg_x5F_down0.400.80
orc_sx_x5F_leg_x5F_up0.500.70

Because we are going to move the orc (actually the body part, and consequently the whole children hierarchy) programmatically by code, we must select the orc_body object and uncheck the Update transform option of the SVGSpriteLoaderBehaviour component.

 
“Update transform” must be unchecked for the body part

Now the scene is almost complete, so we can save it.

 
The scene is now complete

If we click the Play button, we see that:

 
Playing the scene

The reason is because at design time, in the editor, all sprites and their positions are valid for a (test) device resolution equal to 960 x 540. So, we want to:

In order to accomplish these tasks, we add a SVGCameraBehaviour component to the main camera (menu ComponentAdd, then Scripts subsection): this script, at each monobehaviour Update call, checks for a screen resolution change and, if this event occurs, first it sets the Camera.orthographicSize properly, then it informs all its listeners through the OnResize event.

 
The SVGCameraBehaviour script detects if screen resolution has changed

At this point, we add a script to the orc_body sprite (lets call it OrcCharacterBehaviour), that has the following input fields:

Because we are going to resize (i.e. generate at runtime) both background and orc sprites by C# code, before to implement the OrcCharacterBehaviour, we must:

Then we can select the orc_body sprite and implement the OrcCharacterBehaviour script as follow (menu ComponentAddNew script):

using UnityEngine;

public class OrcCharacterBehaviour : MonoBehaviour {

    private float BackgroundWalkingLine()
    {
        // walking line is located at ~12% of the background half height, in world coordinates
        return (Background != null) ? (-Background.WorldHeight * 0.5f) * 0.12f : 0.0f;
    }

    private void ResetOrcPos()
    {
        // move the orc at the walking line
        transform.position = new Vector3(0, BackgroundWalkingLine(), 0);
    }

    private void ResizeBackground(int newScreenWidth, int newScreenHeight)
    {
        // we want to cover the whole screen
        Pair<SVGBackgroundScaleType, int> scaleData = Background.CoverFullScreen(newScreenWidth, newScreenHeight);
        Background.ScaleAdaption = scaleData.First;
        Background.Size = scaleData.Second;
        Background.UpdateBackground(false);
    }

    private void ResizeOrcCharacter(int backgroundWidth, int backgroundHeight)
    {
        // get the orc (body) sprite loader
        SVGSpriteLoaderBehaviour spriteLoader = gameObject.GetComponent<SVGSpriteLoaderBehaviour>();
        // update/regenerate all orc sprites; NB: we want to size the orc according to
        // the background sprite (actually the background height)
        spriteLoader.UpdateSprite(true, backgroundWidth, backgroundHeight);
    }

    private void OnResize(int newScreenWidth, int newScreenHeight)
    {
        // render the background so that it covers the whole screen
        ResizeBackground(newScreenWidth, newScreenHeight);
        // update/regenerate all orc sprites according to the background dimensions
        ResizeOrcCharacter((int)Background.PixelWidth, (int)Background.PixelHeight);
        // move the orc at the world origin
        ResetOrcPos();
    }

    // Use this for initialization
    void Start()
    {
        // register ourself for receiving resize events
        Camera.OnResize += OnResize;
        // now fire a resize event by hand
        Camera.Resize(true);
    }
    
    // the scene camera
    public SVGCameraBehaviour Camera;
    // the background gameobject
    public SVGBackgroundBehaviour Background;
}

Before to play the scene, we must set OrcCharacterBehaviour properties; so we must drag&drop:

 
The OrcCharacterBehaviour script, attached to the body sprite

Now if we click play, we see that the camera viewing volume is covering the whole screen, the background sprite is resized according to the screen dimensions and the orc character has the same vertical proportion respect to the background! The next step is to move the orc along the horizontal axis, and enable the camera to follow it and scroll the background. To accomplish these tasks, the OrcCharacterBehaviour script must implement a function that derives the camera position according to the orc position:

private Vector3 CameraPosCalc(Vector3 orcPos)
{
    // set the camera according to the orc position
    Vector3 cameraPos = new Vector3(orcPos.x, 0, -10);
    float cameraWorldLeft = cameraPos.x - (Camera.WorldWidth / 2);
    float cameraWorldRight = cameraPos.x + (Camera.WorldWidth / 2);
    // make sure the camera won't go outside the background
    if (cameraWorldLeft < Background.WorldLeft)
    {
        cameraPos.x += Background.WorldLeft - cameraWorldLeft;
    }
    else
    if (cameraWorldRight > this.Background.WorldRight)
    {
        cameraPos.x -= cameraWorldRight - Background.WorldRight;
    }
    return cameraPos;
}

private void CameraPosAssign(Vector3 orcPos)
{
    // set the camera according to the orc position
    Camera.transform.position = (Camera.PixelWidth > Background.PixelWidth) ? new Vector3(0, 0, -10) : CameraPosCalc(orcPos);
}

and two functions to move the orc left or right, changing its body world position (the y coordinate will be fixed to the walking line); such functions will be called in the LateUpdate routine, if the user has pressed the mouse button:

private void Move(Vector3 delta)
{
    // move the orc
    Vector3 orcPos = transform.position + delta;
    // get the orc (body) sprite loader
    SpriteRenderer spriteRenderer = gameObject.GetComponent<SpriteRenderer>();
    float orcBodyWidth = spriteRenderer.sprite.bounds.size.x;
    // orc body pivot is located at 50% of the whole orc sprite, so we can calculate bounds easily
    float orcWorldLeft = orcPos.x - (orcBodyWidth / 2);
    float orcWorldRight = orcPos.x + (orcBodyWidth / 2);
    // make sure the orc won't go outside the background
    if (orcWorldLeft < Background.WorldLeft)
    {
        orcPos.x += (Background.WorldLeft - orcWorldLeft);
    }
    else
    if (orcWorldRight > Background.WorldRight)
    {
        orcPos.x -= (orcWorldRight - Background.WorldRight);
    }
    // update the orc position
    transform.position = orcPos;
    // set the camera according to the orc position
    this.CameraPosAssign(orcPos);
}

private void MoveLeft()
{
    // flip the orc horizontally
    this.transform.localScale = new Vector3(-1, this.transform.localScale.y, this.transform.localScale.z);
    this.Move(new Vector3(-WALKING_SPEED, 0, 0));
}

private void MoveRight()
{
    this.transform.localScale = new Vector3(1, this.transform.localScale.y, this.transform.localScale.z);
    this.Move(new Vector3(WALKING_SPEED, 0, 0));
}

void LateUpdate()
{
    if (Input.GetButton("Fire1"))
    {
        Vector3 worldMousePos = Camera.GetComponent<Camera>().ScreenToWorldPoint(Input.mousePosition);
        if (worldMousePos.x > transform.position.x)
        {
            this.MoveRight();
        }
        else
        if (worldMousePos.x < transform.position.x)
        {
            this.MoveLeft();
        }
    }
}

// the walking speed, in world coordinates
private const float WALKING_SPEED = 0.04f;

As you can see, all the code (orc and camera movement) is based on world coordinates. The source code of the final script can be found here.

In order to complete the example, we must animate the orc; we can use the “idle” and “walking” animations that we have already prepared in the Assets/Anim/OrcScene folder:

 
Animation attached to the orc body

Save the scene and click play and see the animated orc, starting with the “idle” animation; by pressing the mouse (or tapping the device screen), the orc will walk towards right or left.

Now you can have fun experimenting with it!