fullstack

[Unity3D] Coroutine

Unity

- Delay 만들기


일정 주기마다 실행되는 함수를 만들고 싶을때, 다음과 같이 만들 수 있다.


1
2
3
4
5
6
7
8
9
10
11
float accTime = 0;
float delay = 1;
 
void Update() {
    accTime += Time.deltaTime;
    if(accTime > delay)
    {
        func();
        accTime = 0;
    }
}



이는 Update문 안에서 accTime을 매 프레임마다 더해주고 accTime과 delay를 비교해서 처리하게되는데 Coroutine을 사용하면 더 간단하고 좋은 성능으로 만들 수 있다.


1
2
3
4
5
6
IEnumerator delay()
{
    yield return new WaitForSeconds(1f);
    func();
    StartCoroutine(delay());
}





- Coroutine


일반 함수는 호출하면 반환값을 반환하기 전에 실행이 완료되어 시간의 경과와 함께 일련의 이벤트에는 사용할 수 없다. 이는 Coroutine을 사용하면 편리하게 구현할 수 있다.

Coroutine은 실행을 중지하여 Unity에 제어권을 돌려주고, 계속할 때는 다음 프레임에서 중지한 곳부터 실행을 계속할 수 있는 기능이다.

즉 Coroutine을 사용하면 시간을 두거나 순차적으로 기능을 실행할 때 매우 유용하다.


가장 기본적인 Coroutine함수는 다음과 같다.


1
2
3
4
5
6
IEnumerator func()
{
    // event.
    yield return null;
    // event2.
}



Coroutine은 StartCoroutine 함수를 사용하여 실행하며, IEnumerator 형식을 반환값으로 가지고 yield return 구문을 포함하고 있어야 한다.

yield return 구문에는 일정시간은 기다리는 new WaitForSeconds(float) 이 가장 많이 쓰이며 다른 Coroutine이 끝날 때가지 대기하거나 웹 통신 작업이 끝날 때까지 대기하는 등 다양한 구문이 있다.


 yield return null

  다음 프레임까지 대기

 yield return new WaitForSeconds(float)

  지정된 초만큼 대기

 yield return new WaitForFixedUpdate()

  다음 물리 프레임까지 대기

 yield return new WaitForEndOfFrame()

  모든 렌더링 작업이 끝날 때까지 대기

 yield return StartCoroutine(string)

  다른 코루틴이 끝날 때까지 대기

 yield return new WWW(string)

  웹 통신 작업이 끝날 때까지 대기

 yield return new AsyncOperation

  비동기 작업이 끝날 때까지 대기(씬로딩)


[Unity3D] 이동, 회전, 크기변경 정리

Unity

Unity에서 GameObject의 이동, 회전, 크기변경을 하기 위한 방법에 대해 알아보자.

 

 

 

- 이동

 

1
transform.position = new Vector3(x, y, z);

 
가장 간단한 방법으로 GameObject의 위치를 직접 지정해 줄 수 있다.
 
 
1
transform.Translate(speed, 00);

 
현재 위치를 기준으로 x축으로 움직이고 싶다면 위와같이 쓸 수 있다.
 
 
1
transform.position = Vector3.MoveTowards(transform.position, target.position, speed);

 

taget 오브젝트에게 일정하게 이동하고 싶다면 위와같이 MoveToward를 쓰면 된다.

 

 

 

- 회전

 

1
transform.rotation = Quaternion.identity;

