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

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

并为此对象添加一个脚本 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上。

相对的,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,后来觉得不需要让牌跟着手指移动,所以就放弃了。
















