반응형

루 1.5.9버전 업데이트 및 최적화 작업, IL2CPP빌드


이번에 Lu 를 1.5.9버전으로 업데이트하면서 최적화 중심으로 작업을 진행하였다.

최적화 작업을 이전에도 여러번 했는데도 불구하고 최적화 작업은 항상 할게 많다...


이번 업데이트는 외관상 큰 변화는 없지만 퍼포먼스는 조금더 개선됬다고 생각한다.


1) 게임플레이 개선, 수정 사항


Planet Monster AI수정: 기존에는 중앙에 고정시켰는데 어색해 보여서 움직이게끔 바꿨다.

초반에 보스가 스폰될때 Dissolve효과가 있다.

우측상단에 FPS 표시





2) Editor Log활용: Apk 용량 줄이기


Console창 구석에 있는 아이콘을 오른쪽 클린하면 Open Editor Log라는 창이 있다.

이 창을 열면 Text형식의 Log창이 뜬다.



그리고 프로젝트를 빌드 후 Editor Log창을 클릭하면 Log내용에서 Build Report을 확인할 수 있다. 

(꼭 빌드 후에 해야지 Build Report Log가 남는다)


여기서 자신의 프로젝트가 어느 부분에서 용량을 차지하는지 확인 할 수있다. 

대부분 프로젝트가 그렇듯이 용량을 가장 많이 자치하는 부분 중 하나는 텍스쳐일것이다.

내 프로젝트도 가장 용량을 많이 차지한 부분이 텍스처이다



사진을 보면 알 수 있듯이 Particle Effect에 들어가는 Texture그리고 보스몹에 들어가는 tga형식의 Texture가 지나치게 높은것을 확인 할 수 있다. 이걸 최적화하면 된다.

최적화하는 가장 쉬운 방법 중 하나는 Unity가 제공하는 기능중 하나인 Texture Compression 기능이다.



Texture를 Compress 하게 되면 용량이 많이 줄어든다.

참고로 Texture를 Compress하려면 Texture파일이 높이와 폭이 4^n꼴이어야한다 ex) 512x512, 1024x512 등등

그렇기 때문에 만약 Texture사이즈가 4^n꼴이 아니면 이것부터 수정하는 작업을 해야한다. 

(참고로 Texture크기를 수정하면 Texture를 사용하고 있는 GameObject도 같이 바뀌기 때문에 꼭 확인해야한다)

(또 지나치게 Compress를 많이하면 Texture가 Blur하게 보이기 때문에 적절한 수치를 찾아야한다)

(Font도 용량을 은근히 많이 먹는다. 종류가 다른 Font가 지나치게 많이 사용되면 APK 용량이 커질수 있다는걸 알 수 있다...)


아무튼 Texture의 크기를 수정하고 적절하게 Compress해주면 


용량이 확 줄어든다! 

내 프로젝트는 62MB -> 46MB으로 줄어들었다



3) IL2CPP빌드


IL2CPP이란 말그대로 IL(Intermediate Language, 중간어) 를 CPP(c++)로 바꿔주는 빌드이다.

더 자세한 내용은 다음 링크에서 보면 된다.

https://blogs.unity3d.com/kr/2015/09/22/kr-csharp-compile-il2cpp/


IL2CPP빌드를 왜 하냐? 여러가지 이유가 있지만 

유니티 공식 문서에 따르면 

 IL2CPP는 Unity 프로젝트의 성능, 보안 및 플랫폼 호환성을 개선하는 등의 용도로 사용됩니다. "

라고 한다...


APK를 크랙할때 크랙프로그램을 통해 프로젝트를 뜯을 수 있는데 

IL로 빌드된 APK같은 경우 보안에 최약하다고 한다. 

쉽게 뜯기고 코드도 쉽게 찾을 수 있다고 한다...

하지만 IL2CPP로 빌드하면 뜯어도 알아보기 힘든 형태로 있기때문에 크랙하기 더 복잡하다고 한다. 

유명한 게임아니면 시간투자해서 크랙하는것 자체가 시간낭비기 때문에

IL2CPP로 빌드하는것 자체가 나름 보안을 강화하는 역할을 한다.


내 프로젝트는 자체가 작음에도 불구하고

빌드시간이 IL2CPP로 10분정도 걸린것 같다. (Mono로 했을때 2분)

(참고로 빌드한 컴퓨터 사양이 낮다. 그래서 더 오래걸린 것도 있다 

컴퓨터 사양 : i3 4179, gtx960,  ram 8g)

규모가 정말 크다면 빌드하는데 몇시간 걸리지 않을까 싶다. 

추가) 처음 IL2CPP빌드했을때 10분정도 걸렸지만 그 이후에 다시 한번 빌드하니 3분정도 걸린것 같다


현재 이 프로젝트가 원래 무겁지 않은 탓인지 Mono이나 IL2CPP로 빌드 했을때 플레이어가 느끼는 성능차이는 없다고 생각이든다.

