털털한 개발자, 긔저기의 개발공간

게임을 개발할 때 Object Pooling은 정말 많이 사용하는 기법 중에 하나다.

 

매번 오브젝트를 생성하는 것이 아니라 미리 생성해놓은 오브젝트를 재사용 하는것이기 때문에

 

cpu의 사용량을 대폭 줄여준다. 

 

 

이번 포스팅에는 UniRx에서 지원해주는 Object Pooling을 사용해 볼것이다.

 

 

1. Object Pooling 클래스 만들기

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using UnityEngine;
using UniRx.Toolkit;
 
public class ObjectPooling<T> : ObjectPool<T> where T : Component
{
    private readonly T _prefab;
    private readonly Transform _parentTransform;
 
    /// <summary>생성자</summary>
    /// <param name="parent">오브젝트들의 부모</param>
    /// <param name="prefab">풀링할 오브젝트 프리팹</param>
    public ObjectPooling(Transform parent, T prefab)
    {
        _parentTransform = parent;
        _prefab = prefab;
    }
 
    /// <summary>오브젝트 Rent시 없을 때 생성하는 함수</summary>
    /// <returns>생성한 오브젝트 반환</returns>
    protected override T CreateInstance()
    {
        var obj = GameObject.Instantiate(_prefab);
        obj.transform.SetParent(_parentTransform);
        return obj;
    }
}
 
 
 

여러 오브젝트를 사용하기 위해 Generic 클래스를 하나 만들어준다

 

 

2. 생성 후 사용

사용 하기

Object Pool을 생성해 주고 사용하면 된다.

 

PreloadAsync는 코루틴을 사용해서 프레임마다 몇개씩 생성할 것인지 지정해줄수도 있다.

 

그냥 가져다 사용하면 되니 얼마나 간편한가!

 

물론 더 많은 함수가 있지만 이정도의 함수로도 충분히 사용할 수 있다.

 

다음 포스팅에는 오브젝트 풀의 내부를 한번 살펴보겠다.

 

 

게임을 개발하다 보면 float을 사용할때가 정말로 많다.

 

하지만 float의 계산이 오차가 있기 때문에 항상 조심해서 사용해야 한다.

 

4byte 변수안에 소숫점까지 다 표현해야하고 일반적인 정수형 변수의 계산이랑은

 

다르기 때문에 꽤 많은 상황에서 오차가 생기곤 한다

 

(부동소수점은 IEEE 754 표준을 사용한다)

https://ko.wikipedia.org/wiki/IEEE_754

 

IEEE 754 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. IEEE 754는 전기 전자 기술자 협회(IEEE)에서 개발한 컴퓨터에서 부동소수점을 표현하는 가장 널리 쓰이는 표준이다. ±0 등의 수와 무한, NaN 등의 기호를 표시하는 법과 이러한 수에 대한 연산을 정의하고 있다. 가장 최신 버전인 IEEE 754-2008은 IEEE 754-1985와 IEEE 754-1997을 대부분 포함한다. IEEE 754에는 32 비트 단정도(single-precision), 64 비트 배정

ko.wikipedia.org

예를 들어 적에게 총알을 맞아서 hp가 깎이는 경우라고 생각했을 때

 

적의 체력은 10, 총알의 데미지는 2라고 생각해보자

 

그렇다면 10-2 = 8의 체력이 남아야 되는데 오차때문에 7.99999 등의 숫자가 나오기도 한다.

 

이게 반복이 되면 밑의 사진과 같은 숫자가 출력되는 것이다....

 

float 오차

2.38...E-07이면 0.0000xxx 등의 아주 작은 값이다.

 

그러나 이 값도 어떻게 보면 0보다 큰 값이기 때문에 

 

조건

이런 조건에서 걸리지 않게 된다... 즉 5발을 맞아야 죽는 적이 6발을 맞아야 죽는 경우가 생긴다는 말씀!

 

 

 

이를 해결하는 방법은 여러가지가 있지만 나는 반올림을 이용해 해결했다.

 

 

반올림 해결법

 

float 값에 사용하는 자리수 * 10을 곱해서 반올림을 한다. 나는 0.x 번째까지 사용하므로 10을 곱했다.

 

그런다음 반올림을 하고 다시 사용하는 자리수 / 10을 해주면 완료!

 

반올림을 하기 때문에 작은 값도 남지않아 제대로 비교를 할 수 있다!

Unity로 개발을 하게 되면 많은 사람들이 안드로이드, 아이폰 등등

 

모바일 플랫폼의 출시를 목표로 두고 게임을 만들 것이다. 

 

그렇게 되면 많은 기기에 맞춰서 개발을 해야 하는데 생각보다 꽤 잡기힘든 문제가 발생하기도 한다...

 

특히 어떤 기기에서는 잘 돌아가고 어떤 기기에선 잘 돌아가지 않는 상황이 발생하면 머리 터지기 직전...

 

 

