---
# System prepended metadata

title: Day 14 | 魔術方塊AR遊戲開發Part3 - 面的旋轉(上)
tags: [Unity, AR手遊]

---

# Day 14 | 魔術方塊AR遊戲開發Part3 - 面的旋轉(上)
###### tags: `Unity` `AR手遊`

在上一篇我們完成了魔術方塊的偵測，今天我們要來製作面的旋轉。
> **目錄**
> 選擇的面
> 面的旋轉

## 選擇的面
建立SelectFace():
* 需要用到ReadCube及CubeState，更新面的資訊。

```
    private CubeState cubeState;
    private ReadCube readCube;
    private int layerMask = 1 << 8;

    void Start()
    {
        readCube = FindObjectOfType<ReadCube>();
        cubeState = FindObjectOfType<CubeState>();
    }
```
* 在手指點擊螢幕時，讀取目前狀態
  * 判斷raycast是否偵測到面
  * 建立List儲存面的資訊
  * 如果偵測到面存在，選取該面
```
 if (Input.touchCount == 1)
        {          
            readCube.ReadState();

            RaycastHit hit;
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(ray, out hit, 100.0f, layerMask))
            {
                GameObject face = hit.collider.gameObject;
                
                List<List<GameObject>> cubeSides = new List<List<GameObject>>()
                {
                    cubeState.up,
                    cubeState.down,
                    cubeState.left,
                    cubeState.right,
                    cubeState.front,
                    cubeState.back
                };
                
                foreach (List<GameObject> cubeSide in cubeSides)
                {
                    if (cubeSide.Contains(face))
                    {
                        //選取該面
                        cubeState.PickUp(cubeSide);
                    }
                }
            }
        }
```
在CubeState()中新增PickUp()函式:
```
 public void PickUp(List<GameObject> cubeSide)
    {
        foreach (GameObject face in cubeSide)
        {
            if (face != cubeSide[4])
            {
                face.transform.parent.transform.parent = cubeSide[4].transform.parent;
            }
        }
    }  
```

## 面的旋轉
面的旋轉會以面的中心做為旋轉樞，因此在Scene中為每個旋轉樞新增PivotRotate()
![](https://i.imgur.com/jjZfocw.png)

Rotate()函式:
* 儲存觸控點的位置數值
* 並將需移動面存入List中
* 計算面向數值
```
    private List<GameObject> activeSide;
    private Vector3 localForward;
    private Vector3 touchRef;
    private bool dragging = false;
    
   public void Rotate(List<GameObject> side)
    {
        Touch touch = Input.GetTouch(1);
        activeSide = side;
        touchRef = touch.position;
        dragging = true;
        
        //計算面向數值
        localForward = Vector3.zero - side[4].transform.parent.transform.localPosition;
    }
```
SpinRotate()函式:
* 將旋轉數值初始化
* 並計算目前點擊點和上一次點擊點之間的差
```
 private Vector3 rotation;
 private float sensitivity = 0.4f;
 
 private void SpinSide(List<GameObject> side)
    {
        rotation = Vector3.zero;
        
        Touch touch = Input.GetTouch(1);
        Vector3 touchOffset = (touch.position - touchRef);        
    }  
```
並加入判斷面，改變旋轉數值(rotation)
```
if (side == cubeState.up)
        {
            rotation.y = (touchOffset.x + touchOffset.y) * sensitivity * 1;
        }
```
旋轉數值更新後，旋轉並紀錄點擊資訊
```
    transform.Rotate(rotation, Space.Self);
    touchRef = touch.position;
```
在Update中加入下方程式，讓SpinSide()不會重複被呼叫
```
 void Update()
    {
        if (dragging)
        {
            SpinSide(activeSide);
            if (Input.GetMouseButtonUp(0))
            {
                dragging = false;
            }
        }       
    }
```

若這時候執行畫面，會發現雖然可以旋轉面，但若在旋轉一半時，不再觸控螢幕，旋轉的面會停留在旋轉圖。

要解決這個問題，需要加上自動旋轉功能，這部分將在下ㄧ篇說明。

---
以上就是面的旋轉(上)，下一篇會是面的旋轉(下)+遊戲機制，明天見嘍!