나름 현재 기준으로 오래된 기종인 갤럭시 S3에서도 큰 무리없이 돌아갈 정도로 프로젝트가 가볍기 때문이다.

그래서 IL2CPP가 내 프로젝트에 큰 의미가 있을까 싶었지만 이것보다 큰 프로젝트에서는 성능의 차이를 느낄 수 있을 것이다.

그나마 내 프로젝트에서는 체감되는 부분은 UI를 다룰때 살짝(?) 차이가 있다.

현재 Dotween 이라는 에셋을 사용하여 UI Tweening동작을 하고 있는데 게임이 처음 로딩된 후 초반에 부드럽게 Tweening이 이루어지지 않고 프레임드랍이 조금씩 발생했다. 하지만 이번에 IL2CPP로 빌드한 후에는 초반에도 부드럽게 Tweening동작이 이루어진다.





반응형
반응형

유니티) 보스의 공격 범위 표시


많은 RPG게임에서 보스전을 할때 공격 범위를 미리 표시한다.

프로젝트 루에서도 적이 공격 모션을 취할때 미리 공격 범위를 표시한다.

공격 범위를 표시하는데 여러가지 방법이 있다.

루에서는 두가지 방법을 사용하고 있다.


1. 공격범위를 나타내는 게임 오브젝트 생성 

말 그대로 범위를 나타내는 게임 프리팹을 Instantiate 하는 방식이다. 

(만약 공격범위를 여러개 표시할 경우 오브젝트 풀링을 사용하는게 현명하다)




2. 유니티 프로젝터 (Projector)

Projector는 빔 프로젝터처럼 Material을 쏴주는 컴포넌트이다.

Texture를 가진 Projector를 쏴주면 Texture가 부딪히는 오브젝트에 표시된다.



그냥 1번 방식으로 오브젝트를 생성하면 되지 뭐하러 프로젝터를 사용하냐고 생각할 수도 있지만

지형이 평평하지 않거나 지형의 끝자락에서는 프로젝터를 사용하는게 더 깔끔하다.



루에서는 위에서 아래로 프로젝터가 쏘는 형식이다

공격의 종류에 따라 프로젝터가 parameter값들의 변화를 줘 표시 범위를 다르게 하고 있다

아래 스크린샷처럼 프로젝터를 사용했을때 지형끝에 있는 원이 자연스럽게 짤려서 보인다



결론

- 1번 2번 방식을 상황에 맞게 활용할 필요가 있다.

- 공격 범위를 많이 표시해야되는 경우 오브젝트풀링을 사용하는게 현명하다. 


다음은 루에서 한 보스의 공격 패턴 중 하나이다. 여기서 ObjectPoolingManager의 메서드를 콜해 프로젝터를 SetActive(true)하는 방식을 사용하고 있다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    IEnumerator StateCastCrossAttack()
    {
        float randomY = Random.Range(0, 360f);
        crossAttackRotation = new Vector3(90f, randomY, 0f);
        Quaternion quaternion = Quaternion.Euler(crossAttackRotation);
 
        int fieldOfView = 100;
        var projector = ObjectPoolingManager.instance.SpawnProjectorFromPool("CrossProjector", transform.position, fieldOfView);
        projector.transform.rotation = quaternion;
        projector.GetComponent<SetActiveFalseOverTime>().SetActiveFalse(2.5f);
 
        float coolTime = 2f;
        yield return new WaitForSeconds(coolTime);
        animator.SetTrigger("castAttack");
 
        StartCoroutine(WaitForAttackToEnd());
        yield return null;
    }
cs


-하지만 여기서 조심해야할 부분은 2번 방식의 프로젝터를 사용했을떄 batching수, 즉 드로우콜(Draw Call)이 프로젝터당 1개씩 증가한다는것이다. 그래서 여러개의 프로젝터를 생성할때 순간적인 프레임드랍이 발생할 수 있다.





반응형
반응형

유니티) FPS와 관련된 Trouble



오늘 갑자기 Lu 의 게임 최적화때문에 FPS(Frame Per Second)가 어떻게 되는지 확인했다

그전에는 단순히 수치보고 너무 낮지만 않으면 잘돌아간다고 생각하고넘어갔던 문제였는데

앞으로 개발할때 주의해야겠다는 부분을 발견했다


먼저 Lu 프로젝트는 Unity 5.6 버전에서 개발되었다

또한 맥북프로로 개발된 프로젝트이다 


문제를 살펴보자면 Editor창에서 Maximum on Play상태에서의 FPS가 30언저리 밖에 나오지 않는다. 

하지만 Maximum on Play를 활성화시키면 FPS가 100까지 오르고 Batching이 갑자기 많이 발생하는 상황이 나타나면 줄어든다... 어쨋든 FPS가 100을 넘고 그냥 단순히 생각해보면 아 프레임이 잘나오네? 이렇게 생각할 수 있는데 FPS에 따라 플레이어의 움직임에 영향을 미치는것 같은 느낌이 들었다...


1) 다른 인스팩터창과 같이 Game Play를 할때 (Maximum On Play 비활성화) 

