前言

简单的范例如下,按住某张牌,往上拉约一张牌的高度,代表打出该张牌。

unity卡牌模板_Unity


麻将牌游戏对象新增一个 Sprite 对象,用于显示麻将牌内容,命名为〝aTile〞。然后为其添加一个 Box 碰撞器。添加方式如下:

unity卡牌模板_Unity_02


并为此对象添加一个脚本 Tile.cs。完整程序代码如下:

using UnityEngine;
public class Tile : MonoBehaviour {
    public MainScene controller;
    
    private int m_id = 1;
    private Collider2D m_collider2D;
    //--------------------------------------------------------
    void Start ()
    {
        m_collider2D = this.GetComponent<Collider2D>();
    }
    //--------------------------------------------------------
    void Update ()
    {
        if (Input.GetButtonDown("Fire1"))
        {
            Vector3 pos = Input.mousePosition;
            Vector3 wp = Camera.main.ScreenToWorldPoint(pos);
            Vector2 touchPos = new Vector2(wp.x, wp.y);
            if (m_collider2D.OverlapPoint(touchPos))
            {
                controller.SelectIndex(m_id);  //  回传被选到了
            }
        }   
    }
    //--------------------------------------------------------
    public void SetSprite(int id, int spriteNo)
    {
        m_id = id;
        Sprite image = Resources.Load<Sprite>("Tile/" + spriteNo);
        this.GetComponent<SpriteRenderer>().sprite = image;
    }        
    //--------------------------------------------------------
}

在上一期 《Sprite 的触点处理》中只判断是否被点击,若是则做翻牌的处理。但在此就无法如此简单了,被点到后必须通知某程序(在此例为 MainScene),由其决定如何处置,所以在编辑器中要将 controller 指定到 Main Camera,因为 MainScene 脚本挂在 Main Camera上。

unity卡牌模板_Touch_03


相对的,MainScene 中要有一个 public 的 SelectIndex() 方法来接收 Tile 传回的值,代表哪张牌被选到。

if (m_collider2D.OverlapPoint(touchPos))
{
    controller.SelectIndex(m_id);
}

上面的代码段就是做判断,确认被点到,就呼叫 controller.SelectIndex(),将此牌的 id 传回去。MainScene 中的 SelectIndex 方法很简单,只是记录哪张牌被点到而已。如下:

public void SelectIndex(int index)
{
    m_nSelect = index;
}

MainScene 完整的代码如下:

using UnityEngine;
using UnityEngine.UI;

public class MainScene : MonoBehaviour {
    public Tile aTile;
    public Text labMsg;

    private Tile[] m_aryTiles = new Tile[2];
    private int m_nSelect;
    private Vector2 m_startTouchPos;
    //--------------------------------------------------------
    void Start ()
    {
        aTile.gameObject.SetActive(false);
        for(int i=0; i<2; i++)
        {
            float x = -0.37f + i * 0.74f;
            Vector3 pos = new Vector3(x, -2.5f, 0.0f);
            m_aryTiles[i] = Instantiate(aTile) as Tile;
            m_aryTiles[i].SetSprite(i, 12 + i);
            m_aryTiles[i].transform.position = pos;
            m_aryTiles[i].gameObject.SetActive(true);
        }
        m_nSelect = -1;
    }
    //--------------------------------------------------------
    void Update ()
    {
         if (m_nSelect < 0) return;  // 未选到任何一张牌

        if (Input.touchCount == 1)
        {
            Touch t = Input.GetTouch(0);
            if ( t.phase == TouchPhase.Began )
            {
                m_startTouchPos = Camera.main.ScreenToWorldPoint(t.position);
            }
            else if ( t.phase == TouchPhase.Ended )
            {
                Vector3 pos = Camera.main.ScreenToWorldPoint(t.position);
                float yMove = Mathf.Abs(pos.y - m_startTouchPos.y);
                if ( yMove > 1.5f )
                {
                    pos.z = 0.0f;
                    labMsg.text = m_nSelect.ToString() + ", " + pos.ToString();
                    m_aryTiles[m_nSelect].transform.position = pos;
                    
                    m_nSelect = -1;   // 移开了
                }
            }
        }
    }
    //--------------------------------------------------------
 }

宣告一个 Tile[] 用于纪录有几张牌,此例只建立两张牌。

private Tile[] m_aryTiles = new Tile[2];

然后通过 Instantiate 创建出所要的麻将牌对象,用 SetSprite() 方法来设定 id 及图像编号,此例中 12 为二筒、13为三筒。

m_aryTiles[i] = Instantiate(aTile) as Tile;
 m_aryTiles[i].SetSprite(i, 12 + i);

最后将 m_nSelect 起始值设为 -1,代表无任何牌被选到。

屏幕被触击时,任何游戏对象都可以进行判断。每张牌都会侦测碰触点是否在自己的碰撞器范围内,当然 MainScene 也可以判断。

当开始触摸时,TouchPhase 的状态为 TouchPhase.Began,此时要记录触摸点的坐标位置,用m_startTouchPos 纪录。当手指移开屏幕时,状态为 TouchPhase.Ended,将此时离开点的坐标值与开始触摸时的坐标值相比,若移动距离超过某范围(此例是往上移动 1.5f)就代表打出此牌。

当手指移开时,记得将 m_nSelect 设为 -1,就不会再继续侦测 Touch。

结语

TouchPhase 总共有五种状态,此例只用了 Began 及 Ended,原本以为会用到 Moved,后来觉得不需要让牌跟着手指移动,所以就放弃了。