December 7, 2022

578 words 3 mins read

Unity Easy Menu Animation!

Unity Easy Menu Animation!

Everything is indeed better when animated. Especially the menus. I bet you feel the same when you create the first few versions of your passion project and it just feels cold. Something is missing. Maybe it’s the missing menu animations! This is why started to use this trick across all my projects. It is perfect enough for some basic menu animations.

The animation itself is done with a free tool called LeanTween which is awesome. Lightweight enough, easy to use enough.

We will create some extension methods for our GameObject transform. In Unity, you can move and animate a GameObject via this transform component, plus it’s directly accessible, so it seems a good candidate for our purposes. If you don’t know about extension methods, don’t worry it’s dead simple. We will just add a few new methods on our Transform classed instances so, in the end, the whole animation will be a piece of cake to use!

After we add some extensions to our Transform class we should be able to accomplish all the menu appearings and disappearings as simply as adding 3 lines!

// MyAwesomeMenu.cs

private void Start(){
    // Instantly hide the menu offscreen to the right
    transform.HideInstant(direction: Vector3.right);

    // Animate the menu to it's local center position from offscreen
    transform.Show();
}

// Call this Method to destroy the menu
private void HideMenu(){
    // Animate the menu offscreen to left
    // And after the animation is finished, destroy it!
    transform.Hide(
        onComplete: ()=> Destroy(gameObject);
        direction: Vector3.left,
    )
}

I figured out that probably 4 methods on the Transform Class could fulfill my needs. I need to instantly hide/show the menus and hide/show them delayed, with animations. Probably it would be useful to detect the end of animations with a callback! Oh and by the way, hide just means in every context, that the code moves the menu to the side of the canvas. So we need the canvas as well in the code. (If you have multiple canvases it might need some modifications).

As I mentioned we need extension methods. How we do them is we create static public methods in a static class and mark its first parameter with this keyword.

Let’s see how it’s working under the hood!

Note This code should only work if you have LeanTween installed!
using System;
using System.Collections;
using UnityEngine;

public static class MenuAnimationExtensions
{
	private static LeanTweenType _tweenType = LeanTweenType.easeOutQuad;
	private static float _tweenTime = .5f;

	private static float _width =>
        CanvasRect.rect.width == 0 ?
        Screen.width : CanvasRect.rect.width;
	private static float _height =>
        CanvasRect.rect.height == 0 ?
        Screen.height : CanvasRect.rect.height;

	private static RectTransform _canvasRect;
	private static RectTransform CanvasRect {
        get {
            if (_canvasRect == null)
            {
                _canvasRect = GameObject
                                .FindObjectOfType<Canvas>()
                                .GetComponent<RectTransform>();
            }
            return _canvasRect;
        }
    }

	public static void HideInstant(
        this Transform transform,
        Vector3 direction = default)
	{
		if (direction == default)
            direction = Vector3.right;
		transform.localPosition = direction.DenormalizeVector();
	}

	public static void ShowInstant(
        this Transform transform) =>
        transform.localPosition = Vector3.zero;

	public static void Show(
        this Transform transform,
        Action onComplete = null)
	{
		LeanTween.moveLocal(
            transform.gameObject,
            Vector3.zero,
            _tweenTime)
                .setEase(_tweenType)
                .setOnComplete(() => onComplete?.Invoke());
	}

	public static void Hide(
        this Transform transform,
        Action onComplete = null,
        Vector3 direction = default)
	{
		if (direction == default) direction = Vector3.left;
		LeanTween.moveLocal(
            transform.gameObject,
            direction.DenormalizeVector(),
            _tweenTime)
                .setEase(_tweenType)
                .setOnComplete(() => onComplete?.Invoke());
	}

	private static Vector3 DenormalizeVector(this Vector3 vector3)
	{
		if (vector3 == Vector3.up || vector3 == Vector3.down)
            return vector3 * _height;
		if (vector3 == Vector3.left || vector3 == Vector3.right)
            return vector3 * _width;
		return Vector3.right * _width;
	}
}