FPS 30 언저리




1) Maximum On Play 활성화 할때 

FPS 60 유지 (targetframe = 60으로 설정)



문제점은 FPS에 따라 Move되는 거리가 다르게 보이는 것이었는데 FPS가 높으면 더 천천히 그리고 반대로 FPS가 더 빨리 이동한는 점이다... 즉, FPS가 다를때마다 플레이어의 이동속도가 다르게 나타나고 있었다!...


처음에는 스크립상의 문제라고 생각이 됬다.

기본적인 움직임 스크립트는 다음과 같이 구성되어 있는데

1
2
3
4
5
6
7
8
9
10
11
12
13
    void Move(float hor, float ver)
    {
        if (!acting) //when basic movement
            playerSpeed = SPEED_DEFAULT + (float)SaveManger.instance.SpeedLV * 0.08f;
        else // when dash , skill attacks, etc
            playerSpeed = (SPEED_DEFAULT - 3f) + (float)SaveManger.instance.SpeedLV * 0.08f;
 
        Vector3 targetDirection = new Vector3(hor, 0f, ver);
        targetDirection = CameraManager.instance.mainCam.transform.TransformDirection(targetDirection);
        targetDirection.y = 0.0f;
        movement = targetDirection.normalized * playerSpeed * Time.deltaTime;
        playerRigidbody.MovePosition(transform.position + movement);
    }
cs

Rigidbody의 MovePosition 함수를 이용한 움직임 스크립트이다.


하지만 스크립트상으로는 큰 문제점이 보이지 않는다. 왜냐하면 direction을 normaize(정규화)한 이후에 Time.delaTime값을 곱하는 것 자체가 프레임의 높고 낮음과 상관없이 시간당 일정한 거리를 움직이게 하는 역할을 하기때문이다. 

(처음에는 MovePostion함수 자체의 문제인가 의심을 했지만 그것도 당연히 아니었다)


혹시 안드로이드에 앱에서는 어떻게 FPS가 나오는지 궁굼해서 FPS실험을 한 결과 60FPS에 고정되어있다

(Document에서는 Mobile의 경우 주로 30FPS에 맞춘다고 써 있는데 이게 기종에 따라 지원하는 FPS가 다르)

https://docs.unity3d.com/ScriptReference/Application-targetFrameRate.html



그래서 결국 이 문제를 해결하고자

1
Application.targetFrameRate = 60
cs

프레임을 60으로 고정시킨 후에 변화가 있는지 확인해보았다. 하지만 역시 Maximum on Play에서만 60FPS가 고정되었고 Maximum on Play를 끈 상태에선 계속 말도 안되게 낮게 나온다.


왜 이런 현상이 나타날까 열심히 구글링과 테스트한 결과 아주 허무한 결론이다.


한줄로 정리하자면 그냥 

"맥북에서 유니티 5.6 의 버그인것 같다"


맥북프로에 말고 윈도우 데스크탑에서 2017.3 버전으로 테스트한 결과 Maximun on Play 여부와 상관없이 프레임 드랍현상이 일어나지 않는다.

또한 Profiler의 Record기능이 editor상에서 프레임드랍에 영향을 준다. 그래서 Record기능을 끄면 프레임이 오른다... 30까지만...

그래서 이 프로젝트의 게임플레이를 확인할때는 Maximun on Play 를 키고 확인해야하는 번거로움이 있을것 같다... 

그리고 앞으로 모바일 프로젝트할때는 휴대폰이 30FPS, 60FPS인점을 감안해서 targetFrameRate을 지정한 후에 테스트하는게 좋을것 같다.




추가) 2019. 01. 18

최근에 윈도우 컴퓨터에 5.6.6버전을 받아서 Lu 프로젝트를 테스트한 결과 프레임 드랍현상이 나타나지 않았다.

유니티 버전이랑 상관없이 맥북에서 발생하는 버그로 보인다.


추가) 2019. 06. 05

Application.targetFrameRated을 지정시켜도 이는 에디터에 영향이 없다.

결론: 단순한 유니티 에디터의 버그이다.

반응형
반응형
유니티 포트폴리오: 루 게임 플레이 영상
(2019. 01. 04)



최근에 Lu 프로젝트를 업데이트 하면서 플레이 영상을 다시 찍었다

Raid 프로젝트를 개발하면서 Lu 에도 적용해야겠다 싶은 기능들을 추가적으로 넣었다


앱 플레이어를 화면 녹화하는 형식으로 영상을 찍었다

처음에 영상녹화와 게임 플레이를 동시에 하면 렉이 많이 걸려서 당황했다

방법찾으려고 수 많은 삽질을 한 결과

그냥 컴퓨터 사양이 좋지 않아서 생긴 문제였다....!

그래서 데스크탑보다 사양이 좋은 맥북프로로 녹화하니까 

비교적 부드럽게 녹화가 된듯 싶다...

얼릉 데스크탑을 다시 맞춰야겠다




반응형

+ Recent posts