遊戲的機制也很簡單,就讓使用者調整每個環旋轉的角度,然後比對每個環跟前後兩個環的角度,如果差異在某個誤差值以內就視為擺放正確,而如果每個環都擺放正確就遊戲結束。
製作使用的Unity版本為5.2.2f1。
實作測試 (WebGL build,載入似乎會花一點時間),滑鼠拖曳右方小物件放到中心圓圈,接著開始調整環的角度,當角度都正確就遊戲結束。
1、環形物件
製作這個旋轉拼圖這次分為三個簡單的部分,第一個部分是環的部分,負責滑鼠拖曳旋轉;第二個部分是假的Inventory欄位,負責顯示迷你物件、滑鼠點擊拖曳;第三個部分是版面,負責接收迷你物件、檢查每個環的角度。
先從環的部分開始,這邊偷懶就直接先把圖片裁切好一環一環的圖,先製作一個簡單的Script,同樣這個部分滑鼠的點擊判斷也直接使用Unity提供的方法,這個Component之後要放在環形圖片上。
public class Ring : MonoBehaviour { //設定或取得物件的角度 public float Angle { get { return this.transform.eulerAngles.z; } set { this.transform.eulerAngles = new Vector3(0, 0, value); } } private bool isDrag; //是否拖曳中 private float preAngle; //開始拖曳前的角度 private Vector3 mousePos; //開始拖曳前的滑鼠位置 void Update() { if (isDrag) { //基本三角點 Vector2 ringWorldPos = new Vector2(this.transform.position.x, this.transform.position.y); Vector2 startWorldPos = Camera.main.ScreenToWorldPoint(mousePos); Vector2 mouseWorldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition); //計算夾角 float angle = Vector2.Angle(startWorldPos - ringWorldPos, mouseWorldPos - ringWorldPos); Vector3 cross = Vector3.Cross(startWorldPos - ringWorldPos, mouseWorldPos - ringWorldPos); if (cross.z > 0) angle = 360 - angle; //調整圖片角度 this.transform.eulerAngles = new Vector3(0, 0, preAngle - angle); } } void OnMouseDown() { if (!this.gameObject.activeSelf) return; //如果物件沒有顯示就不動作 isDrag = true; preAngle = this.transform.eulerAngles.z; //紀錄開始拖曳前的角度 mousePos = Input.mousePosition; //紀錄開始拖曳前的滑鼠位置 } void OnMouseUp() { if (!this.gameObject.activeSelf) return; //如果物件沒有顯示就不動作 isDrag = false; } //環形圖片物件的顯示/關閉 public void ActiveRing(bool active) { this.gameObject.SetActive(active); if (active) this.transform.eulerAngles = new Vector3(0, 0, Random.Range(0, 360)); //亂數調整角度 } }
接著把每張環形圖片放到場景中,每一個環形圖片的物件都加上Circle Collider 2D及上方自己做的Component,接著稍稍調整每個環形圖片的Z軸座標,如圖片形成一個塔型,這邊假設原始完整的圖角度的Z都是0度。
為何如此做的原因,因為使用OnMouseDown()、OnMouseUp()去判斷,而如果Collider重疊在同一個位置上,判斷上會出問題。形成塔型,小的在前面,大的在後面,這樣點擊小的環就不會觸動大的環。
2、欄位
雖然說是製作欄位,但是這邊其實只是個擺放小圖的位置,直接把(9宮格總和15)的物件拿來修改一點就可以直接使用了。
public class Unit : MonoBehaviour { public int index; //這個物件代表的環的位置, 由外到內 0~n private Vector3 startPosition; //起始位置 private bool isDrag; //是否拖曳中 void Start () { startPosition = this.transform.position; } void Update () { if (isDrag) { Vector2 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition); this.transform.position = mousePos; } } void OnMouseDown() { StopAllCoroutines(); //停止移動的Coroutine isDrag = true; } void OnMouseUp() { isDrag = false; //檢查是否放在板子上 bool isOnBoard = false; RaycastHit2D[] hits = Physics2D.RaycastAll(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero); foreach (RaycastHit2D hit in hits) { //檢查所有的Hit,只取Tag是Board的物件 if (hit.transform.tag == "Board") { //放到板子上,用SendMessage呼叫啟動第幾個環 hit.transform.SendMessage("ActiveRing", index); this.gameObject.SetActive(false); //關閉這個小物件顯示 isOnBoard = true; } } //如果滑鼠座標沒有接觸到板子,就送回起始位置 if(!isOnBoard) StartCoroutine("ReturnPosition", startPosition); } //隨意做的回原位方法 IEnumerator ReturnPosition(Vector3 pos) { Vector3 target = new Vector3(pos.x, pos.y, this.transform.position.z); while (true) { this.transform.position = Vector3.MoveTowards(this.transform.position, target, 10f * Time.deltaTime); if (this.transform.position == target) break; yield return null; } } }
接著在場景中隨意放四個空白方塊當作欄位,接著把小圖放進每個位置中,我這邊是直接用原本環的圖片縮小Scale來用,每個小圖加上Box Collider 2D以及自己做的Component即可,這邊放上Unit後要記得設定每個物件代表的Index數值。
這邊就不用管Z軸位置了,因為到時候放在板子上是用RayCast去抓所有的,不過這邊要注意圖片的SortingOrder,稍微調整前後避免跟底圖、欄位方塊圖同個SortingOrder造成顯示問題。
3、板子
最後就是板子了,這邊就簡單地接收是否顯示某個環,然後用Update()來一直檢查每個環的角度是否都正確。
public class Board : MonoBehaviour { public Ring[] ringList; //由外到內 void Update() { CheckRingsAngle(); } public void ActiveRing(int index) { if (index < 0 || index >= ringList.Length) return; ringList[index].ActiveRing(true); } private void CheckRingsAngle() { //假設每個環正確角度都是0度,比對跟正確角度的差異,在誤差範圍內就視為正確 bool isGameOver = true; for (int i = 0; i < ringList.Length; ++i) { if (ringList[i].gameObject.activeSelf) { float ringAngle = ringList[i].Angle; float offset = Mathf.Abs(0 - ringAngle); if (offset > 180) offset = 360 - offset; if (offset > 5) isGameOver = false; //超過+-5度就沒有擺放正確 } else { isGameOver = false; } } if (isGameOver) { Debug.Log("GameOver"); } } }
接著在背景圖這邊,製作一個空的物件並加上Circle Collider 2D以及Board這兩個Component,把這個Collider大小調整到跟背景圖空缺的大小差不多大小,Z軸位置不用調整,記得這個Collider物件的Tag設定為Board好讓Unit去判斷。
最放把RingList放上去,由最外環到最中心的順序,放完後記得把每個環顯示都關閉。
這樣整體就算完成了,再調整小細節或是製作介面就差不多了。
這個版本不用在乎效能,所以我每個環都是獨立一張圖片,這個其實會造成一些問題,像是如果環的數量越多圖片的數量也就越多這是一點,另外一點就是環是中空的,就算把這些圖集合成一張Atlas,中間透明部分就會占用空間。
如果有任何問題歡迎提出。
4 comments:
我想請問一下,這可以在unity3d文件裡做出來嗎?還是一定要在2D文件裡?
2D的只要轉Z軸就可以了,3D當然也可以,多轉兩個軸而已,看畫面要怎樣呈現而已,可以做成像星球儀一樣,每一個環都可以自由旋轉
請問一下可以分享大大的專案嗎?
有些INSPECTOR的設定不太清楚
Post a Comment