Unity UGUI 翻转卡牌

最近遇到一个问题,要在 UGUI 下面制作一个卡牌翻转的效果。要求一个卡牌有正反两个面,初始时正面在前,当点击卡牌时,翻转到反面在前。
最开始的直接反应就是像 3D 对象那样直接对 transform.rotation.y 做一个旋转180度的动画即可,后来才意识到 UGUI 里面的 Image 等控件都是 2D 的,只有一个面,而且 UGUI 默认的材质也都是只显示一个面的,而 3D 对象是立体的,自然有正反两个面。所以,对于 UGUI 来说,如果使用默认材质,是无法做到一个对象让其有正反两个面的。
我们可以在 Unity Editor 里面很容易的验证这一点。对 UGUI 的 2D 对象 rotation.y 旋转 180 度,等价于 localScale.y = -1 所带来的效果。

那么现在我们怎样实现 UGUI 元素的翻牌效果呢?我想到了两个解决思路:

  1. 自己创建一个材质,这个材质支持双面显示,可能还要配合改变 Camera 的显示选项;
  2. 完成在 UGUI 默认配置的基础上,在一个 GameObject root 下面挂载两个子 GameObject,front 和 back,分别代表正面和反面对象,初始化时 front 显示,back 隐藏,然后对 root 的 rotation.y 做旋转动画,当旋转到90度时,此时 root 垂直于屏幕,把 front 隐藏,而把 back 显示出来,然后再回旋90度,这个时候 back 如同翻牌效果一样显示出来了。

这两个思路应该都可以解决问题,第二种方法实现起来比较简单,也不需要更改 UGUI 的默认材质。我按照第二种方案实现了一下,效果如下。

代码很简单,只有几行代码即可,我使用了 DoTween 来做动画。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;

public class FlipCard : MonoBehaviour
{
    public Transform front;
    public Transform back;

    void Start()
    {
        PlayFlipAnimaiton();
    }


    void PlayFlipAnimaiton()
    {
        front.gameObject.SetActive(true);
        back.gameObject.SetActive(false);

        Sequence seq = DOTween.Sequence();
        
        // step1: rotate to 90 degree
        var rotate = this.transform.DORotate(new Vector3(0, 90, 0), 5f);
        seq.Append(rotate);

        // step2: disable front , show back
        seq.AppendCallback(() =>
        {
            front.gameObject.SetActive(false);
            back.gameObject.SetActive(true);
        });
        
        // step3: reverse rotate to 0 degree
        var reverseRotate = this.transform.DORotate(new Vector3(0, 0, 0), 5f);
        seq.Append(reverseRotate);
    }
    
}