[Unity][개발#2]단일동작 블록, 블록코딩,이동,회전

2021. 4. 29. 14:24PROJECT/VR 소프트웨어 코딩교육 플랫폼

이전 작업물

 

단일행동을 가지고 있는 블록을 오른쪽 블록(Panel Main Loop)에 넣기 성공

 

단일 동작에는 Z축으로 1이동(블록에는 X로 되어있네요), 좌우 90도 회전, 180도 회전으로 규명했습니다.

 

구조설명 :

Z축으로 1이동 스크립트명 : FunctionMove.cs
회전 스크립트명 : FunctionRotate.cs

Panel Main Loop 에 블록이 들어왔음을 인식하는 스크립트명 : player_holder.cs

 

player_hloder.cs

public IEnumerator Go() //스타트버튼을 눌렀을때 실행되는 코루틴함수
    {
        yield return new WaitForSeconds(1f); //1초 딜레이
        Blocks = GameObject.FindGameObjectWithTag("section0"); //Panel Main Loop에 접근
        int nSize = Blocks.transform.childCount; //Panel Main Loop의 자식들 갯수
        for (int i = 0; i < nSize; i++)
        {
            GameObject Child = Blocks.transform.GetChild(i).gameObject; // Panel Main Loop의 자식오브젝트 저장
            //블록의 함수들 다 불러오기
            FunctionMove FunctionMove = Child.GetComponent<FunctionMove>();  //자식오브젝트의 FunctionMove 함수 불러오기
            FunctionRotate FunctionRotate = Child.GetComponent<FunctionRotate>();  //자식오브젝트의 FunctionRotate 함수 불러오기
           
            //차례로 함수들이 있는지 체크하기
            if (FunctionMove)   //FunctionMove 즉, 이동 블록일때 실행
            {
                yield return StartCoroutine(FunctionMove.MoveZ()); //z축 1 이동
            }
            else if (!FunctionMove && FunctionRotate) // 회전 블록 일때 실행
            {
                if (Child.tag == "Rotate_R") //오른쪽 회전
                    yield return StartCoroutine(FunctionRotate.RightRotate());
                else if (Child.tag == "Rotate_L") //왼쪽 회전
                    yield return StartCoroutine(FunctionRotate.LeftRotate());
                else if (Child.tag == "Rotate_B") //오른쪽 회전
                    yield return StartCoroutine(FunctionRotate.BackRotate());
            }
        }
    }
    
     public void OnClickButton() //스타트 버튼 눌렀을때 실행
    {
        StartCoroutine(Go());
    }
}

Panel Main Loop는 section0이라는 태그를 가지고 있다.

단일행동이 Panel Main Loop의 하위 오브젝트로 들어가게 되고 하위 오브젝트들이 각 스크립트 즉,

FunctionMove와 FunctionRotate가 있는지를 확인한다. 

있으면 차례로 실행한다.

 

Z축으로 1 이동

public IEnumerator MoveZ()
    {
        GameObject player;
        player = GameObject.FindGameObjectWithTag("Player");
        player.transform.Translate(0, 0, 1);
        yield return new WaitForSeconds(1);
    }

 

 

z축으로 1이동이 원할하게 잘 된다.

 

회전

    public IEnumerator RightRotate() //오른쪽으로 90도 회전
    {
        GameObject player;
        player = GameObject.FindGameObjectWithTag("Player");
        player.transform.Rotate(0, 90, 0);
        yield return new WaitForSeconds(1);
     }
     public IEnumerator LeftRotate() //왼쪽으로 90도 회전
    {
        GameObject player;
        player = GameObject.FindGameObjectWithTag("Player");
        player.transform.Rotate(0, -90, 0);
        yield return new WaitForSeconds(1);
    }
    public IEnumerator BackRotate() //180도 회전
    {
        GameObject player;
        player = GameObject.FindGameObjectWithTag("Player");
        player.transform.Rotate(0, 180, 0);
        yield return new WaitForSeconds(1);
    }

 

회전까지 잘된다

 

추가적으로 움직임이 끊어지다보니 Time.delta.Time을 이용하여 부드럽게 움직이고 싶었다.

 

public IEnumerator MoveZ()
    {
        GameObject player;
        player = GameObject.FindGameObjectWithTag("Player");
        player.transform.Translate(0, 0, 1 * Time.delta.Time);
        yield return new WaitForSeconds(1);
    }

 

자료를 찾아보다 보니 코루틴에서는  Time.delta.Time을 그냥 이용할 수 없음을 확인했고, 다른 대책으로 while문을 사용하면 해결할 수 있음을 확인했다.

 

public IEnumerator MoveZ()
    {
        GameObject player;
        player = GameObject.FindGameObjectWithTag("Player");
        StartPos = player.transform.position;
        while (true)
        {
            player.transform.Translate(0, 0, 1 * Time.deltaTime);

            if (Mathf.Abs(player.transform.position.z - StartPos.z) >= 1 || Mathf.Abs(player.transform.position.x - StartPos.x) >= 1 || Mathf.Abs(player.transform.position.y - StartPos.y) >= 1)
            {
                break;
            }
            yield return null;
        }
    }

 

while(1)로 무한루프를 만들어주고 if문을 통해 1만큼 움직일 경우 break되도록하였다.

위 gif기준은 z축으로만 먼저 오른쪽 혹은 왼쪽으로 회전하고 그 상태에서 앞으로 갈 수 도 있기때문에 x,y,z 모든 방향으로의 거리를 측정하여 if문안으로 넣었다.

 

문제는 회전이다.

  public IEnumerator RightRotate() ///오른쪽으로 90도 회전
    {
        // 애니메이션 회전을 넣고 싶어서 만드는중 아직 못만듬
        GameObject player;
        player = GameObject.FindGameObjectWithTag("Player");
        Debug.Log(StartPos.y);
        Debug.Log("3");
        while (true)
        {
            player.transform.Rotate(0, 90 * Time.deltaTime, 0);
            /
            Debug.Log(player.transform.rotation.eulerAngles.y);
            if ((player.transform.rotation.eulerAngles.y <= 0.1 && player.transform.rotation.eulerAngles.y >= 359.9))
            {
                // (player.transform.rotation.eulerAngles.y <= 270.05 && player.transform.rotation.eulerAngles.y >= 269.95) || (player.transform.rotation.eulerAngles.y <= 0.05 && player.transform.rotation.eulerAngles.y >= 359.95) || (player.transform.rotation.eulerAngles.y <= 90.05 && player.transform.rotation.eulerAngles.y >= 89.95) || (player.transform.rotation.eulerAngles.y <= 180.05 && player.transform.rotation.eulerAngles.y >= 185.95)
                break;
            }
            yield return null;
        }
    }

 

인스펙터창에는 왼쪽으로 회전은 -90도지만 내부적으로는 0에서 270도로 이동으로 된다. 그래서

처음의 회전에서 나중 회전을 뺐을때 90도를 넘어가면 break를 걸라고 했으나, 0-270는 크기가 270도라서 이와 같은 조건은 쓸 수 없다.

 

그래서 현재 회전을 애니메이션으로 움직이는거는 킵한 상태이다. 어차피 나중에 애니메이션 컨트롤러를 따로 쓸거기 때문이다.

 

 

현재 단일동작은 이렇게 구현되었다.

보안해야 할 점 : 회전 애니메이션 추가, 실제 모델링기반으로 재정의