Creating of wave / ripple effect for buttons like in Material Design in Unity
Tags: unity3d, gamedev, programming, ui
Published: 2024-04-07 22:08:11

**Hey, everybody.** In today's short tutorial I'd like to show you how to work with the **built-in Unity UI (UGUI) event system** on the example of creating a wave effect when you click on an element (whether it's a button or Image doesn't matter), like in **Material Design**

---

**So, let's get started!**
Let's make an universal component based on **MonoBehaviour** and **IPointerClickHandler**

```csharp
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

// We need to Disallow Multiple Component for Performance Issue
[DisallowMultipleComponent]
public class UIRippleEffect : MonoBehaviour, IPointerClickHandler
{
    [Header("Ripple Setup")]
    public Sprite m_EffectSprite;     // Our Ripple Sprite
    public Color RippleColor;         // Ripple Color
    public float MaxPower = .25f;     // Max Opacity of Ripple (from 0 to 1)
    public float Duration = .25f;     // Duration of Ripple effect (in sec)

    // Our Internal Parameters
    private bool m_IsInitialized = false;  // Initialization Flag
    private RectMask2D m_RectMask;         // Rect Mask for Ripple

    // Here we Check our Effect Sprite and Setup Container
    private void Awake() {
        if (m_EffectSprite == null) {
            Debug.LogWarning("Failed to add ripple graphics. Not Ripple found.");
            return;
        }

        SetupRippleContainer();
    }

    // Here we add our mask for ripple effect
    private void SetupRippleContainer() {
        m_RectMask = gameObject.AddComponent<RectMask2D>();
        m_RectMask.padding = new Vector4(5, 5, 5, 5);
        m_RectMask.softness = new Vector2Int(20, 20);
        m_IsInitialized = true;
    }

    // This is our Click event based on IPointerClickHandler for Unity Event System
    public void OnPointerClick(PointerEventData pointerEventData) {
        if(!m_IsInitialized) return;
        GameObject rippleObject = new GameObject("_ripple_");
        LayoutElement crl = rippleObject.AddComponent<LayoutElement>();
        crl.ignoreLayout = true;

        Image currentRippleImage = rippleObject.AddComponent<Image>();
        currentRippleImage.sprite = m_EffectSprite;
        currentRippleImage.transform.SetAsLastSibling();
        currentRippleImage.transform.SetPositionAndRotation(pointerEventData.position, Quaternion.identity);
        currentRippleImage.transform.SetParent(transform);
        currentRippleImage.color = new Color(RippleColor.r, RippleColor.g, RippleColor.b, 0f);
        currentRippleImage.raycastTarget = false;
        StartCoroutine(AnimateRipple(rippleObject.GetComponent<RectTransform>(), currentRippleImage, () => {
            currentRippleImage = null;
            Destroy(rippleObject);
            StopCoroutine(nameof(AnimateRipple));
        }));
    }

    // Here we work with animation of single ripple
    private IEnumerator AnimateRipple(RectTransform rippleTransform, Image rippleImage, Action onComplete) {
        Vector2 initialSize = Vector2.zero;
        Vector2 targetSize = new Vector2(150,150);
        Color initialColor = new Color(RippleColor.r, RippleColor.g, RippleColor.b, MaxPower);
        Color targetColor = new Color(RippleColor.r, RippleColor.g, RippleColor.b, 0f);
        float elapsedTime = 0f;

        while (elapsedTime < Duration)
        {
            elapsedTime += Time.deltaTime;
            rippleTransform.sizeDelta = Vector2.Lerp(initialSize, targetSize, elapsedTime / Duration);
            rippleImage.color = Color.Lerp(initialColor, targetColor, elapsedTime / Duration);
            yield return null;
        }

        onComplete?.Invoke();
    }
}
```

So, using **standard Unity interfaces**, we created a wave effect inside the mask created on our element (this can also be replaced with a shader-based effect for better performance) when clicked. **It doesn't matter what type of element our UI will be - the main thing is that we can catch it with Raycast.**

**Do not forgot to setup your new component at UI:**
![UI Editor](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/482eqxbchha96nor62lc.png)

You can practice more by adding new effects using hover/unhover and other UIs for that. Use the **IPointerEnterHandler**, **IPointerExitHandler** interfaces to do this.

**Thanks for reading the article, I'll always be happy to discuss any projects with you and help you with your ideas on Unity.**

---

[My Discord](https://discord.gg/a7cHDtfYbv) | [My Blog](https://devsdaddy.hashnode.dev/) | [My GitHub](https://github.com/DevsDaddy) | [Buy me a Beer](https://boosty.to/devsdaddy)