물리엔진이 적용된 주사위의 가장 큰 문제는 값이 뭐가 나왔는지 알 수 없다는 것입니다 ㅡ,.ㅡ;
주사위의 회전을 물리엔진이 담당하니 어떤 값이 위로 올라왔는지 확인할 수가 없죠.
이 문제를 해결하려면 맨 위로 올라온 오브젝트를 찾아 값을 체크하는 방법뿐입니다.
이 '맨 위로 올라온 오브젝트'가 무언인가에 따라 다르죠.
몇 가지 방법이 있습니다.
(1) 매쉬를 각 면 단위로 분리한다. (3D경우)
(2) 특정 위치의 점이나 면의 위치값을 비교한다.
(3) 위치 확인용 모델을 추가한다.
여기서 가장 간단한 방법은 (3)번입니다.
주사위에 들어간 숫자가 너무 많다면 (1)번이 더 좋을 수도 있습니다.
이렇게 오브젝트를 구성하였으면 구성한 오브젝트의 위치를 비교하여 가장 위에 있는 오브젝트를 숫자로 변환하여 사용하면 됩니다.
전 유니티를 이용하여 구현하겠습니다.
방법은 (3)번 방법입니다.
주사위로 쓸 모델을 가지고 와서 물리엔진을 적용합니다.
주사위가 좀 튕겨야 더 랜덤한 숫자가 나올 테니 탄성도 적용합니다.
(참고 : [Unity] 탄성 적용하기)
이제 주사위 오브젝트의 숫자에 해당하는 면에 오브젝트를 추가합니다.
이때 숫자 면에 오브젝트가 붙지 않아도 상관없습니다.
제가 사용할 주사위는 4면체로 삼각뿔 쪽에 적힌 숫자를 읽는 주사위입니다.
이 확인용 오브젝트는 '충돌'이 적용되면 안 되기 때문에 충돌체(Collider)는 추가하지 않습니다.
눈에 보여도 안 되기 때문에 메쉬를 'None'이나 'Transparency 1'로 변경해 줍니다.
'Transparency 1'는 .png 파일입니다.
아래 파일을 받아서 넣어 주시면 됩니다.
이 파일을 임포트 시킨 후 텍스쳐를 이 택스쳐를 선택하거나 'Shader'속성을 'Transparent/Cutout/Soft Edge Unlit'로 선택 합니다.
모든 확인용 오브젝트를 투명 처리되면 아래 처럼 보입니다.
이 포스팅의 툴은 '유니티'이므로 유니티 스크립트를 만들겠습니다.
제가 사용한 모델은 4면체지만 다른 다면체도 사용할 수 있도록 확인용 오브젝트를 유동적으로 받기 위해 확인용 오브젝트는 배열로 작성합니다.
///<summary>
/// 숫자 리스트.
///</summary>
public GameObject[] goNumList;
각각의 확인용 오브젝트의 위치를 검사하여 가장 높은 위치에 있는 오브젝트의 인덱스를 선택 값으로 취급합니다.
여기서는 설정된 오브젝트만큼 돌려서 세로 위치 값(y)을 체크합니다.
SelectNum = 0;
m_fTemp = 0;
for (int i = 0; i < m_ListCount; i++)
{
m_goTemp = goNumList[i];
if (m_goTemp.transform.position.y > m_fTemp)
{
m_fTemp = m_goTemp.transform.position.y;
SelectNum = i;
}
}
1번 줄 : 가장 높은 높이 값을 가지고 있는 숫자 값입니다.
2번 줄 : 가장 높은 높이 값을 저장해둘 변수입니다.
7번 줄 : 기존에 저장된 값보다 높은 위치를 가졌을 때
높이 값과 숫자를 저장합니다.
'SelectNum'가 나온 주사위의 값입니다.
전체 코드입니다.
using UnityEngine;
using System.Collections;
public class Dice_Rotate : MonoBehaviour
{
private TextMesh m_tmText;
///<summary>
/// 숫자 리스트.
///</summary>
public GameObject[] goNumList;
private int m_ListCount;
private GameObject m_goTemp;
private float m_fTemp;
public int SelectNum;
// Use this for initialization
void Start ()
{
m_ListCount = goNumList.Length;
//화면에 표시할 3D Text.
m_tmText = (TextMesh)GameObject.Find("NewText").GetComponent(typeof(TextMesh));
//다이스가 굴러갑니다~,
m_tmText.text = "다이스가 굴러갑니다~,";
RandomRotate();
}
// Update is called once per frame
void Update ()
{
//마우스가 내려갔는지?
if (true == Input.GetMouseButtonDown(0))
{
//내려갔다.
RandomRotate();
}
GetSelectNum();
}
private void RandomRotate()
{
//초기 위치 설정.
transform.position = new Vector3(Random.Range(9,12), Random.Range(8, 9), Random.Range(-11, -6));
//랜덤한 각도만큼 회전.
transform.Rotate(new Vector3(Random.Range(1, 100), Random.Range(1, 100), Random.Range(1, 100)), Space.Self);
}
private void GetSelectNum()
{
SelectNum = 0;
m_fTemp = 0;
for (int i = 0; i < m_ListCount; i++)
{
m_goTemp = goNumList[i];
if (m_goTemp.transform.position.y > m_fTemp)
{
m_fTemp = m_goTemp.transform.position.y;
SelectNum = i;
}
}
m_tmText.text = "선택 : " + (SelectNum + 1);
}
}
이 코드에서는 값 확인을 위해 '3D Text'를 이용하여 출력하는 코드가 포함되어 있습니다.
만약 직접 이 코드를 사용할 경우 출력용 코드들은 지우셔야 합니다.
테스트를 위해서 오브젝트의 위치를 리셋하는 코드를 이 스크립트 안에 넣었습니다.
사용할 때는 'RandomRotate()'를 지우고 'GetSelectNum()'만 호출해서 사용하시면 됩니다.
'2-2-1.'에서 작성한 스크립트를 우리가 '2-1-2.'에서 만들어둔 오브젝트에 적용합니다.
그러면 오브젝트 속성에 스크립트를 보시면 'Go Num List'라는 항목이 생긴 것을 알 수 있습니다.
'Size'를 원하는 크기로 넣습니다.
(저는 4면체이므로 4를 넣었습니다.)
이제 1번에 해당하는 오브젝트를 'Element 0'에 연결합니다.
이렇게 모든 숫자에 해당하는 오브젝트를 순서대로 넣습니다.
테스트해봅시다.
화면에 선택된 값이 나오는 것을 볼 수 있습니다.
프로젝트 전체 소스 : 테스트에 사용한 프로젝트 다운 받기(클릭)
최익필 님께서 추가해주신 방법이 추가된 프로젝트입니다.(5.0 이상)
( 참고 : Unity Community - Dice - Which face is up? )
3D 작업을 해본 적이 없어서 어떤 프로세스로 3D 작업을 하는지는 모르겠지만 아마도 주사위값을 가지고 오는 것 빼고는 디자이너가 할 듯 한데 말이죠.
그런 건 사치인 우리 같은 사람들은 그냥 작업하면 됩니다 ㅎㅎㅎㅎ