이번 문제는 몇몇 기기에서 잘 출력되던 Image, SpriteRenderer 가 특정 기기에서 출력이 되지 않는 문제다.

 

씬이 아무것도 출력이 되지 않고 검은색으로 나온다.... (Ui Button은 잘 나오는 것 같다.)

 

 

나의 경우 갤럭시 노트 Pro 12.2에서 문제가 발생했는데, 디버깅을 해봐도 잡을 수 없는 문제였다..

 

생각보다 문제는 간단했는데, 카메라의 Allow HDR이 켜져서 발생한 문제였다.

 

카메라 컴포넌트

카메라를 보게되면 기본적으로 Allow HDR이 켜져있다. 그렇기에 별 문제가 없을것이라 생각했는데

 

어떤 기기는 HDR를 지원하지 않는지(?) 아니면 Unity 버그인지 Allow HDR을 켜기만 해도 랜더링이 되지 않는다.

 

해결방법은 아주 간단한데 그냥 Allow HDR을 끄면 된다.

 

유니티 이슈트래커를 안찾아봤으면 해결하기 힘든 버그였다...

 

https://issuetracker.unity3d.com/issues/android-black-screen-is-rendered-when-hdr-is-enabled-on-certain-device-using-mali-t720-gpu

 

Unity IssueTracker - [Android] Black screen is rendered when HDR is enabled on certain device using Mali-T720 GPU

How to reproduce: 1. Open the attached "ReproHDR" project and switch to Android 2. Make sure that "Allow HDR" is enabled on Main Cam...

issuetracker.unity3d.com

정말 찾기 힘든 버그라면 유니티 문제일수도 있으니 이슈트래커를 한번씩 꼭 찾아보는 습관을 가지자!

 

 

모바일 플랫폼으로 개발을 하다보면 최적화에 신경쓰게 되는 경우가 많다.

 

여러 최적화 방법중에 중요한 한가지 방법이 Draw Call을 줄이는 것인데

 

가장 기본적인 최적화라고 말하자면 Batching 이라고 할 수 있을 것 같다.

 

Prifiler에 랜더링 부분, Draw Call과 Batches 를 볼수 있다.

 

Batching 이란 간단하게 설명해서 비슷한 오브젝트 끼리 한번에 드로우 되는것이라고 보면 된다.

 

즉 같은 오브젝트 10개가 있으면 보통 10번의 Draw Call이 불려지는데

 

이를 한번에 묶어 랜더링 함으로써 1번의 Draw Call로 10개의 오브젝트를 불리는 것이다

 

배칭 기법과 배칭 설정 등은 링크로...

 

https://docs.unity3d.com/kr/2018.1/Manual/DrawCallBatching.html

 

 

 

본론으로 넘어가서 Batching 작업 중 같은 오브젝트, Material을 사용하고 있는데 Batch가 묶이지 않는 경우가 있다.

 

Profiler - Rendering - Open Frame Debugger

 

Batching이 되었을 경우 Dynamic Batch로 묶여서 랜더링이 되야하는데 묶이지 않는경우...

 

Batching이 안된 오브젝트를 선택하면?

 

이렇게 Objects have different materials 인 상태라면 Batching이 안된 경우라고 볼수 있다.

 

내 경우에는 Renderer 컴포넌트의 Material에 직접 접근함으로써 발생하는 문제 였다.

 

요런 코드....

 

Material에 접근해서 값을 바꿔주면 오브젝트가 사용하고 있던 Material의 instance를 만들어 넣어준다.

 

이렇게 말이쥬

 

그렇기에 다른 Material을 사용하는 상황이 되는것이고 Batching 이 되지 않는 것!

 

Material을 직접 접근하지 말고 다른 방법을 사용해보자.

몇몇 안드로이드 기기에서 TextMeshPro의 텍스트가 제대로 출력되지 않는 경우가 발생한다.

 

처음에 메모리 문제인줄 알고 약간의 최적화까지 해봤지만 역시나 같은 반응

 

문제는 TextMeshProUGUI와 TextMeshPro에 Material을 혼합하여 사용하기 때문에 발생하는 것이였다.

 

<Material Preset>

 

이게 오류가 뜨거나 로그를 찍어봐도 포지션, 컬러 등등 잘 나오기 때문에 정말 찾기 힘든 버그였다..

 

해결법은 UGUI용 Material과 일반 MeshRenderer용 Material를 따로 구분해주면 된다.

 

 

TMP 오브젝트의 Inspector 밑의 Material 부분에 왼쪽 클릭

 

 

요렇게 하나 더 만들어주자

 

 

 

 

https://forum.unity.com/threads/null-reference-exception-with-empty-string.522184/

 

TextMesh Pro - Null Reference Exception with Empty String

TextMesh Pro returns a null reference exception error if I try to reference text that's empty. I get the error even if I try to get the text.length....

forum.unity.com