회전또한 간단하게 회전값을 지정해 줄 수 있다.
Quaternion 값으로 지정해야하며 Quaternion.identity는 기본값인 (0,0,0)을 나타낸다.
Quaternion에 대한 정보는 링크를 참조하자. ( http://docs.unity3d.com/ScriptReference/Quaternion.html )
 
 
1
transform.Rotate(Vector3.up, speed, Space.World);

Rotate를 사용하여 현재 회전값을 기준으로 회전시킬 수 있다.
매개변수에는 축, 각도, 기준좌표계가 들어간다.
 
 
1
transform.LookAt(target)

target의 방향 정보가있고 이 위치를 향해 바라보고 싶다면 위와같이 LookAt을 사용할 수 있다.
하지만 이는 한번에 회전하므로 천천히 target을 향해 회전하도록 하고 싶다면 아래와 같이 RotateTowards를 사용한다.
 
1
transform.rotation = Quaternion.RotateTowards(transform.rotation, lookRotation, speed);

 
 
- 크기
 
1
transform.localScale = new Vector3(111);

원하는 크기로 변경하고 싶다면 위와같이 사용할 수 있다.
 
 
1
transform.localScale += new Vector3(100);

현재 크기를 기준으로 x축으로 늘리고 싶다면 위와같이 사용할 수 있다.
 
 
 
- Time.deltatime
 
GameObject를 연속적으로 이동하거나 회전시킬때 Update문에서 구현하게 된다.
하지만 이는 매 프레임마다 호출되는 Update 특성 상 PC의 성능에 따라 프레임횟수가 다르기 때문에 문제가 발생한다.
즉, 같은 속도값을 주더라도 좋은PC와 안좋은PC에서 움직이는 속도가 다르게된다.
 
이는 속도값에 Time.deltatime을 곱해 해결할 수 있다.
Time.deltatime을 간단히 설명하자면 전프레임이 완료되기까지 걸린 시간으로 성능이 느릴수록 값이 커지는 특성이 있다.
 
그럼 speed값을 정의할때 다음과 같이 쓰면 되겠다.
 
1
float speed = 10 * Time.deltaTime;

 

 

[Unity3D] GameObject 생성과 삭제. Instantiate와 Destroy

Unity

Unity에서 Instantiate와 Destroy 함수를 이용하여 GameObject를 생성하고 삭제할 수 있다.

 

 

 

- Instantiate

 

Instantiate는 다음과 같이 사용할 수 있다.

 

1
Instantiate(original, position, rotation);

 

 

위와 같이 3가지의 매개변수를 가진다.

original - 생성할 GameObject로 현재 Scene에 있는 GameObject나 Prefab을 지정할 수 있다.

position - Vector3변수로 생성될 GameObject의 위치를 지정한다.

rotation - Quaternion변수로 생성될 GameObject의 회전값을 지정한다. 이변이 없는 한 원래 GameObject의 회전값 즉, original.transform.rotation으로 지정한다.

 

만약 총알을 생성하여 발사한다면 다음과 같이 바로 Rigidbody로 캐스팅하여 사용할 수 있다.

 

1
2
3
Rigidbody clone;
clone = Instantiate(bullet, gun.transform.position, bullet.transform.rotation) as Rigidbody;
clone.AddForce(transform.forward * 5000);
 

 

 

 

- Destroy

 

Destroy는 다음과 같이 사용할 수 있다.

 

1
Destroy(obj);

 


매개변수에 삭제할 Object를 넣어주기만 하면 된다. 
만약 일정 딜레이를 준 후에 Object를 삭제하고 싶다면 다음과 같이 매개변수를 추가해주면 된다.

1
Destroy(obj, time);

 

time은 float 변수로 시간을 지정해 주기만 하면 된다.
 
 
 
- Instantiate와 Destroy의 문제점
 
예를 들어 총알과 같이 수없이 생성되고 삭제되는 GameObject가 있다고 하면 이를 계속 Instantiate와 Destory로 생성하고 삭제한다면 아무래도 시스템에 많은 부담을 줄 것이다. 따라서 이럴 경우에는 오브젝트들을 Pool로 관리하여 재사용할 수 있도록 관리해 주는 것이 좋다
 

 

[Unity3D] Prefab

Unity

Unity에서 같은 GameObject가 여러개 필요하다면 Prefab을 이용해 효율적으로 GameObject를 관리할 수 있다.


- Prefab 생성 방법



위와같이 Project 창에서 Create - Prefab을 선택해 Prefab을 생성할 수 있다. 



그럼 다음과 같이 Prefab이 생성되는데 여기에 Prefab화 하고 싶은 GameObject를 드래그 앤 드롭하면 된다. 

이 과정이 번거롭다면 GameObject를 바로 Project 창에 드래그 앤 드롭하면 Prefab이 자동으로 생성된다.

그럼 만들어진 Prefab을 Scene이나 Hierarchy에 드래그 앤 드롭하여 마음껏 사용할 수 있다.



Prefab화 되어진 GameObject는 위와같이 파란색 글씨로 표시되는데 연결을 끊고 싶다면 위 메뉴중 GameObject - Break Prefab Instance를 선택하면 된다.




- Prefab을 사용해야 하는 이유



Prefab을 사용하면 그림과 같이 한번에 여러개의 GameObject들을 한번에 수정할 수 있다. 만약 이를 일일이 하나씩 모두 해줘야 한다면 매우 번거로울 것이다.

또한 GameObject를 생성할때 Prefab을 바로 생성해서 사용할 수 있기 때문에 생성할 GameObject가 Scene에 없어도 사용할 수 있다.


[Unity3D] 충돌처리. Trigger와 Collision

Unity

- 충돌처리를 위한 조건


우선 충돌이 일어나기 위해서는 두 GameObject가 모두 Collider를 가지고 있어야 하며 둘 중 하나는 Rigidbody를 가지고 있어야 한다.

두 GameObject중 하나만 움직인다면 움직이는 GameObject가 Rigidbody를 가지고 있어야 한다.



위 그림은 Collider가 잘 보이게 하기 위해 GameObject보다 크기를 약간 키워 보았다. 위에서 보이는 초록색 부분이 Collider로 실제로 충돌을 감지하는 영역이다.

Unity에서 제공하는 Object들에는 기본적으로 Collider가 들어가 있으며 Box Collider, Sphere Collider, Capsule Collider 등이 있다. 만약 다른 Model을 불러와 작업한다면 Model에 알맞게 Collider를 설정해 주어야 올바른 충돌처리를 할 수 있다.




- Trigger


Trigger는 GameObject간의 물리적 연산을 하지 않고 충돌을 감지할 수 있다. 즉, 두 GameObject가 접촉했을때 서로 튕겨 나가지않고 그냥 통과하게 된다.

Trigger를 쓰기 위해서는 해당 Collider의 Is Trigger 항목을 체크해야 한다.

다음으로 스크립트에서 함수로 충돌 이벤트를 처리할 수 있다.


1
2
3
void OnTriggerEnter(Collider col) { }
void OnTriggerStay(Collider col) { }
void OnTriggerExit(Collider col) { }



다음과 같이 Enter, Stay, Exit 3가지 버전의 OnTrigger 함수를 만들 수 있다.
3가지 함수는 다음과 같은 특징을 나타낸다.
Enter - 충돌이 시작되는 순간 호출
Stay - 충돌이 되고있을 때 매 프레임마다 호출
Exit - 충돌이 끝날 때 호출

함수의 파라메터로 Collider 객체가 들어오며 col을 이용해 충돌한 GameObject에 대한 처리를 할 수 있다. 



- Collision

Collision은 Trigger와 다르게 물리적인 연산을 하며 충돌을 감지한다.
주의할 것은 Rigidbody의 Kinematic 속성이 꺼져 있어야 충돌이 발생할 수 있다.

1
2
3
void OnCollisionEnter(Collision col) { }
void OnCollisionStay(Collision col) { }
void OnCollisionExit(Collision col) { }



Trigger와 동일하게 3가지 함수를 만들 수 있으며 특징 또한 동일하다.

함수의 파라메터로 Collision 객체가 들어오며 col을 이용해 충돌한 GameObject에 대한 처리를 할 수 있다.



- Tag

충돌을 처리할 때 어떤 Object와 충돌을 했는 지도 중요하기 때문에 이에 대한 처리도 해주어야 한다. 이때 가장 많이 사용하는 것이 Tag 속성이다.

Tag 속성은 위와 같이 Inspector창에서 해당 GameObject의 Tag를 지정해 줄 수 있으며 Add Tag에서 새로운 Tag를 만들 수도 있다.


1
2
3
4
5
6
void OnTriggerEnter(Collider col) {
    if (col.tag == "Enemy")
    {
        // event.
    }
}



그럼 Enemy 라는 태그를 가진 GameObject랑만 충돌처리를 하고 싶다면 위와같이 if문으로 처리할 수 있다.
또한 다중 if문으로 여러 GameObject들에 다른 이벤트를 처리 할 수도 있다. 


[Unity3D] 다른 오브젝트의 함수를 호출하는 방법들

Unity

Unity에서 다른 GameObject의 함수를 호출하기 위한 방법은 여러가지가 있지만 그중 대표적인 방법 3가지만 소개하겠다.

 

 

 

우선 호출할 함수는 public으로 선언되어 있어야 한다.

Player라는 GameObject에 PlayerScript라는 Component가 있고 Func라는 함수를 호출하고 싶다면 

 

1
GameObject.Find("Player").GetComponent<PlayerScript>().Func();
 

 

이 방법이 가장 기본적인 방법이다. 

Player라는 이름을 가진 GameObject를 찾아 PlayerScript라는 Component의 Func 함수를 호출하였다.

 

1
GameObject.FindWithTag("GM").GetComponent<GMScript>().Func();
 

 

GameManager와 같은 유일한 태그를 가지는(GM이라는 태그는 GameManager에서만 사용해야한다) GameObject를 찾을 때에는 FindWithTag를 사용하면 더욱 좋은 퍼포먼스를 낼 수 있다.

 

1
GameObject.FindWithTag("GM").SendMessage("Func");
 

 

마지막으로 SendMessage라는 함수를 문자열로 호출하는 방법이 있다. 

위와같이 호출할 함수를 GameObject에 메세지만 던져주면 알아서 해당 함수가 있는 Component를 찾아서 함수를 호출해준다.

이 방법으로 함수를 호출할때는 호출할 함수가 public으로 선언되어 있지 않아도 된다.

편리한 만큼 약간의 성능저하가 있지만 신경쓸 정도는 아니라고 한다.