遊戲的機制也很簡單,就讓使用者調整每個環旋轉的角度,然後比對每個環跟前後兩個環的角度,如果差異在某個誤差值以內就視為擺放正確,而如果每個環都擺放正確就遊戲結束。
製作使用的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