EasyCastleUNITY

유니티 코루틴 본문

유니티 기초

유니티 코루틴

EasyCastleT 2023. 8. 8. 13:20

https://docs.unity3d.com/kr/2021.3/Manual/Coroutines.html

 

코루틴 - Unity 매뉴얼

코루틴을 사용하면 작업을 다수의 프레임에 분산할 수 있습니다. Unity에서 코루틴은 실행을 일시 정지하고 제어를 Unity에 반환하지만 중단한 부분에서 다음 프레임을 계속할 수 있는 메서드입니

docs.unity3d.com

메서드가 아무리 길어도 1프레임안에서 실행된다. 

따라서, 시간에 따라서 메서드를 적용하려면, 평범한 메서드로는 안된다. 

for문을 했지만 1프레임이기에 한번에 밝아진다.
애니메이션이 아니라 한번에 for문이 돌아가서 한번에 밝아진다.

그러므로, for문을 여러 frame에 걸쳐서 사용해야 된다. 

즉, 렌더링을 값이 변하고 렌더링하고 다시 값이 변하면 렌더링 하는 방식을 해야된다. 

 

Update에서도 가능하지만 코루틴이 더 편리하다. 

왜 그러냐면 코루틴은 Update와 다르게 중지가 가능하기 때문이다. 

 

그러므로 코루틴을 사용하는 것이다. 

코루틴 선언 및 사용법

IEnumerator 반환타입하고, 어딘가에는 yield return 문을 작성하는 것이 코루틴의 사용법이다. 

 

코루틴: IEnumerator 반환 타입과 바디 어딘가에 포함된 yield 반환문으로 선언된 함수

 

 코루틴을 실행하려면 StartCoroutine 함수를 사용해야 한다.

 

MonoBehaviour-StartCoroutine - Unity 스크립팅 API

Starts a coroutine.

docs.unity3d.com

StartCoroutine 사용 사진

이런식으로 코루틴을 사용하려면 StartCoroutine 메서드를 사용하여,

해당 코루틴 함수의 이름을 사용하면 된다. (하지만 옛날 방법)

코루틴 실습

선언한 코루틴 메서드
코루틴 실행
코루틴이 실행된 모습

위에서 그냥 for문을 돌렸던것과 다르게 의도했던 대로 애니메이션이 실행되는 것을 알 수 있다. 

코루틴 예제 (Gameobject 이동)

코루틴이 아닌 방법으로 이동 구현

이만큼이 1 프레임, Update안에 모든 것이 1프레임 안에 실행된다.

즉 바라보고 이동하고 렌더링한다. (Update가 끝나고 렌더링) 

이런식으로 된다. 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Test
{
    public class HeroController : MonoBehaviour
    {
        private Vector3 targetPosition;
        private bool isMoveStart=false;
        // Start is called before the first frame update
        void Start()
        {

        }

        // Update is called once per frame
        void Update()
        {
            //이동시작이라면
            if (this.isMoveStart)
            {
                //방향을 바라봄
                this.transform.LookAt(targetPosition);
                //이미 바라봤으니깐 정면으로 이동 (relateTo: Self/지역좌표)
                //방향 * 속도 * 시간 
                this.transform.Translate(Vector3.forward * 1f*Time.deltaTime);
                //목표지점과 나 사이의 거리를 계산, 즉 1프레임 마다 거리를 계산 
                float distance = Vector3.Distance(this.transform.position, this.targetPosition);
                if(distance <= 0.1f)
                {
                    Debug.Log("<color=yellow>도착!</color>");
                    this.isMoveStart = false;
                }
            }
        }

        public void Move(Vector3 targetPosition)
        {
            //this.transform.position = targetPosition;

            //이동할 목표 지점을 저장
            this.targetPosition = targetPosition;
            //이동시작 
            this.isMoveStart = true;
        }
    }
}

코루틴으로 이동 구현

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Test
{
    public class HeroController : MonoBehaviour
    {
        private Vector3 targetPosition;
   
        // Start is called before the first frame update
        void Start()
        {

        }

        public void Move(Vector3 targetPosition)
        {
            //this.transform.position = targetPosition;

            //이동할 목표 지점을 저장
            this.targetPosition = targetPosition;
            StartCoroutine(this.CoMove());

        }
        private IEnumerator CoMove()
        {
            while (true)
            //무한 반복이 되어 유니티가 멈출 수도 있음
            //그러므로 yield return 필수
            {
                //방향을 바라봄
                this.transform.LookAt(targetPosition);
                //이미 바라봤으니깐 정면으로 이동 (relateTo: Self/지역좌표)
                //방향 * 속도 * 시간 
                this.transform.Translate(Vector3.forward * 1f * Time.deltaTime);
                //목표지점과 나 사이의 거리를 계산, 즉 1프레임 마다 거리를 계산 
                float distance = Vector3.Distance(this.transform.position, this.targetPosition);
                if (distance <= 0.1f)
                {
                    //도착
                    break;
                }
                yield return null; //다음 프레임 시작
            }
            Debug.Log("<color=yellow>도착!</color>");
        }
    }
}

여러번 누르면, 가속이 되는 것처럼 보인다. 그 이유는 전에 있던 코루틴이 실행이 끝나지 않았는데도, 다음에 코루틴도 실행되기 때문이다.

즉 코루틴이 중복실행되어 생기는 문제이다. 

그래서 이 문제를 해결한 코드이다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Test
{
    public class HeroController : MonoBehaviour
    {
        private Vector3 targetPosition;
        private Coroutine moveRoutine;
   
        // Start is called before the first frame update
        void Start()
        {

        }

        public void Move(Vector3 targetPosition)
        {
            //this.transform.position = targetPosition;

            //이동할 목표 지점을 저장
            this.targetPosition = targetPosition;
            if(this.moveRoutine != null)
            {
                //이미 코루틴이 실행중이다 -> 중지
                this.StopCoroutine(this.moveRoutine);
            }
            this.moveRoutine = StartCoroutine(this.CoMove());

        }
        private IEnumerator CoMove()
        {
            while (true)
            //무한 반복이 되어 유니티가 멈출 수도 있음
            //그러므로 yield return 필수
            {
                //방향을 바라봄
                this.transform.LookAt(targetPosition);
                //이미 바라봤으니깐 정면으로 이동 (relateTo: Self/지역좌표)
                //방향 * 속도 * 시간 
                this.transform.Translate(Vector3.forward * 1f * Time.deltaTime);
                //목표지점과 나 사이의 거리를 계산, 즉 1프레임 마다 거리를 계산 
                float distance = Vector3.Distance(this.transform.position, this.targetPosition);
                if (distance <= 0.1f)
                {
                    //도착
                    break;
                }
                yield return null; //다음 프레임 시작
            }
            Debug.Log("<color=yellow>도착!</color>");
        }
    }
}

제대로 동작하는 모습

'유니티 기초' 카테고리의 다른 글

간단 RPG 2  (0) 2023.08.08
간단 RPG  (0) 2023.08.08
바구니로 떨어지는 사과 받기 (여러가지 요소 추가)  (0) 2023.08.07
바구니로 떨어지는 사과 받기  (0) 2023.08.07
주말과제: 이동하고 몬스터 공격  (1) 2023.08.05