Unity IceBomb Skill제작

2021. 7. 16. 00:31Unity/VR

이번에는 기존에 만든 스킬말고 또 하나를 제작하기로 했다.

이름은 IceBomb으로 스킬을 실행하고 손을 높에 올린뒤 땅을 찍으면 보고 있는 곳에서 얼음 기둥이 솟아 나온다.

이 스킬을 만드는데 가장 핵심적인 요소들은 Raycast와 OntriggerEnter두가지 이다. 한번 천천히 보도록 하자.


로직

전편들에 의해서 스킬관리 시스템이 구축이 되었으므로 일단 IceBomb이라는 스킬명을 가진 객체가 하나 필요하다.

이 곳에서는 많은 역할을 하지않고 바로 Logic을 담당하는 객체를 생성해주는 역할을 한다.

public class IceBomb : MonoBehaviour        //raycast곡선변경 알아보기
{
    private Transform EyeTrans;
    public GameObject IceBomb_Logic_Collider;
    // Start is called before the first frame update
    void Start()
    {
        EyeTrans = GameObject.Find("EyeTrans").GetComponent<Transform>();

        GameObject icebomb_Collider = Instantiate(IceBomb_Logic_Collider);
        icebomb_Collider.transform.SetParent(EyeTrans,false);
    }
}

 

여기서 나오는 EyeTrans는 눈 위치에 존재하는 객체이며 IceBomb같은 손을 올리는 동작이 눈라인 까지 올라가야 할 때 쓸 객체이다. 이 객체의 위치로 Logic객체가 instantiate된다.

 

먼저 로직객체의 인스펙터를 보자.

보면 boxcollider가 제일 눈에 띄인다. 이 것은 두손이 눈앞에 모두 위치 했는지 검사 해주기 위한 트리거 박스인 것이다. 그렇기에 is Trigger도 체크 해 주었다.

 

이 로직의 구조는 다음과 같다.

두손이 눈앞 라인 까지 올라 갔는지 검사 → 충분히 손의 위치가 내려갔음을 검사 → Raycast를 통한 위치 초기화 후 생성

다음 코드를 보자

public class IceBomb_Logic_Col : MonoBehaviour
{
    private bool leftReady;
    private bool rightReady;

    private Transform leftPos;
    private Transform rightPos;

    private GameObject EyeTrans;

    public GameObject IceBomb;
    public GameObject TempTrans;

    float handPosY;
    
 void Start()
    {
        leftPos = GameObject.Find("LeftHandTrans").GetComponent<Transform>();
        rightPos = GameObject.Find("RightHandTrans").GetComponent<Transform>();

        EyeTrans = GameObject.Find("EyeTrans");
        TempTrans = GameObject.Find("TempTrans");    
    }

초기화 부분이다.

먼저 두손의 위치를 알아야 손을 내리는 동작에서 기준점을 잡을 수 있기 때문에 두손의 위치를 초기화 해주었다.(left,right Trans) 여기서 저장되는 기준점이 handposY이다.

두손이 내가 원하는 만큼 올라갔는지를 저장해주는 변수 Ready를 만들어 주었다.

EyeTrans는 Raycast를 눈위치에서 쓰기위해 가져온 변수이다. 

TempTrans는 뒤에 후술하겠다.

 

 private void OnTriggerEnter(Collider other)
        {
            if (other.gameObject.name == "MagicPrepare_L")
            {
                leftReady = true;
                SetHandPos();
            }
            if (other.gameObject.name == "MagicPrepare_R")
            {
                rightReady = true;
                SetHandPos();
            }
        }

Trigger함수이다. 왼손 오른속 각각 트리거에 발동 되면 Ready변수에 true를 저장해주고 setHandpos함수를 실행 해준다.

 

 void SetHandPos()
        {
            if (leftReady == true && rightReady == true)
            {
                handPosY = rightPos.position.y;
            }
        }

두개다 true가 되었을때 함수가 실행이되면 handPosY로 기준점을 잠아주는 함수이다. 이때 굳이 두손모두로 기준점을 잡지않고 오른손만으로 기준점을 잡았다.(y좌표만 필요)

 

다음코드는 나머지 로직들을 다 포함하는 코드이다.

 void Update()
        {
            if (leftPos.position.y < handPosY - 0.7f && rightPos.position.y < handPosY - 0.7f && use == false)
            {
                use = true;

                RaycastHit hit;
                //float distance = 1000f;
                int layerMask = 1 << LayerMask.NameToLayer("Terrain");
                if (Physics.Raycast(EyeTrans.transform.position, EyeTrans.transform.forward, out hit, Mathf.Infinity, layerMask))
                {
                    Vector3 insPos = hit.point;
                    TempTrans.transform.position = insPos;

                    Instantiate(IceBomb, TempTrans.transform);

                    Debug.Log("발동");
                    Destroy(this.gameObject);       
                }
            }
        }
  if (leftPos.position.y < handPosY - 0.7f && rightPos.position.y < handPosY - 0.7f && use == false)

맨첫줄 if문은 손이 충분히 내려갔는지의 대한 검사를 진행한다. 여기서는 두손다 검사를 진행하며 기준점보다 y좌표가 0.7더 내려가면 if문을 통과한다.

 

 int layerMask = 1 << LayerMask.NameToLayer("Terrain");

layerMask를 설정하는 방법이다. 먼저 자신이 사용할 Layer를 할당하는게 먼저이다.

이렇게 설정된 레이어는 위 문법으로 layerMask를 초기화 해 줄수있다. * layerMask의 초기화는 2진수로 진행 된다.

 

RaycastHit hit;
if (Physics.Raycast(EyeTrans.transform.position, EyeTrans.transform.forward, out hit, Mathf.Infinity, layerMask))
 {
	Vector3 insPos = hit.point;
	TempTrans.transform.position = insPos;
 
	Instantiate(IceBomb, TempTrans.transform);

	Debug.Log("발동");
	Destroy(this.gameObject);       
 }

Raycast사용법이다. 위에서 초기화한EyeTrans를 통해 광선을 쏴주고 광선의 hitPoint를 통해 스킬이펙트를 instantiate해준다. 그리고 발동이 완료되면 삭제된다.

여기서 봐야할 부분이 두가지가 존재하는데 첫번째는 광선의 로컬화이다.

EyeTrans.transform.forward
Vector3.forwad

이 두코드의 차이점은 무엇일까 둘다 forward이긴하지만 바로 global좌표기준이냐 local좌표기준이냐가 가장 큰 차이다. 우리가 만들 로직은 눈의 position과 rotation에 따라 광선의 방향이 다양하게 바뀌어야 하기 때문에 local이 필수적인 것이다.

 

두번째는 hit.point는 그자체로 transform을 대신해서 사용될 수 없다는 것이다. instantiate는 두번째 인자에 Transform이 들어가는데 따지고 보면 Transform안에는 position,rotation,scale값이 들어있다. position만 있는 것이 아니다. 그래서 이걸 간단하게 처리하기위해 TempTrans를 만들고 그것의 Transform정보를 받아 hitPoint에서 position정보만 붙여 넣어준다. 그리고 그 정보를통해 instantiate해주는 것이다.

 

실제 사용

 

 

위에서 설명한 모든 기능이 구현된 실제 사용 영상이다.